Imported Upstream version 7.2.1
1
.foreman
Normal file
|
@ -0,0 +1 @@
|
||||||
|
port: 3000
|
40
.gitignore
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
.bundle
|
||||||
|
.rbx/
|
||||||
|
db/*.sqlite3
|
||||||
|
db/*.sqlite3-journal
|
||||||
|
log/*.log*
|
||||||
|
tmp/
|
||||||
|
.sass-cache/
|
||||||
|
coverage/*
|
||||||
|
backups/*
|
||||||
|
*.swp
|
||||||
|
public/uploads/
|
||||||
|
.ruby-version
|
||||||
|
.ruby-gemset
|
||||||
|
.rvmrc
|
||||||
|
.rbenv-version
|
||||||
|
.directory
|
||||||
|
nohup.out
|
||||||
|
Vagrantfile
|
||||||
|
.vagrant
|
||||||
|
config/gitlab.yml
|
||||||
|
config/database.yml
|
||||||
|
config/initializers/omniauth.rb
|
||||||
|
config/initializers/rack_attack.rb
|
||||||
|
config/initializers/smtp_settings.rb
|
||||||
|
config/unicorn.rb
|
||||||
|
config/resque.yml
|
||||||
|
config/aws.yml
|
||||||
|
db/data.yml
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
.chef
|
||||||
|
vendor/bundle/*
|
||||||
|
rails_best_practices_output.html
|
||||||
|
doc/code/*
|
||||||
|
.secret
|
||||||
|
*.log
|
||||||
|
public/uploads.*
|
||||||
|
public/assets/
|
||||||
|
.envrc
|
||||||
|
dump.rdb
|
4
.hound.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Prefer single quotes
|
||||||
|
StringLiterals:
|
||||||
|
EnforcedStyle: single_quotes
|
||||||
|
Enabled: true
|
26
.pkgr.yml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
user: git
|
||||||
|
group: git
|
||||||
|
before_precompile: ./bin/pkgr_before_precompile.sh
|
||||||
|
targets:
|
||||||
|
debian-7: &wheezy
|
||||||
|
build_dependencies:
|
||||||
|
- libicu-dev
|
||||||
|
dependencies:
|
||||||
|
- libicu48
|
||||||
|
- libpcre3
|
||||||
|
- git
|
||||||
|
ubuntu-12.04: *wheezy
|
||||||
|
ubuntu-14.04:
|
||||||
|
build_dependencies:
|
||||||
|
- libicu-dev
|
||||||
|
dependencies:
|
||||||
|
- libicu52
|
||||||
|
- libpcre3
|
||||||
|
- git
|
||||||
|
centos-6:
|
||||||
|
build_dependencies:
|
||||||
|
- libicu-devel
|
||||||
|
dependencies:
|
||||||
|
- libicu
|
||||||
|
- pcre
|
||||||
|
- git
|
1
.rspec
Normal file
|
@ -0,0 +1 @@
|
||||||
|
--color
|
4
.simplecov
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# .simplecov
|
||||||
|
SimpleCov.start 'rails' do
|
||||||
|
merge_timeout 3600
|
||||||
|
end
|
8
.teatro.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
stage:
|
||||||
|
before:
|
||||||
|
- cp config/gitlab.teatro.yml config/gitlab.yml
|
||||||
|
- mkdir /apps/gitlab-satellites
|
||||||
|
- mkdir /apps/repositories
|
||||||
|
|
||||||
|
database:
|
||||||
|
- RAILS_ENV=development force=yes bundle exec rake db:create gitlab:setup
|
36
.travis.yml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
language: ruby
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- TRAVIS=true
|
||||||
|
matrix:
|
||||||
|
- TASK=spinach_project DB=mysql
|
||||||
|
- TASK=spinach_other DB=mysql
|
||||||
|
- TASK=spec:api DB=mysql
|
||||||
|
- TASK=spec:feature DB=mysql
|
||||||
|
- TASK=spec:other DB=mysql
|
||||||
|
- TASK=jasmine:ci DB=mysql
|
||||||
|
- TASK=spinach_project DB=postgresql
|
||||||
|
- TASK=spinach_other DB=postgresql
|
||||||
|
- TASK=spec:api DB=postgresql
|
||||||
|
- TASK=spec:feature DB=postgresql
|
||||||
|
- TASK=spec:other DB=postgresql
|
||||||
|
- TASK=jasmine:ci DB=postgresql
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get install libicu-dev -y
|
||||||
|
install:
|
||||||
|
- "travis_retry bundle install --deployment --without production --retry 5"
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- 'master'
|
||||||
|
rvm:
|
||||||
|
- 2.0.0
|
||||||
|
services:
|
||||||
|
- redis-server
|
||||||
|
before_script:
|
||||||
|
- "cp config/database.yml.$DB config/database.yml"
|
||||||
|
- "cp config/gitlab.yml.example config/gitlab.yml"
|
||||||
|
- "bundle exec rake db:setup"
|
||||||
|
- "bundle exec rake db:seed_fu"
|
||||||
|
script: "bundle exec rake $TASK --trace"
|
||||||
|
notifications:
|
||||||
|
email: false
|
858
CHANGELOG
Normal file
|
@ -0,0 +1,858 @@
|
||||||
|
v 7.2.1
|
||||||
|
- Delete orphaned labels during label migration (James Brooks)
|
||||||
|
- Security: prevent XSS with stricter MIME types for raw repo files
|
||||||
|
|
||||||
|
v 7.2.0
|
||||||
|
- Explore page
|
||||||
|
- Add project stars (Ciro Santilli)
|
||||||
|
- Log Sidekiq arguments
|
||||||
|
- Better labels: colors, ability to rename and remove
|
||||||
|
- Improve the way merge request collects diffs
|
||||||
|
- Improve compare page for large diffs
|
||||||
|
- Expose the full commit message via API
|
||||||
|
- Fix 500 error on repository rename
|
||||||
|
- Fix bug when MR download patch return invalid diff
|
||||||
|
- Test gitlab-shell integration
|
||||||
|
- Repository import timeout increased from 2 to 4 minutes allowing larger repos to be imported
|
||||||
|
- API for labels (Robert Schilling)
|
||||||
|
- API: ability to set an import url when creating project for specific user
|
||||||
|
|
||||||
|
v 7.1.1
|
||||||
|
- Fix cpu usage issue in Firefox
|
||||||
|
- Fix redirect loop when changing password by new user
|
||||||
|
- Fix 500 error on new merge request page
|
||||||
|
|
||||||
|
v 7.1.0
|
||||||
|
- Remove observers
|
||||||
|
- Improve MR discussions
|
||||||
|
- Filter by description on Issues#index page
|
||||||
|
- Fix bug with namespace select when create new project page
|
||||||
|
- Show README link after description for non-master members
|
||||||
|
- Add @all mention for comments
|
||||||
|
- Dont show reply button if user is not signed in
|
||||||
|
- Expose more information for issues with webhook
|
||||||
|
- Add a mention of the merge request into the default merge request commit message
|
||||||
|
- Improve code highlight, introduce support for more languages like Go, Clojure, Erlang etc
|
||||||
|
- Fix concurrency issue in repository download
|
||||||
|
- Dont allow repository name start with ?
|
||||||
|
- Improve email threading (Pierre de La Morinerie)
|
||||||
|
- Cleaner help page
|
||||||
|
- Group milestones
|
||||||
|
- Improved email notifications
|
||||||
|
- Contributors API (sponsored by Mobbr)
|
||||||
|
- Fix LDAP TLS authentication (Boris HUISGEN)
|
||||||
|
- Show VERSION information on project sidebar
|
||||||
|
- Improve branch removal logic when accept MR
|
||||||
|
- Fix bug where comment form is spawned inside the Reply button
|
||||||
|
- Remove Dir.chdir from Satellite#lock for thread-safety
|
||||||
|
- Increased default git max_size value from 5MB to 20MB in gitlab.yml. Please update your configs!
|
||||||
|
- Show error message in case of timeout in satellite when create MR
|
||||||
|
- Show first 100 files for huge diff instead of hiding all
|
||||||
|
- Change default admin email from admin@local.host to admin@example.com
|
||||||
|
|
||||||
|
v 7.0.0
|
||||||
|
- The CPU no longer overheats when you hold down the spacebar
|
||||||
|
- Improve edit file UI
|
||||||
|
- Add ability to upload group avatar when create
|
||||||
|
- Protected branch cannot be removed
|
||||||
|
- Developers can remove normal branches with UI
|
||||||
|
- Remove branch via API (sponsored by O'Reilly Media)
|
||||||
|
- Move protected branches page to Project settings area
|
||||||
|
- Redirect to Files view when create new branch via UI
|
||||||
|
- Drag and drop upload of image in every markdown-area (Earle Randolph Bunao and Neil Francis Calabroso)
|
||||||
|
- Refactor the markdown relative links processing
|
||||||
|
- Make it easier to implement other CI services for GitLab
|
||||||
|
- Group masters can create projects in group
|
||||||
|
- Deprecate ruby 1.9.3 support
|
||||||
|
- Only masters can rewrite/remove git tags
|
||||||
|
- Add X-Frame-Options SAMEORIGIN to Nginx config so Sidekiq admin is visible
|
||||||
|
- UI improvements
|
||||||
|
- Case-insensetive search for issues
|
||||||
|
- Update to rails 4.1
|
||||||
|
- Improve performance of application for projects and groups with a lot of members
|
||||||
|
- Formally support Ruby 2.1
|
||||||
|
- Include Nginx gitlab-ssl config
|
||||||
|
- Add manual language detection for highlight.js
|
||||||
|
- Added example.com/:username routing
|
||||||
|
- Show notice if your profile is public
|
||||||
|
- UI improvements for mobile devices
|
||||||
|
- Improve diff rendering performance
|
||||||
|
- Drag-n-drop for issues and merge requests between states at milestone page
|
||||||
|
- Fix '0 commits' message for huge repositories on project home page
|
||||||
|
- Prevent 500 error page when visit commit page from large repo
|
||||||
|
- Add notice about huge push over http to unicorn config
|
||||||
|
- File action in satellites uses default 30 seconds timeout instead of old 10 seconds one
|
||||||
|
- Overall performance improvements
|
||||||
|
- Skip init script check on omnibus-gitlab
|
||||||
|
- Be more selective when killing stray Sidekiqs
|
||||||
|
- Check LDAP user filter during sign-in
|
||||||
|
- Remove wall feature (no data loss - you can take it from database)
|
||||||
|
- Dont expose user emails via API unless you are admin
|
||||||
|
- Detect issues closed by Merge Request description
|
||||||
|
- Better email subject lines from email on push service (Alex Elman)
|
||||||
|
- Enable identicon for gravatar be default
|
||||||
|
|
||||||
|
v 6.9.2
|
||||||
|
- Revert the commit that broke the LDAP user filter
|
||||||
|
|
||||||
|
v 6.9.1
|
||||||
|
- Fix scroll to highlighted line
|
||||||
|
- Fix the pagination on load for commits page
|
||||||
|
|
||||||
|
v 6.9.0
|
||||||
|
- Store Rails cache data in the Redis `cache:gitlab` namespace
|
||||||
|
- Adjust MySQL limits for existing installations
|
||||||
|
- Add db index on project_id+iid column. This prevents duplicate on iid (During migration duplicates will be removed)
|
||||||
|
- Markdown preview or diff during editing via web editor (Evgeniy Sokovikov)
|
||||||
|
- Give the Rails cache its own Redis namespace
|
||||||
|
- Add ability to set different ssh host, if different from http/https
|
||||||
|
- Fix syntax highlighting for code comments blocks
|
||||||
|
- Improve comments loading logic
|
||||||
|
- Stop refreshing comments when the tab is hidden
|
||||||
|
- Improve issue and merge request mobile UI (Drew Blessing)
|
||||||
|
- Document how to convert a backup to PostgreSQL
|
||||||
|
- Fix locale bug in backup manager
|
||||||
|
- Fix can not automerge when MR description is too long
|
||||||
|
- Fix wiki backup skip bug
|
||||||
|
- Two Step MR creation process
|
||||||
|
- Remove unwanted files from satellite working directory with git clean -fdx
|
||||||
|
- Accept merge request via API (sponsored by O'Reilly Media)
|
||||||
|
- Add more access checks during API calls
|
||||||
|
- Block SSH access for 'disabled' Active Directory users
|
||||||
|
- Labels for merge requests (Drew Blessing)
|
||||||
|
- Threaded emails by setting a Message-ID (Philip Blatter)
|
||||||
|
|
||||||
|
v 6.8.0
|
||||||
|
- Ability to at mention users that are participating in issue and merge req. discussion
|
||||||
|
- Enabled GZip Compression for assets in example Nginx, make sure that Nginx is compiled with --with-http_gzip_static_module flag (this is default in Ubuntu)
|
||||||
|
- Make user search case-insensitive (Christopher Arnold)
|
||||||
|
- Remove omniauth-ldap nickname bug workaround
|
||||||
|
- Drop all tables before restoring a Postgres backup
|
||||||
|
- Make the repository downloads path configurable
|
||||||
|
- Create branches via API (sponsored by O'Reilly Media)
|
||||||
|
- Changed permission of gitlab-satellites directory not to be world accessible
|
||||||
|
- Protected branch does not allow force push
|
||||||
|
- Fix popen bug in `rake gitlab:satellites:create`
|
||||||
|
- Disable connection reaping for MySQL
|
||||||
|
- Allow oauth signup without email for twitter and github
|
||||||
|
- Fix faulty namespace names that caused 500 on user creation
|
||||||
|
- Option to disable standard login
|
||||||
|
- Clean old created archives from repository downloads directory
|
||||||
|
- Fix download link for huge MR diffs
|
||||||
|
- Expose event and mergerequest timestamps in API
|
||||||
|
- Fix emails on push service when only one commit is pushed
|
||||||
|
|
||||||
|
v 6.7.3
|
||||||
|
- Fix the merge notification email not being sent (Pierre de La Morinerie)
|
||||||
|
- Drop all tables before restoring a Postgres backup
|
||||||
|
- Remove yanked modernizr gem
|
||||||
|
|
||||||
|
v 6.7.2
|
||||||
|
- Fix upgrader script
|
||||||
|
|
||||||
|
v 6.7.1
|
||||||
|
- Fix GitLab CI integration
|
||||||
|
|
||||||
|
v 6.7.0
|
||||||
|
- Increased the example Nginx client_max_body_size from 5MB to 20MB, consider updating it manually on existing installations
|
||||||
|
- Add support for Gemnasium as a Project Service (Olivier Gonzalez)
|
||||||
|
- Add edit file button to MergeRequest diff
|
||||||
|
- Public groups (Jason Hollingsworth)
|
||||||
|
- Cleaner headers in Notification Emails (Pierre de La Morinerie)
|
||||||
|
- Blob and tree gfm links to anchors work
|
||||||
|
- Piwik Integration (Sebastian Winkler)
|
||||||
|
- Show contribution guide link for new issue form (Jeroen van Baarsen)
|
||||||
|
- Fix CI status for merge requests from fork
|
||||||
|
- Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
|
||||||
|
- New page load indicator that includes a spinner that scrolls with the page
|
||||||
|
- Converted all the help sections into markdown
|
||||||
|
- LDAP user filters
|
||||||
|
- Streamline the content of notification emails (Pierre de La Morinerie)
|
||||||
|
- Fixes a bug with group member administration (Matt DeTullio)
|
||||||
|
- Sort tag names using VersionSorter (Robert Speicher)
|
||||||
|
- Add GFM autocompletion for MergeRequests (Robert Speicher)
|
||||||
|
- Add webhook when a new tag is pushed (Jeroen van Baarsen)
|
||||||
|
- Add button for toggling inline comments in diff view
|
||||||
|
- Add retry feature for repository import
|
||||||
|
- Reuse the GitLab LDAP connection within each request
|
||||||
|
- Changed markdown new line behaviour to conform to markdown standards
|
||||||
|
- Fix global search
|
||||||
|
- Faster authorized_keys rebuilding in `rake gitlab:shell:setup` (requires gitlab-shell 1.8.5)
|
||||||
|
- Create and Update MR calls now support the description parameter (Greg Messner)
|
||||||
|
- Markdown relative links in the wiki link to wiki pages, markdown relative links in repositories link to files in the repository
|
||||||
|
- Added Slack service integration (Federico Ravasio)
|
||||||
|
- Better API responses for access_levels (sponsored by O'Reilly Media)
|
||||||
|
- Requires at least 2 unicorn workers
|
||||||
|
- Requires gitlab-shell v1.9+
|
||||||
|
- Replaced gemoji(due to closed licencing problem) with Phantom Open Emoji library(combined SIL Open Font License, MIT License and the CC 3.0 License)
|
||||||
|
- Fix `/:username.keys` response content type (Dmitry Medvinsky)
|
||||||
|
|
||||||
|
v 6.6.5
|
||||||
|
- Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
|
||||||
|
- Hide mr close button for comment form if merge request was closed or inline comment
|
||||||
|
- Adds ability to reopen closed merge request
|
||||||
|
|
||||||
|
v 6.6.4
|
||||||
|
- Add missing html escape for highlighted code blocks in comments, issues
|
||||||
|
|
||||||
|
v 6.6.3
|
||||||
|
- Fix 500 error when edit yourself from admin area
|
||||||
|
- Hide private groups for public profiles
|
||||||
|
|
||||||
|
v 6.6.2
|
||||||
|
- Fix 500 error on branch/tag create or remove via UI
|
||||||
|
|
||||||
|
v 6.6.1
|
||||||
|
- Fix 500 error on files tab if submodules presents
|
||||||
|
|
||||||
|
v 6.6.0
|
||||||
|
- Retrieving user ssh keys publically(github style): http://__HOST__/__USERNAME__.keys
|
||||||
|
- Permissions: Developer now can manage issue tracker (modify any issue)
|
||||||
|
- Improve Code Compare page performance
|
||||||
|
- Group avatar
|
||||||
|
- Pygments.rb replaced with highlight.js
|
||||||
|
- Improve Merge request diff store logic
|
||||||
|
- Improve render performnace for MR show page
|
||||||
|
- Fixed Assembla hardcoded project name
|
||||||
|
- Jira integration documentation
|
||||||
|
- Refactored app/services
|
||||||
|
- Remove snippet expiration
|
||||||
|
- Mobile UI improvements (Drew Blessing)
|
||||||
|
- Fix block/remove UI for admin::users#show page
|
||||||
|
- Show users' group membership on users' activity page (Robert Djurasaj)
|
||||||
|
- User pages are visible without login if user is authorized to a public project
|
||||||
|
- Markdown rendered headers have id derived from their name and link to their id
|
||||||
|
- Improve application to work faster with large groups (100+ members)
|
||||||
|
- Multiple emails per user
|
||||||
|
- Show last commit for file when view file source
|
||||||
|
- Restyle Issue#show page and MR#show page
|
||||||
|
- Ability to filter by multiple labels for Issues page
|
||||||
|
- Rails version to 4.0.3
|
||||||
|
- Fixed attachment identifier displaying underneath note text (Jason Blanchard)
|
||||||
|
|
||||||
|
v 6.5.1
|
||||||
|
- Fix branch selectbox when create merge request from fork
|
||||||
|
|
||||||
|
v 6.5.0
|
||||||
|
- Dropdown menus on issue#show page for assignee and milestone (Jason Blanchard)
|
||||||
|
- Add color custimization and previewing to broadcast messages
|
||||||
|
- Fixed notes anchors
|
||||||
|
- Load new comments in issues dynamically
|
||||||
|
- Added sort options to Public page
|
||||||
|
- New filters (assigned/authored/all) for Dashboard#issues/merge_requests (sponsored by Say Media)
|
||||||
|
- Add project visibility icons to dashboard
|
||||||
|
- Enable secure cookies if https used
|
||||||
|
- Protect users/confirmation with rack_attack
|
||||||
|
- Default HTTP headers to protect against MIME-sniffing, force https if enabled
|
||||||
|
- Bootstrap 3 with responsive UI
|
||||||
|
- New repository download formats: tar.bz2, zip, tar (Jason Hollingsworth)
|
||||||
|
- Restyled accept widgets for MR
|
||||||
|
- SCSS refactored
|
||||||
|
- Use jquery timeago plugin
|
||||||
|
- Fix 500 error for rdoc files
|
||||||
|
- Ability to customize merge commit message (sponsored by Say Media)
|
||||||
|
- Search autocomplete via ajax
|
||||||
|
- Add website url to user profile
|
||||||
|
- Files API supports base64 encoded content (sponsored by O'Reilly Media)
|
||||||
|
- Added support for Go's repository retrieval (Bruno Albuquerque)
|
||||||
|
|
||||||
|
v6.4.3
|
||||||
|
- Don't use unicorn worker killer if PhusionPassenger is defined
|
||||||
|
|
||||||
|
v6.4.2
|
||||||
|
- Fixed wrong behaviour of script/upgrade.rb
|
||||||
|
|
||||||
|
v6.4.1
|
||||||
|
- Fixed bug with repository rename
|
||||||
|
- Fixed bug with project transfer
|
||||||
|
|
||||||
|
v 6.4.0
|
||||||
|
- Added sorting to project issues page (Jason Blanchard)
|
||||||
|
- Assembla integration (Carlos Paramio)
|
||||||
|
- Fixed another 500 error with submodules
|
||||||
|
- UI: More compact issues page
|
||||||
|
- Minimal password length increased to 8 symbols
|
||||||
|
- Side-by-side diff view (Steven Thonus)
|
||||||
|
- Internal projects (Jason Hollingsworth)
|
||||||
|
- Allow removal of avatar (Drew Blessing)
|
||||||
|
- Project web hooks now support issues and merge request events
|
||||||
|
- Visiting project page while not logged in will redirect to sign-in instead of 404 (Jason Hollingsworth)
|
||||||
|
- Expire event cache on avatar creation/removal (Drew Blessing)
|
||||||
|
- Archiving old projects (Steven Thonus)
|
||||||
|
- Rails 4
|
||||||
|
- Add time ago tooltips to show actual date/time
|
||||||
|
- UI: Fixed UI for admin system hooks
|
||||||
|
- Ruby script for easier GitLab upgrade
|
||||||
|
- Do not remove Merge requests if fork project was removed
|
||||||
|
- Improve sign-in/signup UX
|
||||||
|
- Add resend confirmation link to sign-in page
|
||||||
|
- Set noreply@HOSTNAME for reply_to field in all emails
|
||||||
|
- Show GitLab API version on Admin#dashboard
|
||||||
|
- API Cross-origin resource sharing
|
||||||
|
- Show READMe link at project home page
|
||||||
|
- Show repo size for projects in Admin area
|
||||||
|
|
||||||
|
v 6.3.0
|
||||||
|
- API for adding gitlab-ci service
|
||||||
|
- Init script now waits for pids to appear after (re)starting before reporting status (Rovanion Luckey)
|
||||||
|
- Restyle project home page
|
||||||
|
- Grammar fixes
|
||||||
|
- Show branches list (which branches contains commit) on commit page (Andrew Kumanyaev)
|
||||||
|
- Security improvements
|
||||||
|
- Added support for GitLab CI 4.0
|
||||||
|
- Fixed issue with 500 error when group did not exist
|
||||||
|
- Ability to leave project
|
||||||
|
- You can create file in repo using UI
|
||||||
|
- You can remove file from repo using UI
|
||||||
|
- API: dropped default_branch attribute from project during creation
|
||||||
|
- Project default_branch is not stored in db any more. It takes from repo now.
|
||||||
|
- Admin broadcast messages
|
||||||
|
- UI improvements
|
||||||
|
- Dont show last push widget if user removed this branch
|
||||||
|
- Fix 500 error for repos with newline in file name
|
||||||
|
- Extended html titles
|
||||||
|
- API: create/update/delete repo files
|
||||||
|
- Admin can transfer project to any namespace
|
||||||
|
- API: projects/all for admin users
|
||||||
|
- Fix recent branches order
|
||||||
|
|
||||||
|
v 6.2.4
|
||||||
|
- Security: Cast API private_token to string (CVE-2013-4580)
|
||||||
|
- Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
|
||||||
|
- Fix for Git SSH access for LDAP users
|
||||||
|
|
||||||
|
v 6.2.3
|
||||||
|
- Security: More protection against CVE-2013-4489
|
||||||
|
- Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
|
||||||
|
- Fix sidekiq rake tasks
|
||||||
|
|
||||||
|
v 6.2.2
|
||||||
|
- Security: Update gitlab_git (CVE-2013-4489)
|
||||||
|
|
||||||
|
v 6.2.1
|
||||||
|
- Security: Fix issue with generated passwords for new users
|
||||||
|
|
||||||
|
v 6.2.0
|
||||||
|
- Public project pages are now visible to everyone (files, issues, wik, etc.)
|
||||||
|
THIS MEANS YOUR ISSUES AND WIKI FOR PUBLIC PROJECTS ARE PUBLICLY VISIBLE AFTER THE UPGRADE
|
||||||
|
- Add group access to permissions page
|
||||||
|
- Require current password to change one
|
||||||
|
- Group owner or admin can remove other group owners
|
||||||
|
- Remove group transfer since we have multiple owners
|
||||||
|
- Respect authorization in Repository API
|
||||||
|
- Improve UI for Project#files page
|
||||||
|
- Add more security specs
|
||||||
|
- Added search for projects by name to api (Izaak Alpert)
|
||||||
|
- Make default user theme configurable (Izaak Alpert)
|
||||||
|
- Update logic for validates_merge_request for tree of MR (Andrew Kumanyaev)
|
||||||
|
- Rake tasks for web hooks management (Jonhnny Weslley)
|
||||||
|
- Extended User API to expose admin and can_create_group for user creation/updating (Boyan Tabakov)
|
||||||
|
- API: Remove group
|
||||||
|
- API: Remove project
|
||||||
|
- Avatar upload on profile page with a maximum of 100KB (Steven Thonus)
|
||||||
|
- Store the sessions in Redis instead of the cookie store
|
||||||
|
- Fixed relative links in markdown
|
||||||
|
- User must confirm their email if signup enabled
|
||||||
|
- User must confirm changed email
|
||||||
|
|
||||||
|
v 6.1.0
|
||||||
|
- Project specific IDs for issues, mr, milestones
|
||||||
|
Above items will get a new id and for example all bookmarked issue urls will change.
|
||||||
|
Old issue urls are redirected to the new one if the issue id is too high for an internal id.
|
||||||
|
- Description field added to Merge Request
|
||||||
|
- API: Sudo api calls (Izaak Alpert)
|
||||||
|
- API: Group membership api (Izaak Alpert)
|
||||||
|
- Improved commit diff
|
||||||
|
- Improved large commit handling (Boyan Tabakov)
|
||||||
|
- Rewrite: Init script now less prone to errors and keeps better track of the service (Rovanion Luckey)
|
||||||
|
- Link issues, merge requests, and commits when they reference each other with GFM (Ash Wilson)
|
||||||
|
- Close issues automatically when pushing commits with a special message
|
||||||
|
- Improve user removal from admin area
|
||||||
|
- Invalidate events cache when project was moved
|
||||||
|
- Remove deprecated classes and rake tasks
|
||||||
|
- Add event filter for group and project show pages
|
||||||
|
- Add links to create branch/tag from project home page
|
||||||
|
- Add public-project? checkbox to new-project view
|
||||||
|
- Improved compare page. Added link to proceed into Merge Request
|
||||||
|
- Send an email to a user when they are added to group
|
||||||
|
- New landing page when you have 0 projects
|
||||||
|
|
||||||
|
v 6.0.0
|
||||||
|
- Feature: Replace teams with group membership
|
||||||
|
We introduce group membership in 6.0 as a replacement for teams.
|
||||||
|
The old combination of groups and teams was confusing for a lot of people.
|
||||||
|
And when the members of a team where changed this wasn't reflected in the project permissions.
|
||||||
|
In GitLab 6.0 you will be able to add members to a group with a permission level for each member.
|
||||||
|
These group members will have access to the projects in that group.
|
||||||
|
Any changes to group members will immediately be reflected in the project permissions.
|
||||||
|
You can even have multiple owners for a group, greatly simplifying administration.
|
||||||
|
- Feature: Ability to have multiple owners for group
|
||||||
|
- Feature: Merge Requests between fork and project (Izaak Alpert)
|
||||||
|
- Feature: Generate fingerprint for ssh keys
|
||||||
|
- Feature: Ability to create and remove branches with UI
|
||||||
|
- Feature: Ability to create and remove git tags with UI
|
||||||
|
- Feature: Groups page in profile. You can leave group there
|
||||||
|
- API: Allow login with LDAP credentials
|
||||||
|
- Redesign: project settings navigation
|
||||||
|
- Redesign: snippets area
|
||||||
|
- Redesign: ssh keys page
|
||||||
|
- Redesign: buttons, blocks and other ui elements
|
||||||
|
- Add comment title to rss feed
|
||||||
|
- You can use arrows to navigate at tree view
|
||||||
|
- Add project filter on dashboard
|
||||||
|
- Cache project graph
|
||||||
|
- Drop support of root namespaces
|
||||||
|
- Default theme is classic now
|
||||||
|
- Cache result of methods like authorize_projects, project.team.members etc
|
||||||
|
- Remove $.ready events
|
||||||
|
- Fix onclick events being double binded
|
||||||
|
- Add notification level to group membership
|
||||||
|
- Move all project controllers/views under Projects:: module
|
||||||
|
- Move all profile controllers/views under Profiles:: module
|
||||||
|
- Apply user project limit only for personal projects
|
||||||
|
- Unicorn is default web server again
|
||||||
|
- Store satellites lock files inside satellites dir
|
||||||
|
- Disabled threadsafety mode in rails
|
||||||
|
- Fixed bug with loosing MR comments
|
||||||
|
- Improved MR comments logic
|
||||||
|
- Render readme file for projects in public area
|
||||||
|
|
||||||
|
v 5.4.2
|
||||||
|
- Security: Cast API private_token to string (CVE-2013-4580)
|
||||||
|
- Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
|
||||||
|
|
||||||
|
v 5.4.1
|
||||||
|
- Security: Fixes for CVE-2013-4489
|
||||||
|
- Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
|
||||||
|
|
||||||
|
v 5.4.0
|
||||||
|
- Ability to edit own comments
|
||||||
|
- Documentation improvements
|
||||||
|
- Improve dashboard projects page
|
||||||
|
- Fixed nav for empty repos
|
||||||
|
- GitLab Markdown help page
|
||||||
|
- Misspelling fixes
|
||||||
|
- Added support of unicorn and fog gems
|
||||||
|
- Added client list to API doc
|
||||||
|
- Fix PostgreSQL database restoration problem
|
||||||
|
- Increase snippet content column size
|
||||||
|
- allow project import via git:// url
|
||||||
|
- Show participants on issues, including mentions
|
||||||
|
- Notify mentioned users with email
|
||||||
|
|
||||||
|
v 5.3.0
|
||||||
|
- Refactored services
|
||||||
|
- Campfire service added
|
||||||
|
- HipChat service added
|
||||||
|
- Fixed bug with LDAP + git over http
|
||||||
|
- Fixed bug with google analytics code being ignored
|
||||||
|
- Improve sign-in page if ldap enabled
|
||||||
|
- Respect newlines in wall messages
|
||||||
|
- Generate the Rails secret token on first run
|
||||||
|
- Rename repo feature
|
||||||
|
- Init.d: remove gitlab.socket on service start
|
||||||
|
- Api: added teams api
|
||||||
|
- Api: Prevent blob content being escaped
|
||||||
|
- Api: Smart deploy key add behaviour
|
||||||
|
- Api: projects/owned.json return user owned project
|
||||||
|
- Fix bug with team assignation on project from #4109
|
||||||
|
- Advanced snippets: public/private, project/personal (Andrew Kulakov)
|
||||||
|
- Repository Graphs (Karlo Nicholas T. Soriano)
|
||||||
|
- Fix dashboard lost if comment on commit
|
||||||
|
- Update gitlab-grack. Fixes issue with --depth option
|
||||||
|
- Fix project events duplicate on project page
|
||||||
|
- Fix postgres error when displaying network graph.
|
||||||
|
- Fix dashboard event filter when navigate via turbolinks
|
||||||
|
- init.d: Ensure socket is removed before starting service
|
||||||
|
- Admin area: Style teams:index, group:show pages
|
||||||
|
- Own page for failed forking
|
||||||
|
- Scrum view for milestone
|
||||||
|
|
||||||
|
v 5.2.0
|
||||||
|
- Turbolinks
|
||||||
|
- Git over http with ldap credentials
|
||||||
|
- Diff with better colors and some spacing on the corners
|
||||||
|
- Default values for project features
|
||||||
|
- Fixed huge_commit view
|
||||||
|
- Restyle project clone panel
|
||||||
|
- Move Gitlab::Git code to gitlab_git gem
|
||||||
|
- Move update docs in repo
|
||||||
|
- Requires gitlab-shell v1.4.0
|
||||||
|
- Fixed submodules listing under file tab
|
||||||
|
- Fork feature (Angus MacArthur)
|
||||||
|
- git version check in gitlab:check
|
||||||
|
- Shared deploy keys feature
|
||||||
|
- Ability to generate default labels set for issues
|
||||||
|
- Improve gfm autocomplete (Harold Luo)
|
||||||
|
- Added support for Google Analytics
|
||||||
|
- Code search feature (Javier Castro)
|
||||||
|
|
||||||
|
v 5.1.0
|
||||||
|
- You can login with email or username now
|
||||||
|
- Corrected project transfer rollback when repository cannot be moved
|
||||||
|
- Move both repo and wiki when project transfer requested
|
||||||
|
- Admin area: project editing was removed from admin namespace
|
||||||
|
- Access: admin user has now access to any project.
|
||||||
|
- Notification settings
|
||||||
|
- Gitlab::Git set of objects to abstract from grit library
|
||||||
|
- Replace Unicorn web server with Puma
|
||||||
|
- Backup/Restore refactored. Backup dump project wiki too now
|
||||||
|
- Restyled Issues list. Show milestone version in issue row
|
||||||
|
- Restyled Merge Request list
|
||||||
|
- Backup now dump/restore uploads
|
||||||
|
- Improved performance of dashboard (Andrew Kumanyaev)
|
||||||
|
- File history now tracks renames (Akzhan Abdulin)
|
||||||
|
- Drop wiki migration tools
|
||||||
|
- Drop sqlite migration tools
|
||||||
|
- project tagging
|
||||||
|
- Paginate users in API
|
||||||
|
- Restyled network graph (Hiroyuki Sato)
|
||||||
|
|
||||||
|
v 5.0.1
|
||||||
|
- Fixed issue with gitlab-grit being overridden by grit
|
||||||
|
|
||||||
|
v 5.0.0
|
||||||
|
- Replaced gitolite with gitlab-shell
|
||||||
|
- Removed gitolite-related libraries
|
||||||
|
- State machine added
|
||||||
|
- Setup gitlab as git user
|
||||||
|
- Internal API
|
||||||
|
- Show team tab for empty projects
|
||||||
|
- Import repository feature
|
||||||
|
- Updated rails
|
||||||
|
- Use lambda for scopes
|
||||||
|
- Redesign admin area -> users
|
||||||
|
- Redesign admin area -> user
|
||||||
|
- Secure link to file attachments
|
||||||
|
- Add validations for Group and Team names
|
||||||
|
- Restyle team page for project
|
||||||
|
- Update capybara, rspec-rails, poltergeist to recent versions
|
||||||
|
- Wiki on git using Gollum
|
||||||
|
- Added Solarized Dark theme for code review
|
||||||
|
- Don't show user emails in autocomplete lists, profile pages
|
||||||
|
- Added settings tab for group, team, project
|
||||||
|
- Replace user popup with icons in header
|
||||||
|
- Handle project moving with gitlab-shell
|
||||||
|
- Added select2-rails for selectboxes with ajax data load
|
||||||
|
- Fixed search field on projects page
|
||||||
|
- Added teams to search autocomplete
|
||||||
|
- Move groups and teams on dashboard sidebar to sub-tabs
|
||||||
|
- API: improved return codes and docs. (Felix Gilcher, Sebastian Ziebell)
|
||||||
|
- Redesign wall to be more like chat
|
||||||
|
- Snippets, Wall features are disabled by default for new projects
|
||||||
|
|
||||||
|
v 4.2.0
|
||||||
|
- Teams
|
||||||
|
- User show page. Via /u/username
|
||||||
|
- Show help contents on pages for better navigation
|
||||||
|
- Async gitolite calls
|
||||||
|
- added satellites logs
|
||||||
|
- can_create_group, can_create_team booleans for User
|
||||||
|
- Process web hooks async
|
||||||
|
- GFM: Fix images escaped inside links
|
||||||
|
- Network graph improved
|
||||||
|
- Switchable branches for network graph
|
||||||
|
- API: Groups
|
||||||
|
- Fixed project download
|
||||||
|
|
||||||
|
v 4.1.0
|
||||||
|
- Optional Sign-Up
|
||||||
|
- Discussions
|
||||||
|
- Satellites outside of tmp
|
||||||
|
- Line numbers for blame
|
||||||
|
- Project public mode
|
||||||
|
- Public area with unauthorized access
|
||||||
|
- Load dashboard events with ajax
|
||||||
|
- remember dashboard filter in cookies
|
||||||
|
- replace resque with sidekiq
|
||||||
|
- fix routing issues
|
||||||
|
- cleanup rake tasks
|
||||||
|
- fix backup/restore
|
||||||
|
- scss cleanup
|
||||||
|
- show preview for note images
|
||||||
|
- improved network-graph
|
||||||
|
- get rid of app/roles/
|
||||||
|
- added new classes Team, Repository
|
||||||
|
- Reduce amount of gitolite calls
|
||||||
|
- Ability to add user in all group projects
|
||||||
|
- remove deprecated configs
|
||||||
|
- replaced Korolev font with open font
|
||||||
|
- restyled admin/dashboard page
|
||||||
|
- restyled admin/projects page
|
||||||
|
|
||||||
|
v 4.0.0
|
||||||
|
- Remove project code and path from API. Use id instead
|
||||||
|
- Return valid cloneable url to repo for web hook
|
||||||
|
- Fixed backup issue
|
||||||
|
- Reorganized settings
|
||||||
|
- Fixed commits compare
|
||||||
|
- Refactored scss
|
||||||
|
- Improve status checks
|
||||||
|
- Validates presence of User#name
|
||||||
|
- Fixed postgres support
|
||||||
|
- Removed sqlite support
|
||||||
|
- Modified post-receive hook
|
||||||
|
- Milestones can be closed now
|
||||||
|
- Show comment events on dashboard
|
||||||
|
- Quick add team members via group#people page
|
||||||
|
- [API] expose created date for hooks and SSH keys
|
||||||
|
- [API] list, create issue notes
|
||||||
|
- [API] list, create snippet notes
|
||||||
|
- [API] list, create wall notes
|
||||||
|
- Remove project code - use path instead
|
||||||
|
- added username field to user
|
||||||
|
- rake task to fill usernames based on emails create namespaces for users
|
||||||
|
- STI Group < Namespace
|
||||||
|
- Project has namespace_id
|
||||||
|
- Projects with namespaces also namespaced in gitolite and stored in subdir
|
||||||
|
- Moving project to group will move it under group namespace
|
||||||
|
- Ability to move project from namespaces to another
|
||||||
|
- Fixes commit patches getting escaped (see #2036)
|
||||||
|
- Support diff and patch generation for commits and merge request
|
||||||
|
- MergeReqest doesn't generate a temporary file for the patch any more
|
||||||
|
- Update the UI to allow downloading Patch or Diff
|
||||||
|
|
||||||
|
v 3.1.0
|
||||||
|
- Updated gems
|
||||||
|
- Services: Gitlab CI integration
|
||||||
|
- Events filter on dashboard
|
||||||
|
- Own namespace for redis/resque
|
||||||
|
- Optimized commit diff views
|
||||||
|
- add alphabetical order for projects admin page
|
||||||
|
- Improved web editor
|
||||||
|
- Commit stats page
|
||||||
|
- Documentation split and cleanup
|
||||||
|
- Link to commit authors everywhere
|
||||||
|
- Restyled milestones list
|
||||||
|
- added Milestone to Merge Request
|
||||||
|
- Restyled Top panel
|
||||||
|
- Refactored Satellite Code
|
||||||
|
- Added file line links
|
||||||
|
- moved from capybara-webkit to poltergeist + phantomjs
|
||||||
|
|
||||||
|
v 3.0.3
|
||||||
|
- Fixed bug with issues list in Chrome
|
||||||
|
- New Feature: Import team from another project
|
||||||
|
|
||||||
|
v 3.0.2
|
||||||
|
- Fixed gitlab:app:setup
|
||||||
|
- Fixed application error on empty project in admin area
|
||||||
|
- Restyled last push widget
|
||||||
|
|
||||||
|
v 3.0.1
|
||||||
|
- Fixed git over http
|
||||||
|
|
||||||
|
v 3.0.0
|
||||||
|
- Projects groups
|
||||||
|
- Web Editor
|
||||||
|
- Fixed bug with gitolite keys
|
||||||
|
- UI improved
|
||||||
|
- Increased performance of application
|
||||||
|
- Show user avatar in last commit when browsing Files
|
||||||
|
- Refactored Gitlab::Merge
|
||||||
|
- Use Font Awesome for icons
|
||||||
|
- Separate observing of Note and MergeRequests
|
||||||
|
- Milestone "All Issues" filter
|
||||||
|
- Fix issue close and reopen button text and styles
|
||||||
|
- Fix forward/back while browsing Tree hierarchy
|
||||||
|
- Show number of notes for commits and merge requests
|
||||||
|
- Added support pg from box and update installation doc
|
||||||
|
- Reject ssh keys that break gitolite
|
||||||
|
- [API] list one project hook
|
||||||
|
- [API] edit project hook
|
||||||
|
- [API] list project snippets
|
||||||
|
- [API] allow to authorize using private token in HTTP header
|
||||||
|
- [API] add user creation
|
||||||
|
|
||||||
|
v 2.9.1
|
||||||
|
- Fixed resque custom config init
|
||||||
|
|
||||||
|
v 2.9.0
|
||||||
|
- fixed inline notes bugs
|
||||||
|
- refactored rspecs
|
||||||
|
- refactored gitolite backend
|
||||||
|
- added factory_girl
|
||||||
|
- restyled projects list on dashboard
|
||||||
|
- ssh keys validation to prevent gitolite crash
|
||||||
|
- send notifications if changed permission in project
|
||||||
|
- scss refactoring. gitlab_bootstrap/ dir
|
||||||
|
- fix git push http body bigger than 112k problem
|
||||||
|
- list of labels page under issues tab
|
||||||
|
- API for milestones, keys
|
||||||
|
- restyled buttons
|
||||||
|
- OAuth
|
||||||
|
- Comment order changed
|
||||||
|
|
||||||
|
v 2.8.1
|
||||||
|
- ability to disable gravatars
|
||||||
|
- improved MR diff logic
|
||||||
|
- ssh key help page
|
||||||
|
|
||||||
|
v 2.8.0
|
||||||
|
- Gitlab Flavored Markdown
|
||||||
|
- Bulk issues update
|
||||||
|
- Issues API
|
||||||
|
- Cucumber coverage increased
|
||||||
|
- Post-receive files fixed
|
||||||
|
- UI improved
|
||||||
|
- Application cleanup
|
||||||
|
- more cucumber
|
||||||
|
- capybara-webkit + headless
|
||||||
|
|
||||||
|
v 2.7.0
|
||||||
|
- Issue Labels
|
||||||
|
- Inline diff
|
||||||
|
- Git HTTP
|
||||||
|
- API
|
||||||
|
- UI improved
|
||||||
|
- System hooks
|
||||||
|
- UI improved
|
||||||
|
- Dashboard events endless scroll
|
||||||
|
- Source performance increased
|
||||||
|
|
||||||
|
v 2.6.0
|
||||||
|
- UI polished
|
||||||
|
- Improved network graph + keyboard nav
|
||||||
|
- Handle huge commits
|
||||||
|
- Last Push widget
|
||||||
|
- Bugfix
|
||||||
|
- Better performance
|
||||||
|
- Email in resque
|
||||||
|
- Increased test coverage
|
||||||
|
- Ability to remove branch with MR accept
|
||||||
|
- a lot of code refactored
|
||||||
|
|
||||||
|
v 2.5.0
|
||||||
|
- UI polished
|
||||||
|
- Git blame for file
|
||||||
|
- Bugfix
|
||||||
|
- Email in resque
|
||||||
|
- Better test coverage
|
||||||
|
|
||||||
|
v 2.4.0
|
||||||
|
- Admin area stats page
|
||||||
|
- Ability to block user
|
||||||
|
- Simplified dashboard area
|
||||||
|
- Improved admin area
|
||||||
|
- Bootstrap 2.0
|
||||||
|
- Responsive layout
|
||||||
|
- Big commits handling
|
||||||
|
- Performance improved
|
||||||
|
- Milestones
|
||||||
|
|
||||||
|
v 2.3.1
|
||||||
|
- Issues pagination
|
||||||
|
- ssl fixes
|
||||||
|
- Merge Request pagination
|
||||||
|
|
||||||
|
v 2.3.0
|
||||||
|
- Dashboard r1
|
||||||
|
- Search r1
|
||||||
|
- Project page
|
||||||
|
- Close merge request on push
|
||||||
|
- Persist MR diff after merge
|
||||||
|
- mysql support
|
||||||
|
- Documentation
|
||||||
|
|
||||||
|
v 2.2.0
|
||||||
|
- We’ve added support of LDAP auth
|
||||||
|
- Improved permission logic (4 roles system)
|
||||||
|
- Protected branches (now only masters can push to protected branches)
|
||||||
|
- Usability improved
|
||||||
|
- twitter bootstrap integrated
|
||||||
|
- compare view between commits
|
||||||
|
- wiki feature
|
||||||
|
- now you can enable/disable issues, wiki, wall features per project
|
||||||
|
- security fixes
|
||||||
|
- improved code browsing (ajax branch switch etc)
|
||||||
|
- improved per-line commenting
|
||||||
|
- git submodules displayed
|
||||||
|
- moved to rails 3.2
|
||||||
|
- help section improved
|
||||||
|
|
||||||
|
v 2.1.0
|
||||||
|
- Project tab r1
|
||||||
|
- List branches/tags
|
||||||
|
- per line comments
|
||||||
|
- mass user import
|
||||||
|
|
||||||
|
v 2.0.0
|
||||||
|
- gitolite as main git host system
|
||||||
|
- merge requests
|
||||||
|
- project/repo access
|
||||||
|
- link to commit/issue feed
|
||||||
|
- design tab
|
||||||
|
- improved email notifications
|
||||||
|
- restyled dashboard
|
||||||
|
- bugfix
|
||||||
|
|
||||||
|
v 1.2.2
|
||||||
|
- common config file gitlab.yml
|
||||||
|
- issues restyle
|
||||||
|
- snippets restyle
|
||||||
|
- clickable news feed header on dashboard
|
||||||
|
- bugfix
|
||||||
|
|
||||||
|
v 1.2.1
|
||||||
|
- bugfix
|
||||||
|
|
||||||
|
v 1.2.0
|
||||||
|
- new design
|
||||||
|
- user dashboard
|
||||||
|
- network graph
|
||||||
|
- markdown support for comments
|
||||||
|
- encoding issues
|
||||||
|
- wall like twitter timeline
|
||||||
|
|
||||||
|
v 1.1.0
|
||||||
|
- project dashboard
|
||||||
|
- wall redesigned
|
||||||
|
- feature: code snippets
|
||||||
|
- fixed horizontal scroll on file preview
|
||||||
|
- fixed app crash if commit message has invalid chars
|
||||||
|
- bugfix & code cleaning
|
||||||
|
|
||||||
|
v 1.0.2
|
||||||
|
- fixed bug with empty project
|
||||||
|
- added adv validation for project path & code
|
||||||
|
- feature: issues can be sortable
|
||||||
|
- bugfix
|
||||||
|
- username displayed on top panel
|
||||||
|
|
||||||
|
v 1.0.1
|
||||||
|
- fixed: with invalid source code for commit
|
||||||
|
- fixed: lose branch/tag selection when use tree navigation
|
||||||
|
- when history clicked - display path
|
||||||
|
- bug fix & code cleaning
|
||||||
|
|
||||||
|
v 1.0.0
|
||||||
|
- bug fix
|
||||||
|
- projects preview mode
|
||||||
|
|
||||||
|
v 0.9.6
|
||||||
|
- css fix
|
||||||
|
- new repo empty tree until restart server - fixed
|
||||||
|
|
||||||
|
v 0.9.4
|
||||||
|
- security improved
|
||||||
|
- authorization improved
|
||||||
|
- html escaping
|
||||||
|
- bug fix
|
||||||
|
- increased test coverage
|
||||||
|
- design improvements
|
||||||
|
|
||||||
|
v 0.9.1
|
||||||
|
- increased test coverage
|
||||||
|
- design improvements
|
||||||
|
- new issue email notification
|
||||||
|
- updated app name
|
||||||
|
- issue redesigned
|
||||||
|
- issue can be edit
|
||||||
|
|
||||||
|
v 0.8.0
|
||||||
|
- syntax highlight for main file types
|
||||||
|
- redesign
|
||||||
|
- stability
|
||||||
|
- security fixes
|
||||||
|
- increased test coverage
|
||||||
|
- email notification
|
117
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
# Contribute to GitLab
|
||||||
|
|
||||||
|
Thank you for your interest in contributing to GitLab.
|
||||||
|
This guide details how contribute to GitLab in a way that is efficient for everyone.
|
||||||
|
If you have read this guide and want to know how the GitLab core-team operates please see [the GitLab contributing process](PROCESS.md).
|
||||||
|
|
||||||
|
## Contributor license agreement
|
||||||
|
|
||||||
|
By submitting code as an individual you agree to the [individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md). By submitting code as an entity you agree to the [corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md).
|
||||||
|
|
||||||
|
## Security vulnerability disclosure
|
||||||
|
|
||||||
|
Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](http://www.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
|
||||||
|
|
||||||
|
## Closing policy for issues and merge requests
|
||||||
|
|
||||||
|
GitLab is a popular open source project and the capacity to deal with issues and merge requests is limited. Out of respect for our volunteers, issues and merge requests not in line with the guidelines listed in this document may be closed without notice.
|
||||||
|
|
||||||
|
Please treat our volunteers with courtesy and respect, it will go a long way towards getting your issue resolved.
|
||||||
|
|
||||||
|
Issues and merge requests should be in English and contain appropriate language for audiences of all ages.
|
||||||
|
|
||||||
|
## Issue tracker
|
||||||
|
|
||||||
|
To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from [GitLab.com](http://www.gitlab.com/).
|
||||||
|
|
||||||
|
The [issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues) is only for obvious errors in the latest [stable or development release of GitLab](MAINTENANCE.md). If something is wrong but it is not a regression compared to older versions of GitLab please do not open an issue but a feature request. When submitting an issue please conform to the issue submission guidelines listed below. Not all issues will be addressed and your issue is more likely to be addressed if you submit a merge request which partially or fully addresses the issue.
|
||||||
|
|
||||||
|
Issues can be filed either at [gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues) or [github.com](https://github.com/gitlabhq/gitlabhq/issues).
|
||||||
|
|
||||||
|
Do not use the issue tracker for feature requests. We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose. Please keep feature requests as small and simple as possible, complex ones might be edited to make them small and simple.
|
||||||
|
|
||||||
|
Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
|
||||||
|
|
||||||
|
### Issue tracker guidelines
|
||||||
|
|
||||||
|
**[Search the issues](https://gitlab.com/gitlab-org/gitlab-ce/issues)** for similar entries before submitting your own, there's a good chance somebody else had the same issue. Show your support with `:+1:` and/or join the discussion. Please submit issues in the following format (as the first post):
|
||||||
|
|
||||||
|
1. **Summary:** Summarize your issue in one sentence (what goes wrong, what did you expect to happen)
|
||||||
|
1. **Steps to reproduce:** How can we reproduce the issue, preferably on the [GitLab development virtual machine with vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) (start your issue with: `vagrant destroy && vagrant up && vagrant ssh`)
|
||||||
|
1. **Expected behavior:** Describe your issue in detail
|
||||||
|
1. **Observed behavior**
|
||||||
|
1. **Relevant logs and/or screenshots:** Please use code blocks (\`\`\`) to format console output, logs, and code as it's very hard to read otherwise.
|
||||||
|
1. **Output of checks**
|
||||||
|
* Results of GitLab [Application Check](doc/install/installation.md#check-application-status) (`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`); we will only investigate if the tests are passing
|
||||||
|
* Version of GitLab you are running; we will only investigate issues in the latest stable and development releases as per the [maintenance policy](MAINTENANCE.md)
|
||||||
|
* Add the last commit sha1 of the GitLab version you used to replicate the issue (obtainable from the help page)
|
||||||
|
* Describe your setup (use relevant parts from `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
|
||||||
|
1. **Possible fixes**: If you can, link to the line of code that might be responsible for the problem
|
||||||
|
|
||||||
|
## Merge requests
|
||||||
|
|
||||||
|
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 [status 'accepting merge requests' on our feature request forum](http://feedback.gitlab.com/forums/176466-general/status/796455) but other improvements are also welcome. If you want to add a new feature that is not marked it is best to first create a feedback issue (if there isn't one already) and leave a comment asking for it to be marked accepting merge requests. Please include screenshots or wireframes if the feature will also change the UI.
|
||||||
|
|
||||||
|
Merge requests can be filed either at [gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests) or [github.com](https://github.com/gitlabhq/gitlabhq/pulls).
|
||||||
|
|
||||||
|
### Merge request guidelines
|
||||||
|
|
||||||
|
If you can, please submit a merge request with the fix or improvements including tests. If you don't know how to fix the issue but can write a test that exposes the issue we will accept that as well. In general bug fixes that include a regression test are merged quickly while new features without proper tests are least likely to receive timely feedback. The workflow to make a merge request is as follows:
|
||||||
|
|
||||||
|
1. Fork the project on GitLab Cloud
|
||||||
|
1. Create a feature branch
|
||||||
|
1. Write [tests](README.md#run-the-tests) and code
|
||||||
|
1. Add your changes to the [CHANGELOG](CHANGELOG)
|
||||||
|
1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
|
||||||
|
1. Push the commit to your fork
|
||||||
|
1. Submit a merge request (MR) to the master branch
|
||||||
|
1. The MR title should describe the change you want to make
|
||||||
|
1. The MR description should give a motive for your change and the method you used to achieve it
|
||||||
|
1. If the MR changes the UI it should include before and after screenshots
|
||||||
|
1. If the MR changes CSS classes please include the list of affected pages `grep css-class ./app -R`
|
||||||
|
1. Link relevant [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues) and/or [feature requests](http://feedback.gitlab.com/) from the merge request description and leave a comment on them with a link back to the MR
|
||||||
|
1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submission
|
||||||
|
1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
|
||||||
|
|
||||||
|
The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast. Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as assisting subscribers with upgrade issues, the release of Enterprise Edition and the upgrade of GitLab Cloud. After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
|
||||||
|
|
||||||
|
Please keep the change in a single MR **as small as possible**. If you want to contribute a large feature think very hard what the minimum viable change is. Can you split functionality? Can you only submit the backend/API code? Can you start with a very simple UI? Can you do part of the refactor? The increased reviewability of small MR's that leads to higher code quality is more important to us than having a mimimal commit log. The smaller a MR is the more likely it is it will be merged (quickly), after that you can send more MR's to enhance it.
|
||||||
|
|
||||||
|
For examples of feedback on merge requests please look at already [closed merge requests](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed). If you would like quick feedback on your merge request feel free to mention one of the Merge Marshalls of [the core-team](https://about.gitlab.com/core-team/). Please ensure that your merge request meets the following contribution acceptance criteria.
|
||||||
|
|
||||||
|
**Please format your merge request description as follows:**
|
||||||
|
|
||||||
|
1. What does this MR do?
|
||||||
|
1. Are there points in the code the reviewer needs to double check?
|
||||||
|
1. Why was this MR needed?
|
||||||
|
1. What are the relevant issue numbers / [Feature requests](http://feedback.gitlab.com/)?
|
||||||
|
1. Screenshots (If appropiate)
|
||||||
|
|
||||||
|
## Contribution acceptance criteria
|
||||||
|
|
||||||
|
1. The change is as small as possible (see the above paragraph for details)
|
||||||
|
1. Include proper tests and make all tests pass (unless it contains a test exposing a bug in existing code)
|
||||||
|
1. Can merge without problems (if not please use: `git rebase master`)
|
||||||
|
1. Does not break any existing functionality
|
||||||
|
1. Fixes one specific issue or implements one specific feature (do not combine things, send separate merge requests if needed)
|
||||||
|
1. Keeps the GitLab code base clean and well structured
|
||||||
|
1. Contains functionality we think other users will benefit from too
|
||||||
|
1. Doesn't add configuration options since they complicate future changes
|
||||||
|
1. Initially contains a single commit (please use `git rebase -i` to squash commits)
|
||||||
|
1. Changes after submitting the merge request should be in separate commits (no squashing). You will be asked to squash when the review is over, before merging.
|
||||||
|
1. It conforms to the following style guides
|
||||||
|
|
||||||
|
## Style guides
|
||||||
|
|
||||||
|
1. [Ruby](https://github.com/bbatsov/ruby-style-guide).
|
||||||
|
Important sections include [Source Code Layout](https://github.com/bbatsov/ruby-style-guide#source-code-layout)
|
||||||
|
and [Naming](https://github.com/bbatsov/ruby-style-guide#naming). Use:
|
||||||
|
- multi-line method chaining style **Option B**: dot `.` on previous line
|
||||||
|
- string literal quoting style **Option A**: single quoted by default
|
||||||
|
1. [Rails](https://github.com/bbatsov/rails-style-guide)
|
||||||
|
1. [Testing](https://github.com/thoughtbot/guides/tree/master/style#testing)
|
||||||
|
1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style#coffeescript)
|
||||||
|
1. [Shell commands](doc/development/shell_commands.md) created by GitLab contributors to enhance security
|
||||||
|
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
|
||||||
|
|
||||||
|
This is also the style used by linting tools such as [Rubocop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
|
1
GITLAB_SHELL_VERSION
Normal file
|
@ -0,0 +1 @@
|
||||||
|
1.9.7
|
249
Gemfile
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
source "https://rubygems.org"
|
||||||
|
|
||||||
|
def darwin_only(require_as)
|
||||||
|
RUBY_PLATFORM.include?('darwin') && require_as
|
||||||
|
end
|
||||||
|
|
||||||
|
def linux_only(require_as)
|
||||||
|
RUBY_PLATFORM.include?('linux') && require_as
|
||||||
|
end
|
||||||
|
|
||||||
|
gem "rails", "~> 4.1.0"
|
||||||
|
|
||||||
|
# Make links from text
|
||||||
|
gem 'rails_autolink', '~> 1.1'
|
||||||
|
|
||||||
|
# Default values for AR models
|
||||||
|
gem "default_value_for", "~> 3.0.0"
|
||||||
|
|
||||||
|
# Supported DBs
|
||||||
|
gem "mysql2", group: :mysql
|
||||||
|
gem "pg", group: :postgres
|
||||||
|
|
||||||
|
# Auth
|
||||||
|
gem "devise", '3.2.4'
|
||||||
|
gem "devise-async", '0.9.0'
|
||||||
|
gem 'omniauth', "~> 1.1.3"
|
||||||
|
gem 'omniauth-google-oauth2'
|
||||||
|
gem 'omniauth-twitter'
|
||||||
|
gem 'omniauth-github'
|
||||||
|
|
||||||
|
# Extracting information from a git repository
|
||||||
|
# Provide access to Gitlab::Git library
|
||||||
|
gem "gitlab_git", '~> 6.0'
|
||||||
|
|
||||||
|
# Ruby/Rack Git Smart-HTTP Server Handler
|
||||||
|
gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
|
||||||
|
|
||||||
|
# LDAP Auth
|
||||||
|
gem 'gitlab_omniauth-ldap', '1.0.4', require: "omniauth-ldap"
|
||||||
|
|
||||||
|
# Git Wiki
|
||||||
|
gem 'gollum-lib', '~> 3.0.0'
|
||||||
|
|
||||||
|
# Language detection
|
||||||
|
gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
|
||||||
|
|
||||||
|
# API
|
||||||
|
gem "grape", "~> 0.6.1"
|
||||||
|
gem "grape-entity", "~> 0.4.2"
|
||||||
|
gem 'rack-cors', require: 'rack/cors'
|
||||||
|
|
||||||
|
# Format dates and times
|
||||||
|
# based on human-friendly examples
|
||||||
|
gem "stamp"
|
||||||
|
|
||||||
|
# Enumeration fields
|
||||||
|
gem 'enumerize'
|
||||||
|
|
||||||
|
# Pagination
|
||||||
|
gem "kaminari", "~> 0.15.1"
|
||||||
|
|
||||||
|
# HAML
|
||||||
|
gem "haml-rails"
|
||||||
|
|
||||||
|
# Files attachments
|
||||||
|
gem "carrierwave"
|
||||||
|
|
||||||
|
# Drag and Drop UI
|
||||||
|
gem 'dropzonejs-rails'
|
||||||
|
|
||||||
|
# for aws storage
|
||||||
|
gem "fog", "~> 1.14", group: :aws
|
||||||
|
gem "unf", group: :aws
|
||||||
|
|
||||||
|
# Authorization
|
||||||
|
gem "six"
|
||||||
|
|
||||||
|
# Seed data
|
||||||
|
gem "seed-fu"
|
||||||
|
|
||||||
|
# Markdown to HTML
|
||||||
|
gem "github-markup"
|
||||||
|
|
||||||
|
# Required markup gems by github-markdown
|
||||||
|
gem 'redcarpet', '~> 2.2.2'
|
||||||
|
gem 'RedCloth'
|
||||||
|
gem 'rdoc', '~>3.6'
|
||||||
|
gem 'org-ruby'
|
||||||
|
gem 'creole', '~>0.3.6'
|
||||||
|
gem 'wikicloth', '=0.8.1'
|
||||||
|
gem 'asciidoctor', '= 0.1.4'
|
||||||
|
|
||||||
|
# Diffs
|
||||||
|
gem 'diffy', '~> 3.0.3'
|
||||||
|
|
||||||
|
# Application server
|
||||||
|
group :unicorn do
|
||||||
|
gem "unicorn", '~> 4.6.3'
|
||||||
|
gem 'unicorn-worker-killer'
|
||||||
|
end
|
||||||
|
|
||||||
|
# State machine
|
||||||
|
gem "state_machine"
|
||||||
|
|
||||||
|
# Issue tags
|
||||||
|
gem "acts-as-taggable-on"
|
||||||
|
|
||||||
|
# Background jobs
|
||||||
|
gem 'slim'
|
||||||
|
gem 'sinatra', require: nil
|
||||||
|
gem 'sidekiq', '2.17.0'
|
||||||
|
|
||||||
|
# HTTP requests
|
||||||
|
gem "httparty"
|
||||||
|
|
||||||
|
# Colored output to console
|
||||||
|
gem "colored"
|
||||||
|
|
||||||
|
# GitLab settings
|
||||||
|
gem 'settingslogic'
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
gem "foreman"
|
||||||
|
gem 'version_sorter'
|
||||||
|
|
||||||
|
# Cache
|
||||||
|
gem "redis-rails"
|
||||||
|
|
||||||
|
# Campfire integration
|
||||||
|
gem 'tinder', '~> 1.9.2'
|
||||||
|
|
||||||
|
# HipChat integration
|
||||||
|
gem "hipchat", "~> 0.14.0"
|
||||||
|
|
||||||
|
# Flowdock integration
|
||||||
|
gem "gitlab-flowdock-git-hook", "~> 0.4.2"
|
||||||
|
|
||||||
|
# Gemnasium integration
|
||||||
|
gem "gemnasium-gitlab-service", "~> 0.2"
|
||||||
|
|
||||||
|
# Slack integration
|
||||||
|
gem "slack-notifier", "~> 0.3.2"
|
||||||
|
|
||||||
|
# d3
|
||||||
|
gem "d3_rails", "~> 3.1.4"
|
||||||
|
|
||||||
|
# underscore-rails
|
||||||
|
gem "underscore-rails", "~> 1.4.4"
|
||||||
|
|
||||||
|
# Sanitize user input
|
||||||
|
gem "sanitize", '~> 2.0'
|
||||||
|
|
||||||
|
# Protect against bruteforcing
|
||||||
|
gem "rack-attack"
|
||||||
|
|
||||||
|
# Ace editor
|
||||||
|
gem 'ace-rails-ap'
|
||||||
|
|
||||||
|
# Semantic UI Sass for Sidebar
|
||||||
|
gem 'semantic-ui-sass', '~> 0.16.1.0'
|
||||||
|
|
||||||
|
gem "sass-rails", '~> 4.0.2'
|
||||||
|
gem "coffee-rails"
|
||||||
|
gem "uglifier"
|
||||||
|
gem "therubyracer"
|
||||||
|
gem 'turbolinks'
|
||||||
|
gem 'jquery-turbolinks'
|
||||||
|
|
||||||
|
gem 'select2-rails'
|
||||||
|
gem 'jquery-atwho-rails', "~> 0.3.3"
|
||||||
|
gem "jquery-rails"
|
||||||
|
gem "jquery-ui-rails"
|
||||||
|
gem "jquery-scrollto-rails"
|
||||||
|
gem "raphael-rails", "~> 2.1.2"
|
||||||
|
gem 'bootstrap-sass', '~> 3.0'
|
||||||
|
gem "font-awesome-rails", '~> 3.2'
|
||||||
|
gem "gitlab_emoji", "~> 0.0.1.1"
|
||||||
|
gem "gon", '~> 5.0.0'
|
||||||
|
gem 'nprogress-rails'
|
||||||
|
gem 'request_store'
|
||||||
|
gem "virtus"
|
||||||
|
|
||||||
|
group :development do
|
||||||
|
gem "annotate", "~> 2.6.0.beta2"
|
||||||
|
gem "letter_opener"
|
||||||
|
gem 'quiet_assets', '~> 1.0.1'
|
||||||
|
gem 'rack-mini-profiler', require: false
|
||||||
|
|
||||||
|
# Better errors handler
|
||||||
|
gem 'better_errors'
|
||||||
|
gem 'binding_of_caller'
|
||||||
|
|
||||||
|
gem 'rails_best_practices'
|
||||||
|
|
||||||
|
# Docs generator
|
||||||
|
gem "sdoc"
|
||||||
|
|
||||||
|
# thin instead webrick
|
||||||
|
gem 'thin'
|
||||||
|
end
|
||||||
|
|
||||||
|
group :development, :test do
|
||||||
|
gem 'coveralls', require: false
|
||||||
|
# gem 'rails-dev-tweaks'
|
||||||
|
gem 'spinach-rails'
|
||||||
|
gem "rspec-rails"
|
||||||
|
gem "capybara", '~> 2.2.1'
|
||||||
|
gem "pry"
|
||||||
|
gem "awesome_print"
|
||||||
|
gem "database_cleaner"
|
||||||
|
gem "launchy"
|
||||||
|
gem 'factory_girl_rails'
|
||||||
|
|
||||||
|
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
|
||||||
|
gem 'minitest', '~> 5.3.0'
|
||||||
|
|
||||||
|
# Generate Fake data
|
||||||
|
gem "ffaker"
|
||||||
|
|
||||||
|
# Guard
|
||||||
|
gem 'guard-rspec'
|
||||||
|
gem 'guard-spinach'
|
||||||
|
|
||||||
|
# Notification
|
||||||
|
gem 'rb-fsevent', require: darwin_only('rb-fsevent')
|
||||||
|
gem 'growl', require: darwin_only('growl')
|
||||||
|
gem 'rb-inotify', require: linux_only('rb-inotify')
|
||||||
|
|
||||||
|
# PhantomJS driver for Capybara
|
||||||
|
gem 'poltergeist', '~> 1.5.1'
|
||||||
|
|
||||||
|
gem 'jasmine', '2.0.2'
|
||||||
|
|
||||||
|
gem "spring", '1.1.1'
|
||||||
|
gem "spring-commands-rspec", '1.0.1'
|
||||||
|
gem "spring-commands-spinach", '1.0.0'
|
||||||
|
end
|
||||||
|
|
||||||
|
group :test do
|
||||||
|
gem "simplecov", require: false
|
||||||
|
gem "shoulda-matchers", "~> 2.1.0"
|
||||||
|
gem 'email_spec'
|
||||||
|
gem "webmock"
|
||||||
|
gem 'test_after_commit'
|
||||||
|
end
|
||||||
|
|
||||||
|
group :production do
|
||||||
|
gem "gitlab_meta", '7.0'
|
||||||
|
end
|
697
Gemfile.lock
Normal file
|
@ -0,0 +1,697 @@
|
||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
RedCloth (4.2.9)
|
||||||
|
ace-rails-ap (2.0.1)
|
||||||
|
actionmailer (4.1.1)
|
||||||
|
actionpack (= 4.1.1)
|
||||||
|
actionview (= 4.1.1)
|
||||||
|
mail (~> 2.5.4)
|
||||||
|
actionpack (4.1.1)
|
||||||
|
actionview (= 4.1.1)
|
||||||
|
activesupport (= 4.1.1)
|
||||||
|
rack (~> 1.5.2)
|
||||||
|
rack-test (~> 0.6.2)
|
||||||
|
actionview (4.1.1)
|
||||||
|
activesupport (= 4.1.1)
|
||||||
|
builder (~> 3.1)
|
||||||
|
erubis (~> 2.7.0)
|
||||||
|
activemodel (4.1.1)
|
||||||
|
activesupport (= 4.1.1)
|
||||||
|
builder (~> 3.1)
|
||||||
|
activerecord (4.1.1)
|
||||||
|
activemodel (= 4.1.1)
|
||||||
|
activesupport (= 4.1.1)
|
||||||
|
arel (~> 5.0.0)
|
||||||
|
activesupport (4.1.1)
|
||||||
|
i18n (~> 0.6, >= 0.6.9)
|
||||||
|
json (~> 1.7, >= 1.7.7)
|
||||||
|
minitest (~> 5.1)
|
||||||
|
thread_safe (~> 0.1)
|
||||||
|
tzinfo (~> 1.1)
|
||||||
|
acts-as-taggable-on (2.4.1)
|
||||||
|
rails (>= 3, < 5)
|
||||||
|
addressable (2.3.5)
|
||||||
|
annotate (2.6.0)
|
||||||
|
activerecord (>= 2.3.0)
|
||||||
|
rake (>= 0.8.7)
|
||||||
|
arel (5.0.1.20140414130214)
|
||||||
|
asciidoctor (0.1.4)
|
||||||
|
awesome_print (1.2.0)
|
||||||
|
axiom-types (0.0.5)
|
||||||
|
descendants_tracker (~> 0.0.1)
|
||||||
|
ice_nine (~> 0.9)
|
||||||
|
bcrypt (3.1.7)
|
||||||
|
better_errors (1.0.1)
|
||||||
|
coderay (>= 1.0.0)
|
||||||
|
erubis (>= 2.6.6)
|
||||||
|
binding_of_caller (0.7.2)
|
||||||
|
debug_inspector (>= 0.0.1)
|
||||||
|
bootstrap-sass (3.0.3.0)
|
||||||
|
sass (~> 3.2)
|
||||||
|
builder (3.2.2)
|
||||||
|
capybara (2.2.1)
|
||||||
|
mime-types (>= 1.16)
|
||||||
|
nokogiri (>= 1.3.3)
|
||||||
|
rack (>= 1.0.0)
|
||||||
|
rack-test (>= 0.5.4)
|
||||||
|
xpath (~> 2.0)
|
||||||
|
carrierwave (0.9.0)
|
||||||
|
activemodel (>= 3.2.0)
|
||||||
|
activesupport (>= 3.2.0)
|
||||||
|
json (>= 1.7)
|
||||||
|
celluloid (0.15.2)
|
||||||
|
timers (~> 1.1.0)
|
||||||
|
charlock_holmes (0.6.9.4)
|
||||||
|
cliver (0.3.2)
|
||||||
|
code_analyzer (0.4.3)
|
||||||
|
sexp_processor
|
||||||
|
coderay (1.1.0)
|
||||||
|
coercible (1.0.0)
|
||||||
|
descendants_tracker (~> 0.0.1)
|
||||||
|
coffee-rails (4.0.1)
|
||||||
|
coffee-script (>= 2.2.0)
|
||||||
|
railties (>= 4.0.0, < 5.0)
|
||||||
|
coffee-script (2.2.0)
|
||||||
|
coffee-script-source
|
||||||
|
execjs
|
||||||
|
coffee-script-source (1.6.3)
|
||||||
|
colored (1.2)
|
||||||
|
colorize (0.5.8)
|
||||||
|
connection_pool (1.2.0)
|
||||||
|
coveralls (0.7.0)
|
||||||
|
multi_json (~> 1.3)
|
||||||
|
rest-client
|
||||||
|
simplecov (>= 0.7)
|
||||||
|
term-ansicolor
|
||||||
|
thor
|
||||||
|
crack (0.4.1)
|
||||||
|
safe_yaml (~> 0.9.0)
|
||||||
|
creole (0.3.8)
|
||||||
|
d3_rails (3.1.10)
|
||||||
|
railties (>= 3.1.0)
|
||||||
|
daemons (1.1.9)
|
||||||
|
database_cleaner (1.3.0)
|
||||||
|
debug_inspector (0.0.2)
|
||||||
|
default_value_for (3.0.0)
|
||||||
|
activerecord (>= 3.2.0, < 5.0)
|
||||||
|
descendants_tracker (0.0.3)
|
||||||
|
devise (3.2.4)
|
||||||
|
bcrypt (~> 3.0)
|
||||||
|
orm_adapter (~> 0.1)
|
||||||
|
railties (>= 3.2.6, < 5)
|
||||||
|
thread_safe (~> 0.1)
|
||||||
|
warden (~> 1.2.3)
|
||||||
|
devise-async (0.9.0)
|
||||||
|
devise (~> 3.2)
|
||||||
|
diff-lcs (1.2.5)
|
||||||
|
diffy (3.0.3)
|
||||||
|
docile (1.1.1)
|
||||||
|
dotenv (0.9.0)
|
||||||
|
dropzonejs-rails (0.4.14)
|
||||||
|
rails (> 3.1)
|
||||||
|
email_spec (1.5.0)
|
||||||
|
launchy (~> 2.1)
|
||||||
|
mail (~> 2.2)
|
||||||
|
emoji (1.0.1)
|
||||||
|
json
|
||||||
|
enumerize (0.7.0)
|
||||||
|
activesupport (>= 3.2)
|
||||||
|
equalizer (0.0.8)
|
||||||
|
erubis (2.7.0)
|
||||||
|
escape_utils (0.2.4)
|
||||||
|
eventmachine (1.0.3)
|
||||||
|
excon (0.32.1)
|
||||||
|
execjs (2.0.2)
|
||||||
|
expression_parser (0.9.0)
|
||||||
|
factory_girl (4.3.0)
|
||||||
|
activesupport (>= 3.0.0)
|
||||||
|
factory_girl_rails (4.3.0)
|
||||||
|
factory_girl (~> 4.3.0)
|
||||||
|
railties (>= 3.0.0)
|
||||||
|
faraday (0.8.9)
|
||||||
|
multipart-post (~> 1.2.0)
|
||||||
|
faraday_middleware (0.9.0)
|
||||||
|
faraday (>= 0.7.4, < 0.9)
|
||||||
|
ffaker (1.22.1)
|
||||||
|
ffi (1.9.3)
|
||||||
|
fog (1.21.0)
|
||||||
|
fog-brightbox
|
||||||
|
fog-core (~> 1.21, >= 1.21.1)
|
||||||
|
fog-json
|
||||||
|
nokogiri (~> 1.5, >= 1.5.11)
|
||||||
|
fog-brightbox (0.0.1)
|
||||||
|
fog-core
|
||||||
|
fog-json
|
||||||
|
fog-core (1.21.1)
|
||||||
|
builder
|
||||||
|
excon (~> 0.32)
|
||||||
|
formatador (~> 0.2.0)
|
||||||
|
mime-types
|
||||||
|
net-scp (~> 1.1)
|
||||||
|
net-ssh (>= 2.1.3)
|
||||||
|
fog-json (1.0.0)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
font-awesome-rails (3.2.1.3)
|
||||||
|
railties (>= 3.2, < 5.0)
|
||||||
|
foreman (0.63.0)
|
||||||
|
dotenv (>= 0.7)
|
||||||
|
thor (>= 0.13.6)
|
||||||
|
formatador (0.2.4)
|
||||||
|
gemnasium-gitlab-service (0.2.2)
|
||||||
|
rugged (~> 0.19)
|
||||||
|
gherkin-ruby (0.3.1)
|
||||||
|
racc
|
||||||
|
github-markup (1.1.0)
|
||||||
|
gitlab-flowdock-git-hook (0.4.2.2)
|
||||||
|
gitlab-grit (>= 2.4.1)
|
||||||
|
multi_json
|
||||||
|
gitlab-grack (2.0.0.pre)
|
||||||
|
rack (~> 1.5.1)
|
||||||
|
gitlab-grit (2.6.10)
|
||||||
|
charlock_holmes (~> 0.6)
|
||||||
|
diff-lcs (~> 1.1)
|
||||||
|
mime-types (~> 1.15)
|
||||||
|
posix-spawn (~> 0.3)
|
||||||
|
gitlab-linguist (3.0.0)
|
||||||
|
charlock_holmes (~> 0.6.6)
|
||||||
|
escape_utils (~> 0.2.4)
|
||||||
|
mime-types (~> 1.19)
|
||||||
|
gitlab_emoji (0.0.1.1)
|
||||||
|
emoji (~> 1.0.1)
|
||||||
|
gitlab_git (6.2.1)
|
||||||
|
activesupport (~> 4.0)
|
||||||
|
charlock_holmes (~> 0.6)
|
||||||
|
gitlab-grit (~> 2.6)
|
||||||
|
gitlab-linguist (~> 3.0)
|
||||||
|
rugged (~> 0.21.0)
|
||||||
|
gitlab_meta (7.0)
|
||||||
|
gitlab_omniauth-ldap (1.0.4)
|
||||||
|
net-ldap (~> 0.3.1)
|
||||||
|
omniauth (~> 1.0)
|
||||||
|
pyu-ruby-sasl (~> 0.0.3.1)
|
||||||
|
rubyntlm (~> 0.1.1)
|
||||||
|
gollum-lib (3.0.0)
|
||||||
|
github-markup (~> 1.1.0)
|
||||||
|
gitlab-grit (~> 2.6.5)
|
||||||
|
nokogiri (~> 1.6.1)
|
||||||
|
rouge (~> 1.3.3)
|
||||||
|
sanitize (~> 2.1.0)
|
||||||
|
stringex (~> 2.5.1)
|
||||||
|
gon (5.0.1)
|
||||||
|
actionpack (>= 2.3.0)
|
||||||
|
json
|
||||||
|
grape (0.6.1)
|
||||||
|
activesupport
|
||||||
|
builder
|
||||||
|
hashie (>= 1.2.0)
|
||||||
|
multi_json (>= 1.3.2)
|
||||||
|
multi_xml (>= 0.5.2)
|
||||||
|
rack (>= 1.3.0)
|
||||||
|
rack-accept
|
||||||
|
rack-mount
|
||||||
|
virtus (>= 1.0.0)
|
||||||
|
grape-entity (0.4.2)
|
||||||
|
activesupport
|
||||||
|
multi_json (>= 1.3.2)
|
||||||
|
growl (1.0.3)
|
||||||
|
guard (2.2.4)
|
||||||
|
formatador (>= 0.2.4)
|
||||||
|
listen (~> 2.1)
|
||||||
|
lumberjack (~> 1.0)
|
||||||
|
pry (>= 0.9.12)
|
||||||
|
thor (>= 0.18.1)
|
||||||
|
guard-rspec (4.2.0)
|
||||||
|
guard (>= 2.1.1)
|
||||||
|
rspec (>= 2.14, < 4.0)
|
||||||
|
guard-spinach (0.0.2)
|
||||||
|
guard (>= 1.1)
|
||||||
|
spinach
|
||||||
|
haml (4.0.5)
|
||||||
|
tilt
|
||||||
|
haml-rails (0.5.3)
|
||||||
|
actionpack (>= 4.0.1)
|
||||||
|
activesupport (>= 4.0.1)
|
||||||
|
haml (>= 3.1, < 5.0)
|
||||||
|
railties (>= 4.0.1)
|
||||||
|
hashie (2.1.2)
|
||||||
|
hike (1.2.3)
|
||||||
|
hipchat (0.14.0)
|
||||||
|
httparty
|
||||||
|
httparty
|
||||||
|
http_parser.rb (0.5.3)
|
||||||
|
httparty (0.13.0)
|
||||||
|
json (~> 1.8)
|
||||||
|
multi_xml (>= 0.5.2)
|
||||||
|
httpauth (0.2.1)
|
||||||
|
i18n (0.6.11)
|
||||||
|
ice_nine (0.10.0)
|
||||||
|
jasmine (2.0.2)
|
||||||
|
jasmine-core (~> 2.0.0)
|
||||||
|
phantomjs
|
||||||
|
rack (>= 1.2.1)
|
||||||
|
rake
|
||||||
|
jasmine-core (2.0.0)
|
||||||
|
jquery-atwho-rails (0.3.3)
|
||||||
|
jquery-rails (3.1.0)
|
||||||
|
railties (>= 3.0, < 5.0)
|
||||||
|
thor (>= 0.14, < 2.0)
|
||||||
|
jquery-scrollto-rails (1.4.3)
|
||||||
|
railties (> 3.1, < 5.0)
|
||||||
|
jquery-turbolinks (2.0.1)
|
||||||
|
railties (>= 3.1.0)
|
||||||
|
turbolinks
|
||||||
|
jquery-ui-rails (4.2.1)
|
||||||
|
railties (>= 3.2.16)
|
||||||
|
json (1.8.1)
|
||||||
|
jwt (0.1.13)
|
||||||
|
multi_json (>= 1.5)
|
||||||
|
kaminari (0.15.1)
|
||||||
|
actionpack (>= 3.0.0)
|
||||||
|
activesupport (>= 3.0.0)
|
||||||
|
kgio (2.8.1)
|
||||||
|
launchy (2.4.2)
|
||||||
|
addressable (~> 2.3)
|
||||||
|
letter_opener (1.1.2)
|
||||||
|
launchy (~> 2.2)
|
||||||
|
libv8 (3.16.14.3)
|
||||||
|
listen (2.3.1)
|
||||||
|
celluloid (>= 0.15.2)
|
||||||
|
rb-fsevent (>= 0.9.3)
|
||||||
|
rb-inotify (>= 0.9)
|
||||||
|
lumberjack (1.0.4)
|
||||||
|
mail (2.5.4)
|
||||||
|
mime-types (~> 1.16)
|
||||||
|
treetop (~> 1.4.8)
|
||||||
|
method_source (0.8.2)
|
||||||
|
mime-types (1.25.1)
|
||||||
|
mini_portile (0.6.0)
|
||||||
|
minitest (5.3.5)
|
||||||
|
multi_json (1.10.1)
|
||||||
|
multi_xml (0.5.5)
|
||||||
|
multipart-post (1.2.0)
|
||||||
|
mysql2 (0.3.16)
|
||||||
|
net-ldap (0.3.1)
|
||||||
|
net-scp (1.1.2)
|
||||||
|
net-ssh (>= 2.6.5)
|
||||||
|
net-ssh (2.8.0)
|
||||||
|
nokogiri (1.6.2.1)
|
||||||
|
mini_portile (= 0.6.0)
|
||||||
|
nprogress-rails (0.1.2.3)
|
||||||
|
oauth (0.4.7)
|
||||||
|
oauth2 (0.8.1)
|
||||||
|
faraday (~> 0.8)
|
||||||
|
httpauth (~> 0.1)
|
||||||
|
jwt (~> 0.1.4)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
rack (~> 1.2)
|
||||||
|
omniauth (1.1.4)
|
||||||
|
hashie (>= 1.2, < 3)
|
||||||
|
rack
|
||||||
|
omniauth-github (1.1.1)
|
||||||
|
omniauth (~> 1.0)
|
||||||
|
omniauth-oauth2 (~> 1.1)
|
||||||
|
omniauth-google-oauth2 (0.2.5)
|
||||||
|
omniauth (> 1.0)
|
||||||
|
omniauth-oauth2 (~> 1.1)
|
||||||
|
omniauth-oauth (1.0.1)
|
||||||
|
oauth
|
||||||
|
omniauth (~> 1.0)
|
||||||
|
omniauth-oauth2 (1.1.1)
|
||||||
|
oauth2 (~> 0.8.0)
|
||||||
|
omniauth (~> 1.0)
|
||||||
|
omniauth-twitter (1.0.1)
|
||||||
|
multi_json (~> 1.3)
|
||||||
|
omniauth-oauth (~> 1.0)
|
||||||
|
org-ruby (0.9.8)
|
||||||
|
rubypants (~> 0.2)
|
||||||
|
orm_adapter (0.5.0)
|
||||||
|
pg (0.15.1)
|
||||||
|
phantomjs (1.9.2.0)
|
||||||
|
poltergeist (1.5.1)
|
||||||
|
capybara (~> 2.1)
|
||||||
|
cliver (~> 0.3.1)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
websocket-driver (>= 0.2.0)
|
||||||
|
polyglot (0.3.4)
|
||||||
|
posix-spawn (0.3.9)
|
||||||
|
pry (0.9.12.4)
|
||||||
|
coderay (~> 1.0)
|
||||||
|
method_source (~> 0.8)
|
||||||
|
slop (~> 3.4)
|
||||||
|
pyu-ruby-sasl (0.0.3.3)
|
||||||
|
quiet_assets (1.0.2)
|
||||||
|
railties (>= 3.1, < 5.0)
|
||||||
|
racc (1.4.10)
|
||||||
|
rack (1.5.2)
|
||||||
|
rack-accept (0.4.5)
|
||||||
|
rack (>= 0.4)
|
||||||
|
rack-attack (2.3.0)
|
||||||
|
rack
|
||||||
|
rack-cors (0.2.9)
|
||||||
|
rack-mini-profiler (0.9.0)
|
||||||
|
rack (>= 1.1.3)
|
||||||
|
rack-mount (0.8.3)
|
||||||
|
rack (>= 1.0.0)
|
||||||
|
rack-protection (1.5.1)
|
||||||
|
rack
|
||||||
|
rack-test (0.6.2)
|
||||||
|
rack (>= 1.0)
|
||||||
|
rails (4.1.1)
|
||||||
|
actionmailer (= 4.1.1)
|
||||||
|
actionpack (= 4.1.1)
|
||||||
|
actionview (= 4.1.1)
|
||||||
|
activemodel (= 4.1.1)
|
||||||
|
activerecord (= 4.1.1)
|
||||||
|
activesupport (= 4.1.1)
|
||||||
|
bundler (>= 1.3.0, < 2.0)
|
||||||
|
railties (= 4.1.1)
|
||||||
|
sprockets-rails (~> 2.0)
|
||||||
|
rails_autolink (1.1.6)
|
||||||
|
rails (> 3.1)
|
||||||
|
rails_best_practices (1.14.4)
|
||||||
|
activesupport
|
||||||
|
awesome_print
|
||||||
|
code_analyzer (>= 0.4.3)
|
||||||
|
colored
|
||||||
|
erubis
|
||||||
|
i18n
|
||||||
|
require_all
|
||||||
|
ruby-progressbar
|
||||||
|
railties (4.1.1)
|
||||||
|
actionpack (= 4.1.1)
|
||||||
|
activesupport (= 4.1.1)
|
||||||
|
rake (>= 0.8.7)
|
||||||
|
thor (>= 0.18.1, < 2.0)
|
||||||
|
raindrops (0.12.0)
|
||||||
|
rake (10.3.2)
|
||||||
|
raphael-rails (2.1.2)
|
||||||
|
rb-fsevent (0.9.3)
|
||||||
|
rb-inotify (0.9.2)
|
||||||
|
ffi (>= 0.5.0)
|
||||||
|
rdoc (3.12.2)
|
||||||
|
json (~> 1.4)
|
||||||
|
redcarpet (2.2.2)
|
||||||
|
redis (3.0.6)
|
||||||
|
redis-actionpack (4.0.0)
|
||||||
|
actionpack (~> 4)
|
||||||
|
redis-rack (~> 1.5.0)
|
||||||
|
redis-store (~> 1.1.0)
|
||||||
|
redis-activesupport (4.0.0)
|
||||||
|
activesupport (~> 4)
|
||||||
|
redis-store (~> 1.1.0)
|
||||||
|
redis-namespace (1.4.1)
|
||||||
|
redis (~> 3.0.4)
|
||||||
|
redis-rack (1.5.0)
|
||||||
|
rack (~> 1.5)
|
||||||
|
redis-store (~> 1.1.0)
|
||||||
|
redis-rails (4.0.0)
|
||||||
|
redis-actionpack (~> 4)
|
||||||
|
redis-activesupport (~> 4)
|
||||||
|
redis-store (~> 1.1.0)
|
||||||
|
redis-store (1.1.4)
|
||||||
|
redis (>= 2.2)
|
||||||
|
ref (1.0.5)
|
||||||
|
request_store (1.0.5)
|
||||||
|
require_all (1.3.2)
|
||||||
|
rest-client (1.6.7)
|
||||||
|
mime-types (>= 1.16)
|
||||||
|
rinku (1.7.3)
|
||||||
|
rouge (1.3.3)
|
||||||
|
rspec (2.14.1)
|
||||||
|
rspec-core (~> 2.14.0)
|
||||||
|
rspec-expectations (~> 2.14.0)
|
||||||
|
rspec-mocks (~> 2.14.0)
|
||||||
|
rspec-core (2.14.7)
|
||||||
|
rspec-expectations (2.14.4)
|
||||||
|
diff-lcs (>= 1.1.3, < 2.0)
|
||||||
|
rspec-mocks (2.14.4)
|
||||||
|
rspec-rails (2.14.0)
|
||||||
|
actionpack (>= 3.0)
|
||||||
|
activesupport (>= 3.0)
|
||||||
|
railties (>= 3.0)
|
||||||
|
rspec-core (~> 2.14.0)
|
||||||
|
rspec-expectations (~> 2.14.0)
|
||||||
|
rspec-mocks (~> 2.14.0)
|
||||||
|
ruby-progressbar (1.2.0)
|
||||||
|
rubyntlm (0.1.1)
|
||||||
|
rubypants (0.2.0)
|
||||||
|
rugged (0.21.0)
|
||||||
|
safe_yaml (0.9.7)
|
||||||
|
sanitize (2.1.0)
|
||||||
|
nokogiri (>= 1.4.4)
|
||||||
|
sass (3.2.19)
|
||||||
|
sass-rails (4.0.3)
|
||||||
|
railties (>= 4.0.0, < 5.0)
|
||||||
|
sass (~> 3.2.0)
|
||||||
|
sprockets (~> 2.8, <= 2.11.0)
|
||||||
|
sprockets-rails (~> 2.0)
|
||||||
|
sdoc (0.3.20)
|
||||||
|
json (>= 1.1.3)
|
||||||
|
rdoc (~> 3.10)
|
||||||
|
seed-fu (2.3.1)
|
||||||
|
activerecord (>= 3.1, < 4.2)
|
||||||
|
activesupport (>= 3.1, < 4.2)
|
||||||
|
select2-rails (3.5.2)
|
||||||
|
thor (~> 0.14)
|
||||||
|
semantic-ui-sass (0.16.1.0)
|
||||||
|
sass (~> 3.2)
|
||||||
|
settingslogic (2.0.9)
|
||||||
|
sexp_processor (4.4.0)
|
||||||
|
shoulda-matchers (2.1.0)
|
||||||
|
activesupport (>= 3.0.0)
|
||||||
|
sidekiq (2.17.0)
|
||||||
|
celluloid (>= 0.15.2)
|
||||||
|
connection_pool (>= 1.0.0)
|
||||||
|
json
|
||||||
|
redis (>= 3.0.4)
|
||||||
|
redis-namespace (>= 1.3.1)
|
||||||
|
simple_oauth (0.1.9)
|
||||||
|
simplecov (0.8.2)
|
||||||
|
docile (~> 1.1.0)
|
||||||
|
multi_json
|
||||||
|
simplecov-html (~> 0.8.0)
|
||||||
|
simplecov-html (0.8.0)
|
||||||
|
sinatra (1.4.4)
|
||||||
|
rack (~> 1.4)
|
||||||
|
rack-protection (~> 1.4)
|
||||||
|
tilt (~> 1.3, >= 1.3.4)
|
||||||
|
six (0.2.0)
|
||||||
|
slack-notifier (0.3.2)
|
||||||
|
slim (2.0.2)
|
||||||
|
temple (~> 0.6.6)
|
||||||
|
tilt (>= 1.3.3, < 2.1)
|
||||||
|
slop (3.4.7)
|
||||||
|
spinach (0.8.7)
|
||||||
|
colorize (= 0.5.8)
|
||||||
|
gherkin-ruby (>= 0.3.1)
|
||||||
|
spinach-rails (0.2.1)
|
||||||
|
capybara (>= 2.0.0)
|
||||||
|
railties (>= 3)
|
||||||
|
spinach (>= 0.4)
|
||||||
|
spring (1.1.1)
|
||||||
|
spring-commands-rspec (1.0.1)
|
||||||
|
spring (>= 0.9.1)
|
||||||
|
spring-commands-spinach (1.0.0)
|
||||||
|
spring (>= 0.9.1)
|
||||||
|
sprockets (2.11.0)
|
||||||
|
hike (~> 1.2)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
rack (~> 1.0)
|
||||||
|
tilt (~> 1.1, != 1.3.0)
|
||||||
|
sprockets-rails (2.1.3)
|
||||||
|
actionpack (>= 3.0)
|
||||||
|
activesupport (>= 3.0)
|
||||||
|
sprockets (~> 2.8)
|
||||||
|
stamp (0.5.0)
|
||||||
|
state_machine (1.2.0)
|
||||||
|
stringex (2.5.1)
|
||||||
|
temple (0.6.7)
|
||||||
|
term-ansicolor (1.2.2)
|
||||||
|
tins (~> 0.8)
|
||||||
|
test_after_commit (0.2.2)
|
||||||
|
therubyracer (0.12.0)
|
||||||
|
libv8 (~> 3.16.14.0)
|
||||||
|
ref
|
||||||
|
thin (1.6.1)
|
||||||
|
daemons (>= 1.0.9)
|
||||||
|
eventmachine (>= 1.0.0)
|
||||||
|
rack (>= 1.0.0)
|
||||||
|
thor (0.19.1)
|
||||||
|
thread_safe (0.3.4)
|
||||||
|
tilt (1.4.1)
|
||||||
|
timers (1.1.0)
|
||||||
|
tinder (1.9.3)
|
||||||
|
eventmachine (~> 1.0)
|
||||||
|
faraday (~> 0.8)
|
||||||
|
faraday_middleware (~> 0.9)
|
||||||
|
hashie (>= 1.0, < 3)
|
||||||
|
json (~> 1.8.0)
|
||||||
|
mime-types (~> 1.19)
|
||||||
|
multi_json (~> 1.7)
|
||||||
|
twitter-stream (~> 0.1)
|
||||||
|
tins (0.13.1)
|
||||||
|
treetop (1.4.15)
|
||||||
|
polyglot
|
||||||
|
polyglot (>= 0.3.1)
|
||||||
|
turbolinks (2.0.0)
|
||||||
|
coffee-rails
|
||||||
|
twitter-stream (0.1.16)
|
||||||
|
eventmachine (>= 0.12.8)
|
||||||
|
http_parser.rb (~> 0.5.1)
|
||||||
|
simple_oauth (~> 0.1.4)
|
||||||
|
tzinfo (1.2.2)
|
||||||
|
thread_safe (~> 0.1)
|
||||||
|
uglifier (2.3.2)
|
||||||
|
execjs (>= 0.3.0)
|
||||||
|
json (>= 1.8.0)
|
||||||
|
underscore-rails (1.4.4)
|
||||||
|
unf (0.1.4)
|
||||||
|
unf_ext
|
||||||
|
unf_ext (0.0.6)
|
||||||
|
unicorn (4.6.3)
|
||||||
|
kgio (~> 2.6)
|
||||||
|
rack
|
||||||
|
raindrops (~> 0.7)
|
||||||
|
unicorn-worker-killer (0.4.2)
|
||||||
|
unicorn (~> 4)
|
||||||
|
version_sorter (1.1.0)
|
||||||
|
virtus (1.0.1)
|
||||||
|
axiom-types (~> 0.0.5)
|
||||||
|
coercible (~> 1.0)
|
||||||
|
descendants_tracker (~> 0.0.1)
|
||||||
|
equalizer (~> 0.0.7)
|
||||||
|
warden (1.2.3)
|
||||||
|
rack (>= 1.0)
|
||||||
|
webmock (1.16.0)
|
||||||
|
addressable (>= 2.2.7)
|
||||||
|
crack (>= 0.3.2)
|
||||||
|
websocket-driver (0.3.3)
|
||||||
|
wikicloth (0.8.1)
|
||||||
|
builder
|
||||||
|
expression_parser
|
||||||
|
rinku
|
||||||
|
xpath (2.0.0)
|
||||||
|
nokogiri (~> 1.3)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
RedCloth
|
||||||
|
ace-rails-ap
|
||||||
|
acts-as-taggable-on
|
||||||
|
annotate (~> 2.6.0.beta2)
|
||||||
|
asciidoctor (= 0.1.4)
|
||||||
|
awesome_print
|
||||||
|
better_errors
|
||||||
|
binding_of_caller
|
||||||
|
bootstrap-sass (~> 3.0)
|
||||||
|
capybara (~> 2.2.1)
|
||||||
|
carrierwave
|
||||||
|
coffee-rails
|
||||||
|
colored
|
||||||
|
coveralls
|
||||||
|
creole (~> 0.3.6)
|
||||||
|
d3_rails (~> 3.1.4)
|
||||||
|
database_cleaner
|
||||||
|
default_value_for (~> 3.0.0)
|
||||||
|
devise (= 3.2.4)
|
||||||
|
devise-async (= 0.9.0)
|
||||||
|
diffy (~> 3.0.3)
|
||||||
|
dropzonejs-rails
|
||||||
|
email_spec
|
||||||
|
enumerize
|
||||||
|
factory_girl_rails
|
||||||
|
ffaker
|
||||||
|
fog (~> 1.14)
|
||||||
|
font-awesome-rails (~> 3.2)
|
||||||
|
foreman
|
||||||
|
gemnasium-gitlab-service (~> 0.2)
|
||||||
|
github-markup
|
||||||
|
gitlab-flowdock-git-hook (~> 0.4.2)
|
||||||
|
gitlab-grack (~> 2.0.0.pre)
|
||||||
|
gitlab-linguist (~> 3.0.0)
|
||||||
|
gitlab_emoji (~> 0.0.1.1)
|
||||||
|
gitlab_git (~> 6.0)
|
||||||
|
gitlab_meta (= 7.0)
|
||||||
|
gitlab_omniauth-ldap (= 1.0.4)
|
||||||
|
gollum-lib (~> 3.0.0)
|
||||||
|
gon (~> 5.0.0)
|
||||||
|
grape (~> 0.6.1)
|
||||||
|
grape-entity (~> 0.4.2)
|
||||||
|
growl
|
||||||
|
guard-rspec
|
||||||
|
guard-spinach
|
||||||
|
haml-rails
|
||||||
|
hipchat (~> 0.14.0)
|
||||||
|
httparty
|
||||||
|
jasmine (= 2.0.2)
|
||||||
|
jquery-atwho-rails (~> 0.3.3)
|
||||||
|
jquery-rails
|
||||||
|
jquery-scrollto-rails
|
||||||
|
jquery-turbolinks
|
||||||
|
jquery-ui-rails
|
||||||
|
kaminari (~> 0.15.1)
|
||||||
|
launchy
|
||||||
|
letter_opener
|
||||||
|
minitest (~> 5.3.0)
|
||||||
|
mysql2
|
||||||
|
nprogress-rails
|
||||||
|
omniauth (~> 1.1.3)
|
||||||
|
omniauth-github
|
||||||
|
omniauth-google-oauth2
|
||||||
|
omniauth-twitter
|
||||||
|
org-ruby
|
||||||
|
pg
|
||||||
|
poltergeist (~> 1.5.1)
|
||||||
|
pry
|
||||||
|
quiet_assets (~> 1.0.1)
|
||||||
|
rack-attack
|
||||||
|
rack-cors
|
||||||
|
rack-mini-profiler
|
||||||
|
rails (~> 4.1.0)
|
||||||
|
rails_autolink (~> 1.1)
|
||||||
|
rails_best_practices
|
||||||
|
raphael-rails (~> 2.1.2)
|
||||||
|
rb-fsevent
|
||||||
|
rb-inotify
|
||||||
|
rdoc (~> 3.6)
|
||||||
|
redcarpet (~> 2.2.2)
|
||||||
|
redis-rails
|
||||||
|
request_store
|
||||||
|
rspec-rails
|
||||||
|
sanitize (~> 2.0)
|
||||||
|
sass-rails (~> 4.0.2)
|
||||||
|
sdoc
|
||||||
|
seed-fu
|
||||||
|
select2-rails
|
||||||
|
semantic-ui-sass (~> 0.16.1.0)
|
||||||
|
settingslogic
|
||||||
|
shoulda-matchers (~> 2.1.0)
|
||||||
|
sidekiq (= 2.17.0)
|
||||||
|
simplecov
|
||||||
|
sinatra
|
||||||
|
six
|
||||||
|
slack-notifier (~> 0.3.2)
|
||||||
|
slim
|
||||||
|
spinach-rails
|
||||||
|
spring (= 1.1.1)
|
||||||
|
spring-commands-rspec (= 1.0.1)
|
||||||
|
spring-commands-spinach (= 1.0.0)
|
||||||
|
stamp
|
||||||
|
state_machine
|
||||||
|
test_after_commit
|
||||||
|
therubyracer
|
||||||
|
thin
|
||||||
|
tinder (~> 1.9.2)
|
||||||
|
turbolinks
|
||||||
|
uglifier
|
||||||
|
underscore-rails (~> 1.4.4)
|
||||||
|
unf
|
||||||
|
unicorn (~> 4.6.3)
|
||||||
|
unicorn-worker-killer
|
||||||
|
version_sorter
|
||||||
|
virtus
|
||||||
|
webmock
|
||||||
|
wikicloth (= 0.8.1)
|
27
Guardfile
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# A sample Guardfile
|
||||||
|
# More info at https://github.com/guard/guard#readme
|
||||||
|
|
||||||
|
guard 'rspec', cmd: "spring rspec", version: 2, all_on_start: false, all_after_pass: false do
|
||||||
|
watch(%r{^spec/.+_spec\.rb$})
|
||||||
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
||||||
|
watch(%r{^lib/api/(.+)\.rb$}) { |m| "spec/requests/api/#{m[1]}_spec.rb" }
|
||||||
|
watch('spec/spec_helper.rb') { "spec" }
|
||||||
|
|
||||||
|
# Rails example
|
||||||
|
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||||
|
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
||||||
|
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
||||||
|
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
||||||
|
watch('config/routes.rb') { "spec/routing" }
|
||||||
|
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
||||||
|
|
||||||
|
# Capybara request specs
|
||||||
|
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
||||||
|
end
|
||||||
|
|
||||||
|
guard 'spinach' do
|
||||||
|
watch(%r|^features/(.*)\.feature|)
|
||||||
|
watch(%r|^features/steps/(.*)([^/]+)\.rb|) do |m|
|
||||||
|
"features/#{m[1]}#{m[2]}.feature"
|
||||||
|
end
|
||||||
|
end
|
19
LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2011-2014 GitLab B.V.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
15
MAINTENANCE.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# GitLab Maintenance Policy
|
||||||
|
|
||||||
|
GitLab is a fast moving and evolving project. We currently don't have the resources to support many releases concurrently. We support exactly one stable release at any given time.
|
||||||
|
|
||||||
|
GitLab follows the [Semantic Versioning](http://semver.org/) for its releases: `(Major).(Minor).(Patch)`.
|
||||||
|
|
||||||
|
- **Major version**: Whenever there is something significant or any backwards incompatible changes are introduced to the public API.
|
||||||
|
- **Minor version**: When new, backwards compatible functionality is introduced to the public API or a minor feature is introduced, or when a set of smaller features is rolled out.
|
||||||
|
- **Patch number**: When backwards compatible bug fixes are introduced that fix incorrect behavior.
|
||||||
|
|
||||||
|
The current stable release will receive security patches and bug fixes (eg. `5.0` -> `5.0.1`). Feature releases will mark the next supported stable release where the minor version is increased numerically by increments of one (eg. `5.0 -> 5.1`).
|
||||||
|
|
||||||
|
We encourage everyone to run the latest stable release to ensure that you can easily upgrade to the most secure and feature rich GitLab experience. In order to make sure you can easily run the most recent stable release, we are working hard to keep the update process simple and reliable.
|
||||||
|
|
||||||
|
More information about the release procedures can be found in the doc/release directory.
|
106
PROCESS.md
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
# GitLab Contributing Process
|
||||||
|
|
||||||
|
## Purpose of describing the contributing process
|
||||||
|
|
||||||
|
Below we describe the contributing process to GitLab for two reasons. So that contributors know what to expect from maintainers (possible responses, friendly treatment, etc.). And so that maintainers know what to expect from contributors (use the latest version, ensure that the issue is addressed, friendly treatment, etc.).
|
||||||
|
|
||||||
|
## Common actions
|
||||||
|
|
||||||
|
### Issue team
|
||||||
|
- Looks for issues without [workflow labels](#how-we-handle-issues) and triages issue
|
||||||
|
- Closes invalid issues with a comment (duplicates, [feature requests](#feature-requests), [fixed in newer version](#issue-fixed-in-newer-version), [issue report for old version](#issue-report-for-old-version), not a problem in GitLab, etc.)
|
||||||
|
- Asks for feedback from issue reporter ([invalid issue reports](#improperly-formatted-issue), [format code](#code-format), etc.)
|
||||||
|
- Monitors all issues for feedback (but especially ones commented on since automatically watching them)
|
||||||
|
- Closes issues with no feedback from the reporter for two weeks
|
||||||
|
|
||||||
|
### Merge marshal
|
||||||
|
|
||||||
|
- Responds to merge requests the issue team mentions them in and monitors for new merge requests
|
||||||
|
- Provides feedback to the merge request submitter to improve the merge request (style, tests, etc.)
|
||||||
|
- Mark merge requests 'ready-for-merge' when they meet the contribution guidelines
|
||||||
|
- Mention developer(s) based on the [list of members and their specialities](https://www.gitlab.com/core-team/)
|
||||||
|
- Closes merge requests with no feedback from the reporter for two weeks
|
||||||
|
|
||||||
|
## Priorities of the issue team
|
||||||
|
|
||||||
|
1. Mentioning people (critical)
|
||||||
|
1. Workflow labels (normal)
|
||||||
|
1. Functional labels (minor)
|
||||||
|
1. Assigning issues (avoid if possible)
|
||||||
|
|
||||||
|
## Mentioning people
|
||||||
|
|
||||||
|
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 [GitLab core team](https://www.gitlab.com/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 timely response. If the involvement of the lead developer is needed the other core team members will mention this person.
|
||||||
|
|
||||||
|
## Workflow labels
|
||||||
|
|
||||||
|
Workflow labels are purposely not very detailed since that would be hard to keep updated as you would need to re-evaluate them after every comment. We optionally use functional labels on demand when want to group related issues to get an overview (for example all issues related to RVM, to tackle them in one go) and to add details to the issue.
|
||||||
|
|
||||||
|
- *Awaiting feedback*: Feedback pending from the reporter
|
||||||
|
- *Awaiting confirmation of fix*: The issue should already be solved in **master** (generally you can avoid this workflow item and just close the issue right away)
|
||||||
|
- *Attached MR*: There is a MR attached and the discussion should happen there
|
||||||
|
- We need to let issues stay in sync with the MR's. We can do this with a "Closing #XXXX" or "Fixes #XXXX" comment in the MR. We can't close the issue when there is a merge request because sometimes a MR is not good and we just close the MR, then the issue must stay.
|
||||||
|
- *Awaiting developer action/feedback*: Issue needs to be fixed or clarified by a developer
|
||||||
|
|
||||||
|
## Functional labels
|
||||||
|
|
||||||
|
These labels describe what development specialities are involved such as: PostgreSQL, UX, LDAP.
|
||||||
|
|
||||||
|
## Assigning issues
|
||||||
|
|
||||||
|
If an issue is complex and needs the attention of a specific person, assignment is a good option but assigning issues might discourage other people from contributing to that issue. We need all the contributions we can get so this should never be discouraged. Also, an assigned person might not have time for a few weeks, so others should feel free to takeover.
|
||||||
|
|
||||||
|
## Label colors
|
||||||
|
|
||||||
|
- Light orange `#fef2c0`: workflow labels for issue team members (awaiting feedback, awaiting confirmation of fix)
|
||||||
|
- Bright orange `#eb6420`: workflow labels for core team members (attached MR, awaiting developer action/feedback)
|
||||||
|
- Light blue `#82C5FF`: functional labels
|
||||||
|
- Green labels `#009800`: issues that can generally be ignored. For example, issues given the following labels normally can be closed immediately:
|
||||||
|
- Feature request (see copy & paste response: [Feature requests](#feature-requests))
|
||||||
|
- Support (see copy & paste response: [Support requests and configuration questions](#support-requests-and-configuration-questions)
|
||||||
|
|
||||||
|
## Be kind
|
||||||
|
|
||||||
|
Be kind to people trying to contribute. Be aware that people may be a non-native English speaker, they might not understand things or they might be very sensitive as to how you word things. Use Emoji to express your feelings (heart, star, smile, etc.). Some good tips about giving feedback to merge requests is in the [Thoughtbot code review guide](https://github.com/thoughtbot/guides/tree/master/code-review).
|
||||||
|
|
||||||
|
## Copy & paste responses
|
||||||
|
|
||||||
|
### Improperly formatted issue
|
||||||
|
|
||||||
|
Thanks for the issue report. Please reformat your issue to conform to the issue tracker guidelines found in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
|
||||||
|
|
||||||
|
### Feature requests
|
||||||
|
|
||||||
|
Thank you for your interest in improving GitLab. We don't use the issue tracker for feature requests. Things that are wrong but are not a regression compared to older versions of GitLab are considered feature requests and not issues. Please use the [feature request forum](http://feedback.gitlab.com/) for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
|
||||||
|
|
||||||
|
### Issue report for old version
|
||||||
|
|
||||||
|
Thanks for the issue report but we only support issues for the latest stable version of GitLab. I'm closing this issue but if you still experience this problem in the latest stable version, please open a new issue (but also reference the old issue(s)). Make sure to also include the necessary debugging information conforming to the issue tracker guidelines found in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
|
||||||
|
|
||||||
|
### Support requests and configuration questions
|
||||||
|
|
||||||
|
Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the #gitlab IRC channel on Freenode or the http://www.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
|
||||||
|
|
||||||
|
### Code format
|
||||||
|
|
||||||
|
Please use ``` to format console output, logs, and code as it's very hard to read otherwise.
|
||||||
|
|
||||||
|
### Issue fixed in newer version
|
||||||
|
|
||||||
|
Thanks for the issue report. This issue has already been fixed in newer versions of GitLab. Due to the size of this project and our limited resources we are only able to support the latest stable release as outlined in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker). In order to get this bug fix and enjoy many new features please \[upgrade\]\(https://github.com/gitlabhq/gitlabhq/tree/master/doc/update). If you still experience issues at that time please open a new issue following our issue tracker guidelines found in the \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
|
||||||
|
|
||||||
|
### Improperly formatted merge request
|
||||||
|
|
||||||
|
Thanks for your interest in improving the GitLab codebase! Please update your merge request according to the \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#pull-request-guidelines).
|
||||||
|
|
||||||
|
### Inactivity close of an issue
|
||||||
|
|
||||||
|
It's been at least 2 weeks (and a new release) since we heard from you. I'm closing this issue but if you still experience this problem, please open a new issue (but also reference the old issue(s)). Make sure to also include the necessary debugging information conforming to the issue tracker guidelines found in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
|
||||||
|
|
||||||
|
### Inactivity close of a merge request
|
||||||
|
|
||||||
|
This merge request has been closed because a request for more information has not been reacted to for more than 2 weeks. If you respond and conform to the merge request guidelines in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#pull-requests) we will reopen this merge request.
|
||||||
|
|
||||||
|
### Accepting merge requests
|
||||||
|
|
||||||
|
Is there a request on [the feature request forum](http://feedback.gitlab.com/forums/176466-general) that is similar to this? If so, can you make a comment with a link to it? Please be aware that new functionality that is not marked [accepting merge/pull requests](http://feedback.gitlab.com/forums/176466-general/status/796455) on the forum might not make it into GitLab. You might be asked to make changes and even after implementing them your feature might still be declined. If you want to reduce the chance of this happening please have a discussion in the forum first.
|
2
Procfile
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"}
|
||||||
|
worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitlab_shell
|
138
README.md
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
# GitLab
|
||||||
|
|
||||||
|
## Open source software to collaborate on code
|
||||||
|
|
||||||
|
![logo](https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/gitlab_logo.png)
|
||||||
|
|
||||||
|
![animated-screenshots](https://gist.github.com/fnkr/2f9badd56bfe0ed04ee7/raw/4f48806fbae97f556c2f78d8c2d299c04500cb0d/compiled.gif)
|
||||||
|
|
||||||
|
- Manage Git repositories with fine grained access controls that keep your code secure
|
||||||
|
- Perform code reviews and enhance collaboration with merge requests
|
||||||
|
- Each project can also have an issue tracker and a wiki
|
||||||
|
- Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises
|
||||||
|
- Completely free and open source (MIT Expat license)
|
||||||
|
- Powered by Ruby on Rails
|
||||||
|
|
||||||
|
## Canonical source
|
||||||
|
|
||||||
|
- The source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/) and there are mirrors to make [contributing](CONTRIBUTING.md) as easy as possible.
|
||||||
|
|
||||||
|
## Code status
|
||||||
|
|
||||||
|
- [![build status](https://ci.gitlab.org/projects/1/status.png?ref=master)](https://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch)
|
||||||
|
|
||||||
|
- [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
|
||||||
|
|
||||||
|
- [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq)
|
||||||
|
|
||||||
|
- [![PullReview stats](https://www.pullreview.com/gitlab/gitlab-org/gitlab-ce/badges/master.svg?)](https://www.pullreview.com/gitlab.gitlab.com/gitlab-org/gitlab-ce/reviews/master)
|
||||||
|
|
||||||
|
## Website
|
||||||
|
|
||||||
|
On [www.gitlab.com](https://www.gitlab.com/) you can find more information about:
|
||||||
|
|
||||||
|
- [Subscriptions](https://www.gitlab.com/subscription/)
|
||||||
|
- [Consultancy](https://www.gitlab.com/consultancy/)
|
||||||
|
- [Community](https://www.gitlab.com/community/)
|
||||||
|
- [Hosted GitLab.com](https://www.gitlab.com/gitlab-com/) use GitLab as a free service
|
||||||
|
- [GitLab Enterprise Edition](https://www.gitlab.com/gitlab-ee/) with additional features aimed at larger organizations.
|
||||||
|
- [GitLab CI](https://www.gitlab.com/gitlab-ci/) a continuous integration (CI) server that is easy to integrate with GitLab.
|
||||||
|
|
||||||
|
## Third-party applications
|
||||||
|
|
||||||
|
Access GitLab from multiple platforms with applications below.
|
||||||
|
These applications are maintained by contributors, GitLab B.V. does not offer support for them.
|
||||||
|
|
||||||
|
- [iPhone app](http://gitlabcontrol.com/)
|
||||||
|
- [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en)
|
||||||
|
- [Chrome app](https://chrome.google.com/webstore/detail/chrome-gitlab-notifier/eageapgbnjicdjjihgclpclilenjbobi)
|
||||||
|
- [Command line client](https://github.com/drewblessing/gitlab-cli)
|
||||||
|
- [Ruby API wrapper](https://github.com/NARKOZ/gitlab)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Ubuntu/Debian/CentOS/RHEL**
|
||||||
|
- ruby 2.0+
|
||||||
|
- git 1.7.10+
|
||||||
|
- redis 2.0+
|
||||||
|
- MySQL or PostgreSQL
|
||||||
|
|
||||||
|
** More details are in the [requirements doc](doc/install/requirements.md).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Please see [the installation page on the GitLab website](https://www.gitlab.com/installation/).
|
||||||
|
|
||||||
|
### New versions
|
||||||
|
|
||||||
|
Since 2011 a minor or major version of GitLab is released on the 22nd of every month. Patch and security releases come out when needed. New features are detailed on the [blog](https://www.gitlab.com/blog/) and in the [changelog](CHANGELOG). For more information about the release process see the release [documentation](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/release). Features that will likely be in the next releases can be found on the [feature request forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
|
||||||
|
|
||||||
|
### Upgrading
|
||||||
|
|
||||||
|
For updating the the Omnibus installation please see the [update documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md). For manual installations there is an [upgrader script](doc/update/upgrader.md) and there are [upgrade guides](doc/update).
|
||||||
|
|
||||||
|
## Run in production mode
|
||||||
|
|
||||||
|
The Installation guide contains instructions on how to download an init script and run it automatically on boot. You can also start the init script manually:
|
||||||
|
|
||||||
|
sudo service gitlab start
|
||||||
|
|
||||||
|
or by directly calling the script:
|
||||||
|
|
||||||
|
sudo /etc/init.d/gitlab start
|
||||||
|
|
||||||
|
Please login with `root` / `5iveL!fe`
|
||||||
|
|
||||||
|
## Install a development environment
|
||||||
|
|
||||||
|
We recommend setting up your development environment with [the cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md#installation). If you do not use the cookbook you might need to copy the example development unicorn configuration file
|
||||||
|
|
||||||
|
cp config/unicorn.rb.example.development config/unicorn.rb
|
||||||
|
|
||||||
|
## Run in development mode
|
||||||
|
|
||||||
|
Start it with [Foreman](https://github.com/ddollar/foreman)
|
||||||
|
|
||||||
|
bundle exec foreman start -p 3000
|
||||||
|
|
||||||
|
or start each component separately:
|
||||||
|
|
||||||
|
bundle exec rails s
|
||||||
|
bin/background_jobs start
|
||||||
|
|
||||||
|
And surf to [localhost:3000](http://localhost:3000/) and login with `root` / `5iveL!fe`.
|
||||||
|
|
||||||
|
## Run the tests
|
||||||
|
|
||||||
|
- Run all tests:
|
||||||
|
|
||||||
|
bundle exec rake test
|
||||||
|
|
||||||
|
- [RSpec](http://rspec.info/) unit and functional tests.
|
||||||
|
|
||||||
|
All RSpec tests: `bundle exec rake spec`
|
||||||
|
|
||||||
|
Single RSpec file: `bundle exec rspec spec/controllers/commit_controller_spec.rb`
|
||||||
|
|
||||||
|
- [Spinach](https://github.com/codegram/spinach) integration tests.
|
||||||
|
|
||||||
|
All Spinach tests: `bundle exec rake spinach`
|
||||||
|
|
||||||
|
Single Spinach test: `bundle exec spinach features/project/issues/milestones.feature`
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
All documentation can be found on [doc.gitlab.com/ce/](http://doc.gitlab.com/ce/).
|
||||||
|
|
||||||
|
## Getting help
|
||||||
|
|
||||||
|
Please see [Getting help for GitLab](https://www.gitlab.com/getting-help/) on our website for the many options to get help.
|
||||||
|
|
||||||
|
## Is it any good?
|
||||||
|
|
||||||
|
[Yes](https://news.ycombinator.com/item?id=3067434)
|
||||||
|
|
||||||
|
## Is it awesome?
|
||||||
|
|
||||||
|
Thanks for [asking this question](https://twitter.com/supersloth/status/489462789384056832) Joshua.
|
||||||
|
[These people](https://twitter.com/gitlabhq/favorites) seem to like it.
|
7
Rakefile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env rake
|
||||||
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
||||||
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||||
|
|
||||||
|
require File.expand_path('../config/application', __FILE__)
|
||||||
|
|
||||||
|
Gitlab::Application.load_tasks
|
1
VERSION
Normal file
|
@ -0,0 +1 @@
|
||||||
|
7.2.1
|
BIN
app/assets/images/authbuttons/github_32.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/assets/images/authbuttons/github_64.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
app/assets/images/authbuttons/google_32.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/assets/images/authbuttons/google_64.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
app/assets/images/authbuttons/twitter_32.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/assets/images/authbuttons/twitter_64.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/assets/images/bg-header.png
Normal file
After Width: | Height: | Size: 210 B |
BIN
app/assets/images/bg_fallback.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
app/assets/images/brand_logo.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
app/assets/images/chosen-sprite.png
Normal file
After Width: | Height: | Size: 396 B |
BIN
app/assets/images/dark-scheme-preview.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
app/assets/images/diff_note_add.png
Normal file
After Width: | Height: | Size: 691 B |
BIN
app/assets/images/favicon.ico
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
app/assets/images/icon-link.png
Normal file
After Width: | Height: | Size: 1,019 B |
BIN
app/assets/images/icon-search.png
Normal file
After Width: | Height: | Size: 331 B |
BIN
app/assets/images/icon_sprite.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
app/assets/images/images.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
app/assets/images/logo-black.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
app/assets/images/logo-white.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
app/assets/images/monokai-scheme-preview.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
app/assets/images/move.png
Normal file
After Width: | Height: | Size: 260 B |
BIN
app/assets/images/no_avatar.png
Normal file
After Width: | Height: | Size: 704 B |
BIN
app/assets/images/no_group_avatar.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
app/assets/images/onion_skin_sprites.gif
Normal file
After Width: | Height: | Size: 548 B |
BIN
app/assets/images/progress_bar.gif
Normal file
After Width: | Height: | Size: 494 B |
BIN
app/assets/images/slider_handles.png
Normal file
After Width: | Height: | Size: 4 KiB |
BIN
app/assets/images/solarized-dark-scheme-preview.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
app/assets/images/swipemode_sprites.gif
Normal file
After Width: | Height: | Size: 505 B |
BIN
app/assets/images/switch_icon.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/assets/images/trans_bg.gif
Normal file
After Width: | Height: | Size: 50 B |
BIN
app/assets/images/white-scheme-preview.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
31
app/assets/javascripts/activities.js.coffee
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
class Activities
|
||||||
|
constructor: ->
|
||||||
|
Pager.init 20, true
|
||||||
|
$(".event_filter_link").bind "click", (event) =>
|
||||||
|
event.preventDefault()
|
||||||
|
@toggleFilter($(event.currentTarget))
|
||||||
|
@reloadActivities()
|
||||||
|
|
||||||
|
reloadActivities: ->
|
||||||
|
$(".content_list").html ''
|
||||||
|
Pager.init 20, true
|
||||||
|
|
||||||
|
|
||||||
|
toggleFilter: (sender) ->
|
||||||
|
sender.parent().toggleClass "inactive"
|
||||||
|
event_filters = $.cookie("event_filter")
|
||||||
|
filter = sender.attr("id").split("_")[0]
|
||||||
|
if event_filters
|
||||||
|
event_filters = event_filters.split(",")
|
||||||
|
else
|
||||||
|
event_filters = new Array()
|
||||||
|
|
||||||
|
index = event_filters.indexOf(filter)
|
||||||
|
if index is -1
|
||||||
|
event_filters.push filter
|
||||||
|
else
|
||||||
|
event_filters.splice index, 1
|
||||||
|
|
||||||
|
$.cookie "event_filter", event_filters.join(","), { path: '/' }
|
||||||
|
|
||||||
|
@Activities = Activities
|
55
app/assets/javascripts/admin.js.coffee
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
class Admin
|
||||||
|
constructor: ->
|
||||||
|
$('input#user_force_random_password').on 'change', (elem) ->
|
||||||
|
elems = $('#user_password, #user_password_confirmation')
|
||||||
|
|
||||||
|
if $(@).attr 'checked'
|
||||||
|
elems.val('').attr 'disabled', true
|
||||||
|
else
|
||||||
|
elems.removeAttr 'disabled'
|
||||||
|
|
||||||
|
$('body').on 'click', '.js-toggle-colors-link', (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
$('.js-toggle-colors-link').hide()
|
||||||
|
$('.js-toggle-colors-container').show()
|
||||||
|
|
||||||
|
$('input#broadcast_message_color').on 'input', ->
|
||||||
|
previewColor = $('input#broadcast_message_color').val()
|
||||||
|
$('div.broadcast-message-preview').css('background-color', previewColor)
|
||||||
|
|
||||||
|
$('input#broadcast_message_font').on 'input', ->
|
||||||
|
previewColor = $('input#broadcast_message_font').val()
|
||||||
|
$('div.broadcast-message-preview').css('color', previewColor)
|
||||||
|
|
||||||
|
$('textarea#broadcast_message_message').on 'input', ->
|
||||||
|
previewMessage = $('textarea#broadcast_message_message').val()
|
||||||
|
$('div.broadcast-message-preview span').text(previewMessage)
|
||||||
|
|
||||||
|
$('.log-tabs a').click (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
$(this).tab('show')
|
||||||
|
|
||||||
|
$('.log-bottom').click (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
visible_log = $(".file-content:visible")
|
||||||
|
visible_log.animate({ scrollTop: visible_log.find('ol').height() }, "fast")
|
||||||
|
|
||||||
|
modal = $('.change-owner-holder')
|
||||||
|
|
||||||
|
$('.change-owner-link').bind "click", (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
$(this).hide()
|
||||||
|
modal.show()
|
||||||
|
|
||||||
|
$('.change-owner-cancel-link').bind "click", (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
modal.hide()
|
||||||
|
$('.change-owner-link').show()
|
||||||
|
|
||||||
|
$('li.users_project').bind 'ajax:success', ->
|
||||||
|
Turbolinks.visit(location.href)
|
||||||
|
|
||||||
|
$('li.users_group').bind 'ajax:success', ->
|
||||||
|
Turbolinks.visit(location.href)
|
||||||
|
|
||||||
|
@Admin = Admin
|
87
app/assets/javascripts/api.js.coffee
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
@Api =
|
||||||
|
users_path: "/api/:version/users.json"
|
||||||
|
user_path: "/api/:version/users/:id.json"
|
||||||
|
notes_path: "/api/:version/projects/:id/notes.json"
|
||||||
|
namespaces_path: "/api/:version/namespaces.json"
|
||||||
|
project_users_path: "/api/:version/projects/:id/users.json"
|
||||||
|
|
||||||
|
# Get 20 (depends on api) recent notes
|
||||||
|
# and sort the ascending from oldest to newest
|
||||||
|
notes: (project_id, callback) ->
|
||||||
|
url = Api.buildUrl(Api.notes_path)
|
||||||
|
url = url.replace(':id', project_id)
|
||||||
|
|
||||||
|
$.ajax(
|
||||||
|
url: url,
|
||||||
|
data:
|
||||||
|
private_token: gon.api_token
|
||||||
|
gfm: true
|
||||||
|
recent: true
|
||||||
|
dataType: "json"
|
||||||
|
).done (notes) ->
|
||||||
|
notes.sort (a, b) ->
|
||||||
|
return a.id - b.id
|
||||||
|
callback(notes)
|
||||||
|
|
||||||
|
user: (user_id, callback) ->
|
||||||
|
url = Api.buildUrl(Api.user_path)
|
||||||
|
url = url.replace(':id', user_id)
|
||||||
|
|
||||||
|
$.ajax(
|
||||||
|
url: url
|
||||||
|
data:
|
||||||
|
private_token: gon.api_token
|
||||||
|
dataType: "json"
|
||||||
|
).done (user) ->
|
||||||
|
callback(user)
|
||||||
|
|
||||||
|
# Return users list. Filtered by query
|
||||||
|
# Only active users retrieved
|
||||||
|
users: (query, callback) ->
|
||||||
|
url = Api.buildUrl(Api.users_path)
|
||||||
|
|
||||||
|
$.ajax(
|
||||||
|
url: url
|
||||||
|
data:
|
||||||
|
private_token: gon.api_token
|
||||||
|
search: query
|
||||||
|
per_page: 20
|
||||||
|
active: true
|
||||||
|
dataType: "json"
|
||||||
|
).done (users) ->
|
||||||
|
callback(users)
|
||||||
|
|
||||||
|
# Return project users list. Filtered by query
|
||||||
|
# Only active users retrieved
|
||||||
|
projectUsers: (project_id, query, callback) ->
|
||||||
|
url = Api.buildUrl(Api.project_users_path)
|
||||||
|
url = url.replace(':id', project_id)
|
||||||
|
|
||||||
|
$.ajax(
|
||||||
|
url: url
|
||||||
|
data:
|
||||||
|
private_token: gon.api_token
|
||||||
|
search: query
|
||||||
|
per_page: 20
|
||||||
|
active: true
|
||||||
|
dataType: "json"
|
||||||
|
).done (users) ->
|
||||||
|
callback(users)
|
||||||
|
|
||||||
|
# Return namespaces list. Filtered by query
|
||||||
|
namespaces: (query, callback) ->
|
||||||
|
url = Api.buildUrl(Api.namespaces_path)
|
||||||
|
|
||||||
|
$.ajax(
|
||||||
|
url: url
|
||||||
|
data:
|
||||||
|
private_token: gon.api_token
|
||||||
|
search: query
|
||||||
|
per_page: 20
|
||||||
|
dataType: "json"
|
||||||
|
).done (namespaces) ->
|
||||||
|
callback(namespaces)
|
||||||
|
|
||||||
|
buildUrl: (url) ->
|
||||||
|
url = gon.relative_url_root + url if gon.relative_url_root?
|
||||||
|
return url.replace(':version', gon.api_version)
|
188
app/assets/javascripts/application.js.coffee
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
# This is a manifest file that'll be compiled into including all the files listed below.
|
||||||
|
# Add new JavaScript/Coffee 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
|
||||||
|
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||||
|
# the compiled file.
|
||||||
|
#
|
||||||
|
#= require jquery
|
||||||
|
#= require jquery.ui.all
|
||||||
|
#= require jquery_ujs
|
||||||
|
#= require jquery.cookie
|
||||||
|
#= require jquery.endless-scroll
|
||||||
|
#= require jquery.highlight
|
||||||
|
#= require jquery.history
|
||||||
|
#= require jquery.waitforimages
|
||||||
|
#= require jquery.atwho
|
||||||
|
#= require jquery.scrollTo
|
||||||
|
#= require jquery.blockUI
|
||||||
|
#= require turbolinks
|
||||||
|
#= require jquery.turbolinks
|
||||||
|
#= require bootstrap
|
||||||
|
#= require select2
|
||||||
|
#= require raphael
|
||||||
|
#= require g.raphael-min
|
||||||
|
#= require g.bar-min
|
||||||
|
#= require branch-graph
|
||||||
|
#= require highlight.pack
|
||||||
|
#= require ace/ace
|
||||||
|
#= require d3
|
||||||
|
#= require underscore
|
||||||
|
#= require nprogress
|
||||||
|
#= require nprogress-turbolinks
|
||||||
|
#= require dropzone
|
||||||
|
#= require semantic-ui/sidebar
|
||||||
|
#= require_tree .
|
||||||
|
|
||||||
|
window.slugify = (text) ->
|
||||||
|
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
|
||||||
|
|
||||||
|
window.ajaxGet = (url) ->
|
||||||
|
$.ajax({type: "GET", url: url, dataType: "script"})
|
||||||
|
|
||||||
|
window.showAndHide = (selector) ->
|
||||||
|
|
||||||
|
window.errorMessage = (message) ->
|
||||||
|
ehtml = $("<p>")
|
||||||
|
ehtml.addClass("error_message")
|
||||||
|
ehtml.html(message)
|
||||||
|
ehtml
|
||||||
|
|
||||||
|
window.split = (val) ->
|
||||||
|
return val.split( /,\s*/ )
|
||||||
|
|
||||||
|
window.extractLast = (term) ->
|
||||||
|
return split( term ).pop()
|
||||||
|
|
||||||
|
window.rstrip = (val) ->
|
||||||
|
return val.replace(/\s+$/, '')
|
||||||
|
|
||||||
|
# Disable button if text field is empty
|
||||||
|
window.disableButtonIfEmptyField = (field_selector, button_selector) ->
|
||||||
|
field = $(field_selector)
|
||||||
|
closest_submit = field.closest('form').find(button_selector)
|
||||||
|
|
||||||
|
closest_submit.disable() if rstrip(field.val()) is ""
|
||||||
|
|
||||||
|
field.on 'input', ->
|
||||||
|
if rstrip($(@).val()) is ""
|
||||||
|
closest_submit.disable()
|
||||||
|
else
|
||||||
|
closest_submit.enable()
|
||||||
|
|
||||||
|
# Disable button if any input field with given selector is empty
|
||||||
|
window.disableButtonIfAnyEmptyField = (form, form_selector, button_selector) ->
|
||||||
|
closest_submit = form.find(button_selector)
|
||||||
|
empty = false
|
||||||
|
form.find('input').filter(form_selector).each ->
|
||||||
|
empty = true if rstrip($(this).val()) is ""
|
||||||
|
|
||||||
|
if empty
|
||||||
|
closest_submit.disable()
|
||||||
|
else
|
||||||
|
closest_submit.enable()
|
||||||
|
|
||||||
|
form.keyup ->
|
||||||
|
empty = false
|
||||||
|
form.find('input').filter(form_selector).each ->
|
||||||
|
empty = true if rstrip($(this).val()) is ""
|
||||||
|
|
||||||
|
if empty
|
||||||
|
closest_submit.disable()
|
||||||
|
else
|
||||||
|
closest_submit.enable()
|
||||||
|
|
||||||
|
window.sanitize = (str) ->
|
||||||
|
return str.replace(/<(?:.|\n)*?>/gm, '')
|
||||||
|
|
||||||
|
window.linkify = (str) ->
|
||||||
|
exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
|
||||||
|
return str.replace(exp,"<a href='$1'>$1</a>")
|
||||||
|
|
||||||
|
window.simpleFormat = (str) ->
|
||||||
|
linkify(sanitize(str).replace(/\n/g, '<br />'))
|
||||||
|
|
||||||
|
window.unbindEvents = ->
|
||||||
|
$(document).unbind('scroll')
|
||||||
|
$(document).off('scroll')
|
||||||
|
|
||||||
|
document.addEventListener("page:fetch", unbindEvents)
|
||||||
|
|
||||||
|
$ ->
|
||||||
|
# Click a .one_click_select field, select the contents
|
||||||
|
$(".one_click_select").on 'click', -> $(@).select()
|
||||||
|
|
||||||
|
$('.remove-row').bind 'ajax:success', ->
|
||||||
|
$(this).closest('li').fadeOut()
|
||||||
|
|
||||||
|
# Initialize select2 selects
|
||||||
|
$('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)
|
||||||
|
|
||||||
|
# Initialize tooltips
|
||||||
|
$('.has_tooltip').tooltip()
|
||||||
|
|
||||||
|
# Bottom tooltip
|
||||||
|
$('.has_bottom_tooltip').tooltip(placement: 'bottom')
|
||||||
|
|
||||||
|
# Form submitter
|
||||||
|
$('.trigger-submit').on 'change', ->
|
||||||
|
$(@).parents('form').submit()
|
||||||
|
|
||||||
|
$("abbr.timeago").timeago()
|
||||||
|
$('.js-timeago').timeago()
|
||||||
|
|
||||||
|
# Flash
|
||||||
|
if (flash = $(".flash-container")).length > 0
|
||||||
|
flash.click -> $(@).fadeOut()
|
||||||
|
flash.show()
|
||||||
|
setTimeout (-> flash.fadeOut()), 5000
|
||||||
|
|
||||||
|
# Disable form buttons while a form is submitting
|
||||||
|
$('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
|
||||||
|
buttons = $('[type="submit"]', @)
|
||||||
|
|
||||||
|
switch e.type
|
||||||
|
when 'ajax:beforeSend', 'submit'
|
||||||
|
buttons.disable()
|
||||||
|
else
|
||||||
|
buttons.enable()
|
||||||
|
|
||||||
|
# Show/Hide the profile menu when hovering the account box
|
||||||
|
$('.account-box').hover -> $(@).toggleClass('hover')
|
||||||
|
|
||||||
|
# Focus search field by pressing 's' key
|
||||||
|
$(document).keypress (e) ->
|
||||||
|
# Don't do anything if typing in an input
|
||||||
|
return if $(e.target).is(":input")
|
||||||
|
|
||||||
|
switch e.which
|
||||||
|
when 115
|
||||||
|
$("#search").focus()
|
||||||
|
e.preventDefault()
|
||||||
|
when 63
|
||||||
|
new Shortcuts()
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
|
||||||
|
# Commit show suppressed diff
|
||||||
|
$(".diff-content").on "click", ".supp_diff_link", ->
|
||||||
|
$(@).next('table').show()
|
||||||
|
$(@).remove()
|
||||||
|
|
||||||
|
# Show/hide comments on diff
|
||||||
|
$("body").on "click", ".js-toggle-diff-comments", (e) ->
|
||||||
|
$(@).find('i').
|
||||||
|
toggleClass('icon-chevron-down').
|
||||||
|
toggleClass('icon-chevron-up')
|
||||||
|
$(@).closest(".diff-file").find(".notes_holder").toggle()
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
(($) ->
|
||||||
|
# Disable an element and add the 'disabled' Bootstrap class
|
||||||
|
$.fn.extend disable: ->
|
||||||
|
$(@).attr('disabled', 'disabled').addClass('disabled')
|
||||||
|
|
||||||
|
# Enable an element and remove the 'disabled' Bootstrap class
|
||||||
|
$.fn.extend enable: ->
|
||||||
|
$(@).removeAttr('disabled').removeClass('disabled')
|
||||||
|
|
||||||
|
)(jQuery)
|
15
app/assets/javascripts/behaviors/details_behavior.coffee
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
$ ->
|
||||||
|
$("body").on "click", ".js-details-target", ->
|
||||||
|
container = $(@).closest(".js-details-container")
|
||||||
|
container.toggleClass("open")
|
||||||
|
|
||||||
|
# Show details content. Hides link after click.
|
||||||
|
#
|
||||||
|
# %div
|
||||||
|
# %a.js-details-expand
|
||||||
|
# %div.js-details-content
|
||||||
|
#
|
||||||
|
$("body").on "click", ".js-details-expand", (e) ->
|
||||||
|
$(@).next('.js-details-content').removeClass("hide")
|
||||||
|
$(@).hide()
|
||||||
|
e.preventDefault()
|
14
app/assets/javascripts/behaviors/toggler_behavior.coffee
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
$ ->
|
||||||
|
# Toggle button. Show/hide content inside parent container.
|
||||||
|
# Button does not change visibility. If button has icon - it changes chevron style.
|
||||||
|
#
|
||||||
|
# %div.js-toggle-container
|
||||||
|
# %a.js-toggle-button
|
||||||
|
# %div.js-toggle-content
|
||||||
|
#
|
||||||
|
$("body").on "click", ".js-toggle-button", (e) ->
|
||||||
|
$(@).find('i').
|
||||||
|
toggleClass('icon-chevron-down').
|
||||||
|
toggleClass('icon-chevron-up')
|
||||||
|
$(@).closest(".js-toggle-container").find(".js-toggle-content").toggle()
|
||||||
|
e.preventDefault()
|
76
app/assets/javascripts/blob.js.coffee
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
class BlobView
|
||||||
|
constructor: ->
|
||||||
|
# handle multi-line select
|
||||||
|
handleMultiSelect = (e) ->
|
||||||
|
[ first_line, last_line ] = parseSelectedLines()
|
||||||
|
[ line_number ] = parseSelectedLines($(this).attr("id"))
|
||||||
|
hash = "L#{line_number}"
|
||||||
|
|
||||||
|
if e.shiftKey and not isNaN(first_line) and not isNaN(line_number)
|
||||||
|
if line_number < first_line
|
||||||
|
last_line = first_line
|
||||||
|
first_line = line_number
|
||||||
|
else
|
||||||
|
last_line = line_number
|
||||||
|
|
||||||
|
hash = if first_line == last_line then "L#{first_line}" else "L#{first_line}-#{last_line}"
|
||||||
|
|
||||||
|
setHash(hash)
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
# See if there are lines selected
|
||||||
|
# "#L12" and "#L34-56" supported
|
||||||
|
highlightBlobLines = (e) ->
|
||||||
|
[ first_line, last_line ] = parseSelectedLines()
|
||||||
|
|
||||||
|
unless isNaN first_line
|
||||||
|
$("#tree-content-holder .highlight .line").removeClass("hll")
|
||||||
|
$("#LC#{line}").addClass("hll") for line in [first_line..last_line]
|
||||||
|
$.scrollTo("#L#{first_line}") unless e?
|
||||||
|
|
||||||
|
# parse selected lines from hash
|
||||||
|
# always return first and last line (initialized to NaN)
|
||||||
|
parseSelectedLines = (str) ->
|
||||||
|
first_line = NaN
|
||||||
|
last_line = NaN
|
||||||
|
hash = str || window.location.hash
|
||||||
|
|
||||||
|
if hash isnt ""
|
||||||
|
matches = hash.match(/\#?L(\d+)(\-(\d+))?/)
|
||||||
|
first_line = parseInt(matches?[1])
|
||||||
|
last_line = parseInt(matches?[3])
|
||||||
|
last_line = first_line if isNaN(last_line)
|
||||||
|
|
||||||
|
[ first_line, last_line ]
|
||||||
|
|
||||||
|
setHash = (hash) ->
|
||||||
|
hash = hash.replace(/^\#/, "")
|
||||||
|
nodes = $("#" + hash)
|
||||||
|
# if any nodes are using this id, they must be temporarily changed
|
||||||
|
# also, add a temporary div at the top of the screen to prevent scrolling
|
||||||
|
if nodes.length > 0
|
||||||
|
scroll_top = $(document).scrollTop()
|
||||||
|
nodes.attr("id", "")
|
||||||
|
tmp = $("<div></div>")
|
||||||
|
.css({ position: "absolute", visibility: "hidden", top: scroll_top + "px" })
|
||||||
|
.attr("id", hash)
|
||||||
|
.appendTo(document.body)
|
||||||
|
|
||||||
|
window.location.hash = hash
|
||||||
|
|
||||||
|
# restore the nodes
|
||||||
|
if nodes.length > 0
|
||||||
|
tmp.remove()
|
||||||
|
nodes.attr("id", hash)
|
||||||
|
|
||||||
|
# initialize multi-line select
|
||||||
|
$("#tree-content-holder .line-numbers a[id^=L]").on("click", handleMultiSelect)
|
||||||
|
|
||||||
|
# Highlight the correct lines on load
|
||||||
|
highlightBlobLines()
|
||||||
|
|
||||||
|
# Highlight the correct lines when the hash part of the URL changes
|
||||||
|
$(window).on("hashchange", highlightBlobLines)
|
||||||
|
|
||||||
|
|
||||||
|
@BlobView = BlobView
|
329
app/assets/javascripts/branch-graph.js.coffee
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
class BranchGraph
|
||||||
|
constructor: (@element, @options) ->
|
||||||
|
@preparedCommits = {}
|
||||||
|
@mtime = 0
|
||||||
|
@mspace = 0
|
||||||
|
@parents = {}
|
||||||
|
@colors = ["#000"]
|
||||||
|
@offsetX = 150
|
||||||
|
@offsetY = 20
|
||||||
|
@unitTime = 30
|
||||||
|
@unitSpace = 10
|
||||||
|
@prev_start = -1
|
||||||
|
@load()
|
||||||
|
|
||||||
|
load: ->
|
||||||
|
$.ajax
|
||||||
|
url: @options.url
|
||||||
|
method: "get"
|
||||||
|
dataType: "json"
|
||||||
|
success: $.proxy((data) ->
|
||||||
|
$(".loading", @element).hide()
|
||||||
|
@prepareData data.days, data.commits
|
||||||
|
@buildGraph()
|
||||||
|
, this)
|
||||||
|
|
||||||
|
prepareData: (@days, @commits) ->
|
||||||
|
@collectParents()
|
||||||
|
@graphHeight = $(@element).height()
|
||||||
|
@graphWidth = $(@element).width()
|
||||||
|
ch = Math.max(@graphHeight, @offsetY + @unitTime * @mtime + 150)
|
||||||
|
cw = Math.max(@graphWidth, @offsetX + @unitSpace * @mspace + 300)
|
||||||
|
@r = Raphael(@element.get(0), cw, ch)
|
||||||
|
@top = @r.set()
|
||||||
|
@barHeight = Math.max(@graphHeight, @unitTime * @days.length + 320)
|
||||||
|
|
||||||
|
for c in @commits
|
||||||
|
c.isParent = true if c.id of @parents
|
||||||
|
@preparedCommits[c.id] = c
|
||||||
|
@markCommit(c)
|
||||||
|
|
||||||
|
@collectColors()
|
||||||
|
|
||||||
|
collectParents: ->
|
||||||
|
for c in @commits
|
||||||
|
@mtime = Math.max(@mtime, c.time)
|
||||||
|
@mspace = Math.max(@mspace, c.space)
|
||||||
|
for p in c.parents
|
||||||
|
@parents[p[0]] = true
|
||||||
|
@mspace = Math.max(@mspace, p[1])
|
||||||
|
|
||||||
|
collectColors: ->
|
||||||
|
k = 0
|
||||||
|
while k < @mspace
|
||||||
|
@colors.push Raphael.getColor(.8)
|
||||||
|
# Skipping a few colors in the spectrum to get more contrast between colors
|
||||||
|
Raphael.getColor()
|
||||||
|
Raphael.getColor()
|
||||||
|
k++
|
||||||
|
|
||||||
|
buildGraph: ->
|
||||||
|
r = @r
|
||||||
|
cuday = 0
|
||||||
|
cumonth = ""
|
||||||
|
|
||||||
|
r.rect(0, 0, 40, @barHeight).attr fill: "#222"
|
||||||
|
r.rect(40, 0, 30, @barHeight).attr fill: "#444"
|
||||||
|
|
||||||
|
for day, mm in @days
|
||||||
|
if cuday isnt day[0]
|
||||||
|
# Dates
|
||||||
|
r.text(55, @offsetY + @unitTime * mm, day[0])
|
||||||
|
.attr(
|
||||||
|
font: "12px Monaco, monospace"
|
||||||
|
fill: "#BBB"
|
||||||
|
)
|
||||||
|
cuday = day[0]
|
||||||
|
|
||||||
|
if cumonth isnt day[1]
|
||||||
|
# Months
|
||||||
|
r.text(20, @offsetY + @unitTime * mm, day[1])
|
||||||
|
.attr(
|
||||||
|
font: "12px Monaco, monospace"
|
||||||
|
fill: "#EEE"
|
||||||
|
)
|
||||||
|
cumonth = day[1]
|
||||||
|
|
||||||
|
@renderPartialGraph()
|
||||||
|
|
||||||
|
@bindEvents()
|
||||||
|
|
||||||
|
renderPartialGraph: ->
|
||||||
|
start = Math.floor((@element.scrollTop() - @offsetY) / @unitTime) - 10
|
||||||
|
start = 0 if start < 0
|
||||||
|
end = start + 40
|
||||||
|
end = @commits.length if @commits.length < end
|
||||||
|
|
||||||
|
if @prev_start == -1 or Math.abs(@prev_start - start) > 10
|
||||||
|
i = start
|
||||||
|
|
||||||
|
@prev_start = start
|
||||||
|
|
||||||
|
while i < end
|
||||||
|
commit = @commits[i]
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if commit.hasDrawn isnt true
|
||||||
|
x = @offsetX + @unitSpace * (@mspace - commit.space)
|
||||||
|
y = @offsetY + @unitTime * commit.time
|
||||||
|
|
||||||
|
@drawDot(x, y, commit)
|
||||||
|
|
||||||
|
@drawLines(x, y, commit)
|
||||||
|
|
||||||
|
@appendLabel(x, y, commit)
|
||||||
|
|
||||||
|
@appendAnchor(x, y, commit)
|
||||||
|
|
||||||
|
commit.hasDrawn = true
|
||||||
|
|
||||||
|
@top.toFront()
|
||||||
|
|
||||||
|
bindEvents: ->
|
||||||
|
drag = {}
|
||||||
|
element = @element
|
||||||
|
|
||||||
|
$(element).scroll (event) =>
|
||||||
|
@renderPartialGraph()
|
||||||
|
|
||||||
|
$(window).on
|
||||||
|
keydown: (event) =>
|
||||||
|
# left
|
||||||
|
element.scrollLeft element.scrollLeft() - 50 if event.keyCode is 37
|
||||||
|
# top
|
||||||
|
element.scrollTop element.scrollTop() - 50 if event.keyCode is 38
|
||||||
|
# right
|
||||||
|
element.scrollLeft element.scrollLeft() + 50 if event.keyCode is 39
|
||||||
|
# bottom
|
||||||
|
element.scrollTop element.scrollTop() + 50 if event.keyCode is 40
|
||||||
|
@renderPartialGraph()
|
||||||
|
|
||||||
|
appendLabel: (x, y, commit) ->
|
||||||
|
return unless commit.refs
|
||||||
|
|
||||||
|
r = @r
|
||||||
|
shortrefs = commit.refs
|
||||||
|
# Truncate if longer than 15 chars
|
||||||
|
shortrefs = shortrefs.substr(0, 15) + "…" if shortrefs.length > 17
|
||||||
|
text = r.text(x + 4, y, shortrefs).attr(
|
||||||
|
"text-anchor": "start"
|
||||||
|
font: "10px Monaco, monospace"
|
||||||
|
fill: "#FFF"
|
||||||
|
title: commit.refs
|
||||||
|
)
|
||||||
|
textbox = text.getBBox()
|
||||||
|
# Create rectangle based on the size of the textbox
|
||||||
|
rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr(
|
||||||
|
fill: "#000"
|
||||||
|
"fill-opacity": .5
|
||||||
|
stroke: "none"
|
||||||
|
)
|
||||||
|
triangle = r.path(["M", x - 5, y, "L", x - 15, y - 4, "L", x - 15, y + 4, "Z"]).attr(
|
||||||
|
fill: "#000"
|
||||||
|
"fill-opacity": .5
|
||||||
|
stroke: "none"
|
||||||
|
)
|
||||||
|
|
||||||
|
label = r.set(rect, text)
|
||||||
|
label.transform(["t", -rect.getBBox().width - 15, 0])
|
||||||
|
|
||||||
|
# Set text to front
|
||||||
|
text.toFront()
|
||||||
|
|
||||||
|
appendAnchor: (x, y, commit) ->
|
||||||
|
r = @r
|
||||||
|
top = @top
|
||||||
|
options = @options
|
||||||
|
anchor = r.circle(x, y, 10).attr(
|
||||||
|
fill: "#000"
|
||||||
|
opacity: 0
|
||||||
|
cursor: "pointer"
|
||||||
|
).click(->
|
||||||
|
window.open options.commit_url.replace("%s", commit.id), "_blank"
|
||||||
|
).hover(->
|
||||||
|
@tooltip = r.commitTooltip(x + 5, y, commit)
|
||||||
|
top.push @tooltip.insertBefore(this)
|
||||||
|
, ->
|
||||||
|
@tooltip and @tooltip.remove() and delete @tooltip
|
||||||
|
)
|
||||||
|
top.push anchor
|
||||||
|
|
||||||
|
drawDot: (x, y, commit) ->
|
||||||
|
r = @r
|
||||||
|
r.circle(x, y, 3).attr(
|
||||||
|
fill: @colors[commit.space]
|
||||||
|
stroke: "none"
|
||||||
|
)
|
||||||
|
|
||||||
|
avatar_box_x = @offsetX + @unitSpace * @mspace + 10
|
||||||
|
avatar_box_y = y - 10
|
||||||
|
r.rect(avatar_box_x, avatar_box_y, 20, 20).attr(
|
||||||
|
stroke: @colors[commit.space]
|
||||||
|
"stroke-width": 2
|
||||||
|
)
|
||||||
|
r.image(gon.relative_url_root + commit.author.icon, avatar_box_x, avatar_box_y, 20, 20)
|
||||||
|
r.text(@offsetX + @unitSpace * @mspace + 35, y, commit.message.split("\n")[0]).attr(
|
||||||
|
"text-anchor": "start"
|
||||||
|
font: "14px Monaco, monospace"
|
||||||
|
)
|
||||||
|
|
||||||
|
drawLines: (x, y, commit) ->
|
||||||
|
r = @r
|
||||||
|
for parent, i in commit.parents
|
||||||
|
parentCommit = @preparedCommits[parent[0]]
|
||||||
|
parentY = @offsetY + @unitTime * parentCommit.time
|
||||||
|
parentX1 = @offsetX + @unitSpace * (@mspace - parentCommit.space)
|
||||||
|
parentX2 = @offsetX + @unitSpace * (@mspace - parent[1])
|
||||||
|
|
||||||
|
# Set line color
|
||||||
|
if parentCommit.space <= commit.space
|
||||||
|
color = @colors[commit.space]
|
||||||
|
|
||||||
|
else
|
||||||
|
color = @colors[parentCommit.space]
|
||||||
|
|
||||||
|
# Build line shape
|
||||||
|
if parent[1] is commit.space
|
||||||
|
offset = [0, 5]
|
||||||
|
arrow = "l-2,5,4,0,-2,-5,0,5"
|
||||||
|
|
||||||
|
else if parent[1] < commit.space
|
||||||
|
offset = [3, 3]
|
||||||
|
arrow = "l5,0,-2,4,-3,-4,4,2"
|
||||||
|
|
||||||
|
else
|
||||||
|
offset = [-3, 3]
|
||||||
|
arrow = "l-5,0,2,4,3,-4,-4,2"
|
||||||
|
|
||||||
|
# Start point
|
||||||
|
route = ["M", x + offset[0], y + offset[1]]
|
||||||
|
|
||||||
|
# Add arrow if not first parent
|
||||||
|
if i > 0
|
||||||
|
route.push(arrow)
|
||||||
|
|
||||||
|
# Circumvent if overlap
|
||||||
|
if commit.space isnt parentCommit.space or commit.space isnt parent[1]
|
||||||
|
route.push(
|
||||||
|
"L", parentX2, y + 10,
|
||||||
|
"L", parentX2, parentY - 5,
|
||||||
|
)
|
||||||
|
|
||||||
|
# End point
|
||||||
|
route.push("L", parentX1, parentY)
|
||||||
|
|
||||||
|
r
|
||||||
|
.path(route)
|
||||||
|
.attr(
|
||||||
|
stroke: color
|
||||||
|
"stroke-width": 2)
|
||||||
|
|
||||||
|
markCommit: (commit) ->
|
||||||
|
if commit.id is @options.commit_id
|
||||||
|
r = @r
|
||||||
|
x = @offsetX + @unitSpace * (@mspace - commit.space)
|
||||||
|
y = @offsetY + @unitTime * commit.time
|
||||||
|
r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr(
|
||||||
|
fill: "#000"
|
||||||
|
"fill-opacity": .5
|
||||||
|
stroke: "none"
|
||||||
|
)
|
||||||
|
# Displayed in the center
|
||||||
|
@element.scrollTop(y - @graphHeight / 2)
|
||||||
|
|
||||||
|
Raphael::commitTooltip = (x, y, commit) ->
|
||||||
|
boxWidth = 300
|
||||||
|
boxHeight = 200
|
||||||
|
icon = @image(gon.relative_url_root + commit.author.icon, x, y, 20, 20)
|
||||||
|
nameText = @text(x + 25, y + 10, commit.author.name)
|
||||||
|
idText = @text(x, y + 35, commit.id)
|
||||||
|
messageText = @text(x, y + 50, commit.message)
|
||||||
|
textSet = @set(icon, nameText, idText, messageText).attr(
|
||||||
|
"text-anchor": "start"
|
||||||
|
font: "12px Monaco, monospace"
|
||||||
|
)
|
||||||
|
nameText.attr(
|
||||||
|
font: "14px Arial"
|
||||||
|
"font-weight": "bold"
|
||||||
|
)
|
||||||
|
|
||||||
|
idText.attr fill: "#AAA"
|
||||||
|
@textWrap messageText, boxWidth - 50
|
||||||
|
rect = @rect(x - 10, y - 10, boxWidth, 100, 4).attr(
|
||||||
|
fill: "#FFF"
|
||||||
|
stroke: "#000"
|
||||||
|
"stroke-linecap": "round"
|
||||||
|
"stroke-width": 2
|
||||||
|
)
|
||||||
|
tooltip = @set(rect, textSet)
|
||||||
|
rect.attr(
|
||||||
|
height: tooltip.getBBox().height + 10
|
||||||
|
width: tooltip.getBBox().width + 10
|
||||||
|
)
|
||||||
|
|
||||||
|
tooltip.transform ["t", 20, 20]
|
||||||
|
tooltip
|
||||||
|
|
||||||
|
Raphael::textWrap = (t, width) ->
|
||||||
|
content = t.attr("text")
|
||||||
|
abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
t.attr text: abc
|
||||||
|
letterWidth = t.getBBox().width / abc.length
|
||||||
|
t.attr text: content
|
||||||
|
words = content.split(" ")
|
||||||
|
x = 0
|
||||||
|
s = []
|
||||||
|
|
||||||
|
for word in words
|
||||||
|
if x + (word.length * letterWidth) > width
|
||||||
|
s.push "\n"
|
||||||
|
x = 0
|
||||||
|
x += word.length * letterWidth
|
||||||
|
s.push word + " "
|
||||||
|
|
||||||
|
t.attr text: s.join("")
|
||||||
|
b = t.getBBox()
|
||||||
|
h = Math.abs(b.y2) - Math.abs(b.y) + 1
|
||||||
|
t.attr y: b.y + h
|
||||||
|
|
||||||
|
@BranchGraph = BranchGraph
|
21
app/assets/javascripts/chart.js.coffee
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
@Chart =
|
||||||
|
labels: []
|
||||||
|
values: []
|
||||||
|
|
||||||
|
init: (labels, values, title) ->
|
||||||
|
r = Raphael('activity-chart')
|
||||||
|
|
||||||
|
fin = ->
|
||||||
|
@flag = r.popup(@bar.x, @bar.y, @bar.value or "0").insertBefore(this)
|
||||||
|
|
||||||
|
fout = ->
|
||||||
|
@flag.animate
|
||||||
|
opacity: 0, 300, -> @remove()
|
||||||
|
|
||||||
|
r.text(160, 10, title).attr font: "13px sans-serif"
|
||||||
|
r.barchart(
|
||||||
|
10, 20, 560, 200,
|
||||||
|
[values],
|
||||||
|
{colors:["#456"]}
|
||||||
|
).label(labels, true)
|
||||||
|
.hover(fin, fout)
|
6
app/assets/javascripts/commit.js.coffee
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class Commit
|
||||||
|
constructor: ->
|
||||||
|
$('.files .diff-file').each ->
|
||||||
|
new CommitFile(this)
|
||||||
|
|
||||||
|
@Commit = Commit
|
7
app/assets/javascripts/commit/file.js.coffee
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class CommitFile
|
||||||
|
|
||||||
|
constructor: (file) ->
|
||||||
|
if $('.image', file).length
|
||||||
|
new ImageFile(file)
|
||||||
|
|
||||||
|
@CommitFile = CommitFile
|
128
app/assets/javascripts/commit/image-file.js.coffee
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
class ImageFile
|
||||||
|
|
||||||
|
# Width where images must fits in, for 2-up this gets divided by 2
|
||||||
|
@availWidth = 900
|
||||||
|
@viewModes = ['two-up', 'swipe']
|
||||||
|
|
||||||
|
constructor: (@file) ->
|
||||||
|
# Determine if old and new file has same dimensions, if not show 'two-up' view
|
||||||
|
this.requestImageInfo $('.two-up.view .frame.deleted img', @file), (deletedWidth, deletedHeight) =>
|
||||||
|
this.requestImageInfo $('.two-up.view .frame.added img', @file), (width, height) =>
|
||||||
|
if width == deletedWidth && height == deletedHeight
|
||||||
|
this.initViewModes()
|
||||||
|
else
|
||||||
|
this.initView('two-up')
|
||||||
|
|
||||||
|
initViewModes: ->
|
||||||
|
viewMode = ImageFile.viewModes[0]
|
||||||
|
|
||||||
|
$('.view-modes', @file).removeClass 'hide'
|
||||||
|
$('.view-modes-menu', @file).on 'click', 'li', (event) =>
|
||||||
|
unless $(event.currentTarget).hasClass('active')
|
||||||
|
this.activateViewMode(event.currentTarget.className)
|
||||||
|
|
||||||
|
this.activateViewMode(viewMode)
|
||||||
|
|
||||||
|
activateViewMode: (viewMode) ->
|
||||||
|
$('.view-modes-menu li', @file)
|
||||||
|
.removeClass('active')
|
||||||
|
.filter(".#{viewMode}").addClass 'active'
|
||||||
|
$(".view:visible:not(.#{viewMode})", @file).fadeOut 200, =>
|
||||||
|
$(".view.#{viewMode}", @file).fadeIn(200)
|
||||||
|
this.initView viewMode
|
||||||
|
|
||||||
|
initView: (viewMode) ->
|
||||||
|
this.views[viewMode].call(this)
|
||||||
|
|
||||||
|
prepareFrames = (view) ->
|
||||||
|
maxWidth = 0
|
||||||
|
maxHeight = 0
|
||||||
|
$('.frame', view).each (index, frame) =>
|
||||||
|
width = $(frame).width()
|
||||||
|
height = $(frame).height()
|
||||||
|
maxWidth = if width > maxWidth then width else maxWidth
|
||||||
|
maxHeight = if height > maxHeight then height else maxHeight
|
||||||
|
.css
|
||||||
|
width: maxWidth
|
||||||
|
height: maxHeight
|
||||||
|
|
||||||
|
[maxWidth, maxHeight]
|
||||||
|
|
||||||
|
views:
|
||||||
|
'two-up': ->
|
||||||
|
$('.two-up.view .wrap', @file).each (index, wrap) =>
|
||||||
|
$('img', wrap).each ->
|
||||||
|
currentWidth = $(this).width()
|
||||||
|
if currentWidth > ImageFile.availWidth / 2
|
||||||
|
$(this).width ImageFile.availWidth / 2
|
||||||
|
|
||||||
|
this.requestImageInfo $('img', wrap), (width, height) ->
|
||||||
|
$('.image-info .meta-width', wrap).text "#{width}px"
|
||||||
|
$('.image-info .meta-height', wrap).text "#{height}px"
|
||||||
|
$('.image-info', wrap).removeClass('hide')
|
||||||
|
|
||||||
|
'swipe': ->
|
||||||
|
maxWidth = 0
|
||||||
|
maxHeight = 0
|
||||||
|
|
||||||
|
$('.swipe.view', @file).each (index, view) =>
|
||||||
|
|
||||||
|
[maxWidth, maxHeight] = prepareFrames(view)
|
||||||
|
|
||||||
|
$('.swipe-frame', view).css
|
||||||
|
width: maxWidth + 16
|
||||||
|
height: maxHeight + 28
|
||||||
|
|
||||||
|
$('.swipe-wrap', view).css
|
||||||
|
width: maxWidth + 1
|
||||||
|
height: maxHeight + 2
|
||||||
|
|
||||||
|
$('.swipe-bar', view).css
|
||||||
|
left: 0
|
||||||
|
.draggable
|
||||||
|
axis: 'x'
|
||||||
|
containment: 'parent'
|
||||||
|
drag: (event) ->
|
||||||
|
$('.swipe-wrap', view).width (maxWidth + 1) - $(this).position().left
|
||||||
|
stop: (event) ->
|
||||||
|
$('.swipe-wrap', view).width (maxWidth + 1) - $(this).position().left
|
||||||
|
|
||||||
|
'onion-skin': ->
|
||||||
|
maxWidth = 0
|
||||||
|
maxHeight = 0
|
||||||
|
|
||||||
|
dragTrackWidth = $('.drag-track', @file).width() - $('.dragger', @file).width()
|
||||||
|
|
||||||
|
$('.onion-skin.view', @file).each (index, view) =>
|
||||||
|
|
||||||
|
[maxWidth, maxHeight] = prepareFrames(view)
|
||||||
|
|
||||||
|
$('.onion-skin-frame', view).css
|
||||||
|
width: maxWidth + 16
|
||||||
|
height: maxHeight + 28
|
||||||
|
|
||||||
|
$('.swipe-wrap', view).css
|
||||||
|
width: maxWidth + 1
|
||||||
|
height: maxHeight + 2
|
||||||
|
|
||||||
|
$('.dragger', view).css
|
||||||
|
left: dragTrackWidth
|
||||||
|
.draggable
|
||||||
|
axis: 'x'
|
||||||
|
containment: 'parent'
|
||||||
|
drag: (event) ->
|
||||||
|
$('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth)
|
||||||
|
stop: (event) ->
|
||||||
|
$('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
requestImageInfo: (img, callback) ->
|
||||||
|
domImg = img.get(0)
|
||||||
|
if domImg.complete
|
||||||
|
callback.call(this, domImg.naturalWidth, domImg.naturalHeight)
|
||||||
|
else
|
||||||
|
img.on 'load', =>
|
||||||
|
callback.call(this, domImg.naturalWidth, domImg.naturalHeight)
|
||||||
|
|
||||||
|
@ImageFile = ImageFile
|
57
app/assets/javascripts/commits.js.coffee
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
class CommitsList
|
||||||
|
@data =
|
||||||
|
ref: null
|
||||||
|
limit: 0
|
||||||
|
offset: 0
|
||||||
|
@disable = false
|
||||||
|
|
||||||
|
@showProgress: ->
|
||||||
|
$('.loading').show()
|
||||||
|
|
||||||
|
@hideProgress: ->
|
||||||
|
$('.loading').hide()
|
||||||
|
|
||||||
|
@init: (ref, limit) ->
|
||||||
|
$("body").on "click", ".day-commits-table li.commit", (event) ->
|
||||||
|
if event.target.nodeName != "A"
|
||||||
|
location.href = $(this).attr("url")
|
||||||
|
e.stopPropagation()
|
||||||
|
return false
|
||||||
|
|
||||||
|
@data.ref = ref
|
||||||
|
@data.limit = limit
|
||||||
|
@data.offset = limit
|
||||||
|
|
||||||
|
this.initLoadMore()
|
||||||
|
this.showProgress()
|
||||||
|
|
||||||
|
@getOld: ->
|
||||||
|
this.showProgress()
|
||||||
|
$.ajax
|
||||||
|
type: "GET"
|
||||||
|
url: location.href
|
||||||
|
data: @data
|
||||||
|
complete: this.hideProgress
|
||||||
|
success: (data) ->
|
||||||
|
CommitsList.append(data.count, data.html)
|
||||||
|
dataType: "json"
|
||||||
|
|
||||||
|
@append: (count, html) ->
|
||||||
|
$("#commits-list").append(html)
|
||||||
|
if count > 0
|
||||||
|
@data.offset += count
|
||||||
|
else
|
||||||
|
@disable = true
|
||||||
|
|
||||||
|
@initLoadMore: ->
|
||||||
|
$(document).unbind('scroll')
|
||||||
|
$(document).endlessScroll
|
||||||
|
bottomPixels: 400
|
||||||
|
fireDelay: 1000
|
||||||
|
fireOnce: true
|
||||||
|
ceaseFire: =>
|
||||||
|
@disable
|
||||||
|
callback: =>
|
||||||
|
this.getOld()
|
||||||
|
|
||||||
|
this.CommitsList = CommitsList
|
33
app/assets/javascripts/dashboard.js.coffee
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
class Dashboard
|
||||||
|
constructor: ->
|
||||||
|
@initSidebarTab()
|
||||||
|
|
||||||
|
$(".dash-filter").keyup ->
|
||||||
|
terms = $(this).val()
|
||||||
|
uiBox = $(this).parents('.panel').first()
|
||||||
|
if terms == "" || terms == undefined
|
||||||
|
uiBox.find(".dash-list li").show()
|
||||||
|
else
|
||||||
|
uiBox.find(".dash-list li").each (index) ->
|
||||||
|
name = $(this).find(".filter-title").text()
|
||||||
|
|
||||||
|
if name.toLowerCase().search(terms.toLowerCase()) == -1
|
||||||
|
$(this).hide()
|
||||||
|
else
|
||||||
|
$(this).show()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
initSidebarTab: ->
|
||||||
|
key = "dashboard_sidebar_filter"
|
||||||
|
|
||||||
|
# store selection in cookie
|
||||||
|
$('.dash-sidebar-tabs a').on 'click', (e) ->
|
||||||
|
$.cookie(key, $(e.target).attr('id'))
|
||||||
|
|
||||||
|
# show tab from cookie
|
||||||
|
sidebar_filter = $.cookie(key)
|
||||||
|
$("#" + sidebar_filter).tab('show') if sidebar_filter
|
||||||
|
|
||||||
|
|
||||||
|
@Dashboard = Dashboard
|
46
app/assets/javascripts/diff.js.coffee
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
class Diff
|
||||||
|
UNFOLD_COUNT = 20
|
||||||
|
constructor: ->
|
||||||
|
$(document).on('click', '.js-unfold', (event) =>
|
||||||
|
target = $(event.target)
|
||||||
|
unfoldBottom = target.hasClass('js-unfold-bottom')
|
||||||
|
unfold = true
|
||||||
|
|
||||||
|
[old_line, line_number] = @lineNumbers(target.parent())
|
||||||
|
offset = line_number - old_line
|
||||||
|
|
||||||
|
if unfoldBottom
|
||||||
|
line_number += 1
|
||||||
|
since = line_number
|
||||||
|
to = line_number + UNFOLD_COUNT
|
||||||
|
else
|
||||||
|
[prev_old_line, prev_new_line] = @lineNumbers(target.parent().prev())
|
||||||
|
line_number -= 1
|
||||||
|
to = line_number
|
||||||
|
if line_number - UNFOLD_COUNT > prev_new_line + 1
|
||||||
|
since = line_number - UNFOLD_COUNT
|
||||||
|
else
|
||||||
|
since = prev_new_line + 1
|
||||||
|
unfold = false
|
||||||
|
|
||||||
|
link = target.parents('.diff-file').attr('data-blob-diff-path')
|
||||||
|
params =
|
||||||
|
since: since
|
||||||
|
to: to
|
||||||
|
bottom: unfoldBottom
|
||||||
|
offset: offset
|
||||||
|
unfold: unfold
|
||||||
|
|
||||||
|
$.get(link, params, (response) =>
|
||||||
|
target.parent().replaceWith(response)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
lineNumbers: (line) ->
|
||||||
|
return ([0, 0]) unless line.children().length
|
||||||
|
lines = line.children().slice(0, 2)
|
||||||
|
line_numbers = ($(l).attr('data-linenumber') for l in lines)
|
||||||
|
(parseInt(line_number) for line_number in line_numbers)
|
||||||
|
|
||||||
|
|
||||||
|
@Diff = Diff
|
75
app/assets/javascripts/dispatcher.js.coffee
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
$ ->
|
||||||
|
new Dispatcher()
|
||||||
|
|
||||||
|
class Dispatcher
|
||||||
|
constructor: () ->
|
||||||
|
@initSearch()
|
||||||
|
@initHighlight()
|
||||||
|
@initPageScripts()
|
||||||
|
|
||||||
|
initPageScripts: ->
|
||||||
|
page = $('body').attr('data-page')
|
||||||
|
project_id = $('body').attr('data-project-id')
|
||||||
|
|
||||||
|
unless page
|
||||||
|
return false
|
||||||
|
|
||||||
|
path = page.split(':')
|
||||||
|
|
||||||
|
switch page
|
||||||
|
when 'projects:issues:index'
|
||||||
|
Issues.init()
|
||||||
|
when 'projects:issues:show'
|
||||||
|
new Issue()
|
||||||
|
when 'projects:milestones:show'
|
||||||
|
new Milestone()
|
||||||
|
when 'projects:issues:new'
|
||||||
|
GitLab.GfmAutoComplete.setup()
|
||||||
|
when 'projects:merge_requests:new'
|
||||||
|
GitLab.GfmAutoComplete.setup()
|
||||||
|
new Diff()
|
||||||
|
when 'projects:merge_requests:show'
|
||||||
|
new Diff()
|
||||||
|
when "projects:merge_requests:diffs"
|
||||||
|
new Diff()
|
||||||
|
when 'dashboard:show'
|
||||||
|
new Dashboard()
|
||||||
|
new Activities()
|
||||||
|
when 'projects:commit:show'
|
||||||
|
new Commit()
|
||||||
|
new Diff()
|
||||||
|
when 'groups:show', 'projects:show'
|
||||||
|
new Activities()
|
||||||
|
when 'projects:new', 'projects:edit'
|
||||||
|
new Project()
|
||||||
|
when 'projects:teams:members:index'
|
||||||
|
new TeamMembers()
|
||||||
|
when 'groups:members'
|
||||||
|
new GroupMembers()
|
||||||
|
when 'projects:tree:show'
|
||||||
|
new TreeView()
|
||||||
|
when 'projects:blob:show'
|
||||||
|
new BlobView()
|
||||||
|
when 'projects:labels:new', 'projects:labels:edit'
|
||||||
|
new Labels()
|
||||||
|
|
||||||
|
switch path.first()
|
||||||
|
when 'admin' then new Admin()
|
||||||
|
when 'projects'
|
||||||
|
new Wikis() if path[1] == 'wikis'
|
||||||
|
|
||||||
|
|
||||||
|
initSearch: ->
|
||||||
|
opts = $('.search-autocomplete-opts')
|
||||||
|
path = opts.data('autocomplete-path')
|
||||||
|
project_id = opts.data('autocomplete-project-id')
|
||||||
|
project_ref = opts.data('autocomplete-project-ref')
|
||||||
|
|
||||||
|
new SearchAutocomplete(path, project_id, project_ref)
|
||||||
|
|
||||||
|
initHighlight: ->
|
||||||
|
$('.highlight pre code').each (i, e) ->
|
||||||
|
$(e).html($.map($(e).html().split("\n"), (line, i) ->
|
||||||
|
"<span class='line' id='LC" + (i + 1) + "'>" + line + "</span>"
|
||||||
|
).join("\n"))
|
||||||
|
hljs.highlightBlock(e)
|
7
app/assets/javascripts/extensions/array.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Array.prototype.first = function() {
|
||||||
|
return this[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.prototype.last = function() {
|
||||||
|
return this[this.length-1];
|
||||||
|
}
|
13
app/assets/javascripts/extensions/jquery.js.coffee
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
$.fn.showAndHide = ->
|
||||||
|
$(@).show().
|
||||||
|
delay(3000).
|
||||||
|
fadeOut()
|
||||||
|
|
||||||
|
$.fn.enableButton = ->
|
||||||
|
$(@).removeAttr('disabled').
|
||||||
|
removeClass('disabled')
|
||||||
|
|
||||||
|
$.fn.disableButton = ->
|
||||||
|
$(@).attr('disabled', 'disabled').
|
||||||
|
addClass('disabled')
|
||||||
|
|
15
app/assets/javascripts/flash.js.coffee
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
class Flash
|
||||||
|
constructor: (message, type)->
|
||||||
|
flash = $(".flash-container")
|
||||||
|
flash.html("")
|
||||||
|
|
||||||
|
$('<div/>',
|
||||||
|
class: "flash-#{type}",
|
||||||
|
text: message
|
||||||
|
).appendTo(".flash-container")
|
||||||
|
|
||||||
|
flash.click -> $(@).fadeOut()
|
||||||
|
flash.show()
|
||||||
|
setTimeout (-> flash.fadeOut()), 5000
|
||||||
|
|
||||||
|
@Flash = Flash
|
67
app/assets/javascripts/gfm_auto_complete.js.coffee
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# Creates the variables for setting up GFM auto-completion
|
||||||
|
|
||||||
|
window.GitLab ?= {}
|
||||||
|
GitLab.GfmAutoComplete =
|
||||||
|
# private_token: ''
|
||||||
|
dataSource: ''
|
||||||
|
# Emoji
|
||||||
|
Emoji:
|
||||||
|
template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>'
|
||||||
|
|
||||||
|
# Team Members
|
||||||
|
Members:
|
||||||
|
template: '<li data-value="${username}">${username} <small>${name}</small></li>'
|
||||||
|
|
||||||
|
# Issues and MergeRequests
|
||||||
|
Issues:
|
||||||
|
template: '<li data-value="${id}"><small>${id}</small> ${title} </li>'
|
||||||
|
|
||||||
|
# Add GFM auto-completion to all input fields, that accept GFM input.
|
||||||
|
setup: ->
|
||||||
|
input = $('.js-gfm-input')
|
||||||
|
|
||||||
|
# Emoji
|
||||||
|
input.atwho
|
||||||
|
at: ':'
|
||||||
|
tpl: @Emoji.template
|
||||||
|
callbacks:
|
||||||
|
before_save: (emojis) =>
|
||||||
|
$.map emojis, (em) => name: em.name, insert: em.name+ ':', image: em.path
|
||||||
|
|
||||||
|
# Team Members
|
||||||
|
input.atwho
|
||||||
|
at: '@'
|
||||||
|
tpl: @Members.template
|
||||||
|
search_key: 'search'
|
||||||
|
callbacks:
|
||||||
|
before_save: (members) =>
|
||||||
|
$.map members, (m) => name: m.name, username: m.username, search: "#{m.username} #{m.name}"
|
||||||
|
|
||||||
|
input.atwho
|
||||||
|
at: '#'
|
||||||
|
alias: 'issues'
|
||||||
|
search_key: 'search'
|
||||||
|
tpl: @Issues.template
|
||||||
|
callbacks:
|
||||||
|
before_save: (issues) ->
|
||||||
|
$.map issues, (i) -> id: i.iid, title: sanitize(i.title), search: "#{i.iid} #{i.title}"
|
||||||
|
|
||||||
|
input.atwho
|
||||||
|
at: '!'
|
||||||
|
alias: 'mergerequests'
|
||||||
|
search_key: 'search'
|
||||||
|
tpl: @Issues.template
|
||||||
|
callbacks:
|
||||||
|
before_save: (merges) ->
|
||||||
|
$.map merges, (m) -> id: m.iid, title: sanitize(m.title), search: "#{m.iid} #{m.title}"
|
||||||
|
|
||||||
|
input.one "focus", =>
|
||||||
|
$.getJSON(@dataSource).done (data) ->
|
||||||
|
# load members
|
||||||
|
input.atwho 'load', "@", data.members
|
||||||
|
# load issues
|
||||||
|
input.atwho 'load', "issues", data.issues
|
||||||
|
# load merge requests
|
||||||
|
input.atwho 'load', "mergerequests", data.mergerequests
|
||||||
|
# load emojis
|
||||||
|
input.atwho 'load', ":", data.emojis
|
17
app/assets/javascripts/groups.js.coffee
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
class GroupMembers
|
||||||
|
constructor: ->
|
||||||
|
$('li.users_group').bind 'ajax:success', ->
|
||||||
|
$(this).fadeOut()
|
||||||
|
|
||||||
|
@GroupMembers = GroupMembers
|
||||||
|
|
||||||
|
$ ->
|
||||||
|
# avatar
|
||||||
|
$('.js-choose-group-avatar-button').bind "click", ->
|
||||||
|
form = $(this).closest("form")
|
||||||
|
form.find(".js-group-avatar-input").click()
|
||||||
|
|
||||||
|
$('.js-group-avatar-input').bind "change", ->
|
||||||
|
form = $(this).closest("form")
|
||||||
|
filename = $(this).val().replace(/^.*[\\\/]/, '')
|
||||||
|
form.find(".js-avatar-filename").text(filename)
|
9
app/assets/javascripts/issue.js.coffee
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
class Issue
|
||||||
|
constructor: ->
|
||||||
|
$('.edit-issue.inline-update input[type="submit"]').hide()
|
||||||
|
$(".issue-box .inline-update").on "change", "select", ->
|
||||||
|
$(this).submit()
|
||||||
|
$(".issue-box .inline-update").on "change", "#issue_assignee_id", ->
|
||||||
|
$(this).submit()
|
||||||
|
|
||||||
|
@Issue = Issue
|
79
app/assets/javascripts/issues.js.coffee
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
@Issues =
|
||||||
|
init: ->
|
||||||
|
Issues.initSearch()
|
||||||
|
Issues.initSelects()
|
||||||
|
Issues.initChecks()
|
||||||
|
|
||||||
|
$("body").on "ajax:success", ".close_issue, .reopen_issue", ->
|
||||||
|
t = $(this)
|
||||||
|
totalIssues = undefined
|
||||||
|
reopen = t.hasClass("reopen_issue")
|
||||||
|
$(".issue_counter").each ->
|
||||||
|
issue = $(this)
|
||||||
|
totalIssues = parseInt($(this).html(), 10)
|
||||||
|
if reopen and issue.closest(".main_menu").length
|
||||||
|
$(this).html totalIssues + 1
|
||||||
|
else
|
||||||
|
$(this).html totalIssues - 1
|
||||||
|
$("body").on "click", ".issues-filters .dropdown-menu a", ->
|
||||||
|
$('.issues-list').block(
|
||||||
|
message: null,
|
||||||
|
overlayCSS:
|
||||||
|
backgroundColor: '#DDD'
|
||||||
|
opacity: .4
|
||||||
|
)
|
||||||
|
|
||||||
|
reload: ->
|
||||||
|
Issues.initSelects()
|
||||||
|
Issues.initChecks()
|
||||||
|
$('#filter_issue_search').val($('#issue_search').val())
|
||||||
|
|
||||||
|
initSelects: ->
|
||||||
|
$("select#update_status").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||||
|
$("select#update_assignee_id").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||||
|
$("select#update_milestone_id").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||||
|
$("select#label_name").select2(width: 'resolve', dropdownAutoWidth: true)
|
||||||
|
$("#milestone_id, #assignee_id, #label_name").on "change", ->
|
||||||
|
$(this).closest("form").submit()
|
||||||
|
|
||||||
|
initChecks: ->
|
||||||
|
$(".check_all_issues").click ->
|
||||||
|
$(".selected_issue").prop("checked", @checked)
|
||||||
|
Issues.checkChanged()
|
||||||
|
|
||||||
|
$(".selected_issue").bind "change", Issues.checkChanged
|
||||||
|
|
||||||
|
|
||||||
|
initSearch: ->
|
||||||
|
form = $("#issue_search_form")
|
||||||
|
last_terms = ""
|
||||||
|
$("#issue_search").keyup ->
|
||||||
|
terms = $(this).val()
|
||||||
|
unless terms is last_terms
|
||||||
|
last_terms = terms
|
||||||
|
if terms.length >= 2 or terms.length is 0
|
||||||
|
$.ajax
|
||||||
|
type: "GET"
|
||||||
|
url: location.href
|
||||||
|
data: "issue_search=" + terms
|
||||||
|
complete: ->
|
||||||
|
$(".loading").hide()
|
||||||
|
success: (data) ->
|
||||||
|
$('.issues-holder').html(data.html)
|
||||||
|
Issues.reload()
|
||||||
|
dataType: "json"
|
||||||
|
|
||||||
|
checkChanged: ->
|
||||||
|
checked_issues = $(".selected_issue:checked")
|
||||||
|
if checked_issues.length > 0
|
||||||
|
ids = []
|
||||||
|
$.each checked_issues, (index, value) ->
|
||||||
|
ids.push $(value).attr("data-id")
|
||||||
|
|
||||||
|
$("#update_issues_ids").val ids
|
||||||
|
$(".issues-filters").hide()
|
||||||
|
$(".issues_bulk_update").show()
|
||||||
|
else
|
||||||
|
$("#update_issues_ids").val []
|
||||||
|
$(".issues_bulk_update").hide()
|
||||||
|
$(".issues-filters").show()
|
35
app/assets/javascripts/labels.js.coffee
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
class Labels
|
||||||
|
constructor: ->
|
||||||
|
form = $('.label-form')
|
||||||
|
@setupLabelForm(form)
|
||||||
|
@cleanBinding()
|
||||||
|
@addBinding()
|
||||||
|
@updateColorPreview()
|
||||||
|
|
||||||
|
addBinding: ->
|
||||||
|
$(document).on 'click', '.suggest-colors a', @setSuggestedColor
|
||||||
|
$(document).on 'input', 'input#label_color', @updateColorPreview
|
||||||
|
|
||||||
|
cleanBinding: ->
|
||||||
|
$(document).off 'click', '.suggest-colors a'
|
||||||
|
$(document).off 'input', 'input#label_color'
|
||||||
|
|
||||||
|
# Initializes the form to disable the save button if no color or title is entered
|
||||||
|
setupLabelForm: (form) ->
|
||||||
|
disableButtonIfAnyEmptyField form, '.form-control', form.find('.js-save-button')
|
||||||
|
|
||||||
|
# Updates the the preview color with the hex-color input
|
||||||
|
updateColorPreview: =>
|
||||||
|
previewColor = $('input#label_color').val()
|
||||||
|
$('div.label-color-preview').css('background-color', previewColor)
|
||||||
|
|
||||||
|
# Updates the preview color with a click on a suggested color
|
||||||
|
setSuggestedColor: (e) =>
|
||||||
|
color = $(e.currentTarget).data('color')
|
||||||
|
$('input#label_color').val(color)
|
||||||
|
@updateColorPreview()
|
||||||
|
# Notify the form, that color has changed
|
||||||
|
$('.label-form').trigger('keyup')
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
@Labels = Labels
|
181
app/assets/javascripts/lib/jquery.timeago.js
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
/**
|
||||||
|
* Timeago is a jQuery plugin that makes it easy to support automatically
|
||||||
|
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
|
||||||
|
*
|
||||||
|
* @name timeago
|
||||||
|
* @version 1.1.0
|
||||||
|
* @requires jQuery v1.2.3+
|
||||||
|
* @author Ryan McGeary
|
||||||
|
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
|
||||||
|
*
|
||||||
|
* For usage and examples, visit:
|
||||||
|
* http://timeago.yarp.com/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as an anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else {
|
||||||
|
// Browser globals
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
}(function ($) {
|
||||||
|
$.timeago = function(timestamp) {
|
||||||
|
if (timestamp instanceof Date) {
|
||||||
|
return inWords(timestamp);
|
||||||
|
} else if (typeof timestamp === "string") {
|
||||||
|
return inWords($.timeago.parse(timestamp));
|
||||||
|
} else if (typeof timestamp === "number") {
|
||||||
|
return inWords(new Date(timestamp));
|
||||||
|
} else {
|
||||||
|
return inWords($.timeago.datetime(timestamp));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var $t = $.timeago;
|
||||||
|
|
||||||
|
$.extend($.timeago, {
|
||||||
|
settings: {
|
||||||
|
refreshMillis: 60000,
|
||||||
|
allowFuture: false,
|
||||||
|
strings: {
|
||||||
|
prefixAgo: null,
|
||||||
|
prefixFromNow: null,
|
||||||
|
suffixAgo: "ago",
|
||||||
|
suffixFromNow: "from now",
|
||||||
|
seconds: "less than a minute",
|
||||||
|
minute: "about a minute",
|
||||||
|
minutes: "%d minutes",
|
||||||
|
hour: "about an hour",
|
||||||
|
hours: "about %d hours",
|
||||||
|
day: "a day",
|
||||||
|
days: "%d days",
|
||||||
|
month: "about a month",
|
||||||
|
months: "%d months",
|
||||||
|
year: "about a year",
|
||||||
|
years: "%d years",
|
||||||
|
wordSeparator: " ",
|
||||||
|
numbers: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inWords: function(distanceMillis) {
|
||||||
|
var $l = this.settings.strings;
|
||||||
|
var prefix = $l.prefixAgo;
|
||||||
|
var suffix = $l.suffixAgo;
|
||||||
|
if (this.settings.allowFuture) {
|
||||||
|
if (distanceMillis < 0) {
|
||||||
|
prefix = $l.prefixFromNow;
|
||||||
|
suffix = $l.suffixFromNow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var seconds = Math.abs(distanceMillis) / 1000;
|
||||||
|
var minutes = seconds / 60;
|
||||||
|
var hours = minutes / 60;
|
||||||
|
var days = hours / 24;
|
||||||
|
var years = days / 365;
|
||||||
|
|
||||||
|
function substitute(stringOrFunction, number) {
|
||||||
|
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
|
||||||
|
var value = ($l.numbers && $l.numbers[number]) || number;
|
||||||
|
return string.replace(/%d/i, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
|
||||||
|
seconds < 90 && substitute($l.minute, 1) ||
|
||||||
|
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
|
||||||
|
minutes < 90 && substitute($l.hour, 1) ||
|
||||||
|
hours < 24 && substitute($l.hours, Math.round(hours)) ||
|
||||||
|
hours < 42 && substitute($l.day, 1) ||
|
||||||
|
days < 30 && substitute($l.days, Math.round(days)) ||
|
||||||
|
days < 45 && substitute($l.month, 1) ||
|
||||||
|
days < 365 && substitute($l.months, Math.round(days / 30)) ||
|
||||||
|
years < 1.5 && substitute($l.year, 1) ||
|
||||||
|
substitute($l.years, Math.round(years));
|
||||||
|
|
||||||
|
var separator = $l.wordSeparator || "";
|
||||||
|
if ($l.wordSeparator === undefined) { separator = " "; }
|
||||||
|
return $.trim([prefix, words, suffix].join(separator));
|
||||||
|
},
|
||||||
|
parse: function(iso8601) {
|
||||||
|
var s = $.trim(iso8601);
|
||||||
|
s = s.replace(/\.\d+/,""); // remove milliseconds
|
||||||
|
s = s.replace(/-/,"/").replace(/-/,"/");
|
||||||
|
s = s.replace(/T/," ").replace(/Z/," UTC");
|
||||||
|
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
|
||||||
|
return new Date(s);
|
||||||
|
},
|
||||||
|
datetime: function(elem) {
|
||||||
|
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
|
||||||
|
return $t.parse(iso8601);
|
||||||
|
},
|
||||||
|
isTime: function(elem) {
|
||||||
|
// jQuery's `is()` doesn't play well with HTML5 in IE
|
||||||
|
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// functions that can be called via $(el).timeago('action')
|
||||||
|
// init is default when no action is given
|
||||||
|
// functions are called with context of a single element
|
||||||
|
var functions = {
|
||||||
|
init: function(){
|
||||||
|
var refresh_el = $.proxy(refresh, this);
|
||||||
|
refresh_el();
|
||||||
|
var $s = $t.settings;
|
||||||
|
if ($s.refreshMillis > 0) {
|
||||||
|
setInterval(refresh_el, $s.refreshMillis);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: function(time){
|
||||||
|
$(this).data('timeago', { datetime: $t.parse(time) });
|
||||||
|
refresh.apply(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.timeago = function(action, options) {
|
||||||
|
var fn = action ? functions[action] : functions.init;
|
||||||
|
if(!fn){
|
||||||
|
throw new Error("Unknown function name '"+ action +"' for timeago");
|
||||||
|
}
|
||||||
|
// each over objects here and call the requested function
|
||||||
|
this.each(function(){
|
||||||
|
fn.call(this, options);
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
var data = prepareData(this);
|
||||||
|
if (!isNaN(data.datetime)) {
|
||||||
|
$(this).text(inWords(data.datetime));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareData(element) {
|
||||||
|
element = $(element);
|
||||||
|
if (!element.data("timeago")) {
|
||||||
|
element.data("timeago", { datetime: $t.datetime(element) });
|
||||||
|
var text = $.trim(element.text());
|
||||||
|
if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
|
||||||
|
element.attr("title", text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return element.data("timeago");
|
||||||
|
}
|
||||||
|
|
||||||
|
function inWords(date) {
|
||||||
|
return $t.inWords(distance(date));
|
||||||
|
}
|
||||||
|
|
||||||
|
function distance(date) {
|
||||||
|
return (new Date().getTime() - date.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix for IE6 suckage
|
||||||
|
document.createElement("abbr");
|
||||||
|
document.createElement("time");
|
||||||
|
}));
|
211
app/assets/javascripts/lib/md5.js
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
function md5 (str) {
|
||||||
|
// http://kevin.vanzonneveld.net
|
||||||
|
// + original by: Webtoolkit.info (http://www.webtoolkit.info/)
|
||||||
|
// + namespaced by: Michael White (http://getsprink.com)
|
||||||
|
// + tweaked by: Jack
|
||||||
|
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
||||||
|
// + input by: Brett Zamir (http://brett-zamir.me)
|
||||||
|
// + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
||||||
|
// - depends on: utf8_encode
|
||||||
|
// * example 1: md5('Kevin van Zonneveld');
|
||||||
|
// * returns 1: '6e658d4bfcb59cc13f96c14450ac40b9'
|
||||||
|
var xl;
|
||||||
|
|
||||||
|
var rotateLeft = function (lValue, iShiftBits) {
|
||||||
|
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
|
||||||
|
};
|
||||||
|
|
||||||
|
var addUnsigned = function (lX, lY) {
|
||||||
|
var lX4, lY4, lX8, lY8, lResult;
|
||||||
|
lX8 = (lX & 0x80000000);
|
||||||
|
lY8 = (lY & 0x80000000);
|
||||||
|
lX4 = (lX & 0x40000000);
|
||||||
|
lY4 = (lY & 0x40000000);
|
||||||
|
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
|
||||||
|
if (lX4 & lY4) {
|
||||||
|
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
|
||||||
|
}
|
||||||
|
if (lX4 | lY4) {
|
||||||
|
if (lResult & 0x40000000) {
|
||||||
|
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
|
||||||
|
} else {
|
||||||
|
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (lResult ^ lX8 ^ lY8);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var _F = function (x, y, z) {
|
||||||
|
return (x & y) | ((~x) & z);
|
||||||
|
};
|
||||||
|
var _G = function (x, y, z) {
|
||||||
|
return (x & z) | (y & (~z));
|
||||||
|
};
|
||||||
|
var _H = function (x, y, z) {
|
||||||
|
return (x ^ y ^ z);
|
||||||
|
};
|
||||||
|
var _I = function (x, y, z) {
|
||||||
|
return (y ^ (x | (~z)));
|
||||||
|
};
|
||||||
|
|
||||||
|
var _FF = function (a, b, c, d, x, s, ac) {
|
||||||
|
a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
|
||||||
|
return addUnsigned(rotateLeft(a, s), b);
|
||||||
|
};
|
||||||
|
|
||||||
|
var _GG = function (a, b, c, d, x, s, ac) {
|
||||||
|
a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
|
||||||
|
return addUnsigned(rotateLeft(a, s), b);
|
||||||
|
};
|
||||||
|
|
||||||
|
var _HH = function (a, b, c, d, x, s, ac) {
|
||||||
|
a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
|
||||||
|
return addUnsigned(rotateLeft(a, s), b);
|
||||||
|
};
|
||||||
|
|
||||||
|
var _II = function (a, b, c, d, x, s, ac) {
|
||||||
|
a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
|
||||||
|
return addUnsigned(rotateLeft(a, s), b);
|
||||||
|
};
|
||||||
|
|
||||||
|
var convertToWordArray = function (str) {
|
||||||
|
var lWordCount;
|
||||||
|
var lMessageLength = str.length;
|
||||||
|
var lNumberOfWords_temp1 = lMessageLength + 8;
|
||||||
|
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
|
||||||
|
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
|
||||||
|
var lWordArray = new Array(lNumberOfWords - 1);
|
||||||
|
var lBytePosition = 0;
|
||||||
|
var lByteCount = 0;
|
||||||
|
while (lByteCount < lMessageLength) {
|
||||||
|
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||||
|
lBytePosition = (lByteCount % 4) * 8;
|
||||||
|
lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount) << lBytePosition));
|
||||||
|
lByteCount++;
|
||||||
|
}
|
||||||
|
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||||
|
lBytePosition = (lByteCount % 4) * 8;
|
||||||
|
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
|
||||||
|
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
|
||||||
|
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
|
||||||
|
return lWordArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
var wordToHex = function (lValue) {
|
||||||
|
var wordToHexValue = "",
|
||||||
|
wordToHexValue_temp = "",
|
||||||
|
lByte, lCount;
|
||||||
|
for (lCount = 0; lCount <= 3; lCount++) {
|
||||||
|
lByte = (lValue >>> (lCount * 8)) & 255;
|
||||||
|
wordToHexValue_temp = "0" + lByte.toString(16);
|
||||||
|
wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
|
||||||
|
}
|
||||||
|
return wordToHexValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
var x = [],
|
||||||
|
k, AA, BB, CC, DD, a, b, c, d, S11 = 7,
|
||||||
|
S12 = 12,
|
||||||
|
S13 = 17,
|
||||||
|
S14 = 22,
|
||||||
|
S21 = 5,
|
||||||
|
S22 = 9,
|
||||||
|
S23 = 14,
|
||||||
|
S24 = 20,
|
||||||
|
S31 = 4,
|
||||||
|
S32 = 11,
|
||||||
|
S33 = 16,
|
||||||
|
S34 = 23,
|
||||||
|
S41 = 6,
|
||||||
|
S42 = 10,
|
||||||
|
S43 = 15,
|
||||||
|
S44 = 21;
|
||||||
|
|
||||||
|
str = this.utf8_encode(str);
|
||||||
|
x = convertToWordArray(str);
|
||||||
|
a = 0x67452301;
|
||||||
|
b = 0xEFCDAB89;
|
||||||
|
c = 0x98BADCFE;
|
||||||
|
d = 0x10325476;
|
||||||
|
|
||||||
|
xl = x.length;
|
||||||
|
for (k = 0; k < xl; k += 16) {
|
||||||
|
AA = a;
|
||||||
|
BB = b;
|
||||||
|
CC = c;
|
||||||
|
DD = d;
|
||||||
|
a = _FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
|
||||||
|
d = _FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
|
||||||
|
c = _FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
|
||||||
|
b = _FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
|
||||||
|
a = _FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
|
||||||
|
d = _FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
|
||||||
|
c = _FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
|
||||||
|
b = _FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
|
||||||
|
a = _FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
|
||||||
|
d = _FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
|
||||||
|
c = _FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
|
||||||
|
b = _FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
|
||||||
|
a = _FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
|
||||||
|
d = _FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
|
||||||
|
c = _FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
|
||||||
|
b = _FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
|
||||||
|
a = _GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
|
||||||
|
d = _GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
|
||||||
|
c = _GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
|
||||||
|
b = _GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
|
||||||
|
a = _GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
|
||||||
|
d = _GG(d, a, b, c, x[k + 10], S22, 0x2441453);
|
||||||
|
c = _GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
|
||||||
|
b = _GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
|
||||||
|
a = _GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
|
||||||
|
d = _GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
|
||||||
|
c = _GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
|
||||||
|
b = _GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
|
||||||
|
a = _GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
|
||||||
|
d = _GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
|
||||||
|
c = _GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
|
||||||
|
b = _GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
|
||||||
|
a = _HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
|
||||||
|
d = _HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
|
||||||
|
c = _HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
|
||||||
|
b = _HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
|
||||||
|
a = _HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
|
||||||
|
d = _HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
|
||||||
|
c = _HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
|
||||||
|
b = _HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
|
||||||
|
a = _HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
|
||||||
|
d = _HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
|
||||||
|
c = _HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
|
||||||
|
b = _HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
|
||||||
|
a = _HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
|
||||||
|
d = _HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
|
||||||
|
c = _HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
|
||||||
|
b = _HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
|
||||||
|
a = _II(a, b, c, d, x[k + 0], S41, 0xF4292244);
|
||||||
|
d = _II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
|
||||||
|
c = _II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
|
||||||
|
b = _II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
|
||||||
|
a = _II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
|
||||||
|
d = _II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
|
||||||
|
c = _II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
|
||||||
|
b = _II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
|
||||||
|
a = _II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
|
||||||
|
d = _II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
|
||||||
|
c = _II(c, d, a, b, x[k + 6], S43, 0xA3014314);
|
||||||
|
b = _II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
|
||||||
|
a = _II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
|
||||||
|
d = _II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
|
||||||
|
c = _II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
|
||||||
|
b = _II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
|
||||||
|
a = addUnsigned(a, AA);
|
||||||
|
b = addUnsigned(b, BB);
|
||||||
|
c = addUnsigned(c, CC);
|
||||||
|
d = addUnsigned(d, DD);
|
||||||
|
}
|
||||||
|
|
||||||
|
var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
|
||||||
|
|
||||||
|
return temp.toLowerCase();
|
||||||
|
}
|
70
app/assets/javascripts/lib/utf8_encode.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
function utf8_encode (argString) {
|
||||||
|
// http://kevin.vanzonneveld.net
|
||||||
|
// + original by: Webtoolkit.info (http://www.webtoolkit.info/)
|
||||||
|
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
||||||
|
// + improved by: sowberry
|
||||||
|
// + tweaked by: Jack
|
||||||
|
// + bugfixed by: Onno Marsman
|
||||||
|
// + improved by: Yves Sucaet
|
||||||
|
// + bugfixed by: Onno Marsman
|
||||||
|
// + bugfixed by: Ulrich
|
||||||
|
// + bugfixed by: Rafal Kukawski
|
||||||
|
// + improved by: kirilloid
|
||||||
|
// + bugfixed by: kirilloid
|
||||||
|
// * example 1: utf8_encode('Kevin van Zonneveld');
|
||||||
|
// * returns 1: 'Kevin van Zonneveld'
|
||||||
|
|
||||||
|
if (argString === null || typeof argString === "undefined") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
var string = (argString + ''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
||||||
|
var utftext = '',
|
||||||
|
start, end, stringl = 0;
|
||||||
|
|
||||||
|
start = end = 0;
|
||||||
|
stringl = string.length;
|
||||||
|
for (var n = 0; n < stringl; n++) {
|
||||||
|
var c1 = string.charCodeAt(n);
|
||||||
|
var enc = null;
|
||||||
|
|
||||||
|
if (c1 < 128) {
|
||||||
|
end++;
|
||||||
|
} else if (c1 > 127 && c1 < 2048) {
|
||||||
|
enc = String.fromCharCode(
|
||||||
|
(c1 >> 6) | 192,
|
||||||
|
( c1 & 63) | 128
|
||||||
|
);
|
||||||
|
} else if (c1 & 0xF800 != 0xD800) {
|
||||||
|
enc = String.fromCharCode(
|
||||||
|
(c1 >> 12) | 224,
|
||||||
|
((c1 >> 6) & 63) | 128,
|
||||||
|
( c1 & 63) | 128
|
||||||
|
);
|
||||||
|
} else { // surrogate pairs
|
||||||
|
if (c1 & 0xFC00 != 0xD800) { throw new RangeError("Unmatched trail surrogate at " + n); }
|
||||||
|
var c2 = string.charCodeAt(++n);
|
||||||
|
if (c2 & 0xFC00 != 0xDC00) { throw new RangeError("Unmatched lead surrogate at " + (n-1)); }
|
||||||
|
c1 = ((c1 & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000;
|
||||||
|
enc = String.fromCharCode(
|
||||||
|
(c1 >> 18) | 240,
|
||||||
|
((c1 >> 12) & 63) | 128,
|
||||||
|
((c1 >> 6) & 63) | 128,
|
||||||
|
( c1 & 63) | 128
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (enc !== null) {
|
||||||
|
if (end > start) {
|
||||||
|
utftext += string.slice(start, end);
|
||||||
|
}
|
||||||
|
utftext += enc;
|
||||||
|
start = end = n + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end > start) {
|
||||||
|
utftext += string.slice(start, stringl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return utftext;
|
||||||
|
}
|
196
app/assets/javascripts/markdown_area.js.coffee
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
formatLink = (str) ->
|
||||||
|
"![" + str.alt + "](" + str.url + ")"
|
||||||
|
|
||||||
|
$(document).ready ->
|
||||||
|
alertClass = "alert alert-danger alert-dismissable div-dropzone-alert"
|
||||||
|
alertAttr = "class=\"close\" data-dismiss=\"alert\"" + "aria-hidden=\"true\""
|
||||||
|
divHover = "<div class=\"div-dropzone-hover\"></div>"
|
||||||
|
divSpinner = "<div class=\"div-dropzone-spinner\"></div>"
|
||||||
|
divAlert = "<div class=\"" + alertClass + "\"></div>"
|
||||||
|
iconPicture = "<i class=\"icon-picture div-dropzone-icon\"></i>"
|
||||||
|
iconSpinner = "<i class=\"icon-spinner icon-spin div-dropzone-icon\"></i>"
|
||||||
|
btnAlert = "<button type=\"button\"" + alertAttr + ">×</button>"
|
||||||
|
project_image_path_upload = window.project_image_path_upload or null
|
||||||
|
|
||||||
|
$("textarea.markdown-area").wrap "<div class=\"div-dropzone\"></div>"
|
||||||
|
|
||||||
|
$(".div-dropzone").parent().addClass "div-dropzone-wrapper"
|
||||||
|
|
||||||
|
$(".div-dropzone").append divHover
|
||||||
|
$(".div-dropzone-hover").append iconPicture
|
||||||
|
$(".div-dropzone").append divSpinner
|
||||||
|
$(".div-dropzone-spinner").append iconSpinner
|
||||||
|
$(".div-dropzone-spinner").css
|
||||||
|
"opacity": 0
|
||||||
|
"display": "none"
|
||||||
|
|
||||||
|
dropzone = $(".div-dropzone").dropzone(
|
||||||
|
url: project_image_path_upload
|
||||||
|
dictDefaultMessage: ""
|
||||||
|
clickable: true
|
||||||
|
paramName: "markdown_img"
|
||||||
|
maxFilesize: 10
|
||||||
|
uploadMultiple: false
|
||||||
|
acceptedFiles: "image/jpg,image/jpeg,image/gif,image/png"
|
||||||
|
headers:
|
||||||
|
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
|
||||||
|
|
||||||
|
previewContainer: false
|
||||||
|
|
||||||
|
processing: ->
|
||||||
|
$(".div-dropzone-alert").alert "close"
|
||||||
|
|
||||||
|
dragover: ->
|
||||||
|
$(".div-dropzone > textarea").addClass "div-dropzone-focus"
|
||||||
|
$(".div-dropzone-hover").css "opacity", 0.7
|
||||||
|
return
|
||||||
|
|
||||||
|
dragleave: ->
|
||||||
|
$(".div-dropzone > textarea").removeClass "div-dropzone-focus"
|
||||||
|
$(".div-dropzone-hover").css "opacity", 0
|
||||||
|
return
|
||||||
|
|
||||||
|
drop: ->
|
||||||
|
$(".div-dropzone > textarea").removeClass "div-dropzone-focus"
|
||||||
|
$(".div-dropzone-hover").css "opacity", 0
|
||||||
|
$(".div-dropzone > textarea").focus()
|
||||||
|
return
|
||||||
|
|
||||||
|
success: (header, response) ->
|
||||||
|
child = $(dropzone[0]).children("textarea")
|
||||||
|
$(child).val $(child).val() + formatLink(response.link) + "\n"
|
||||||
|
return
|
||||||
|
|
||||||
|
error: (temp, errorMessage) ->
|
||||||
|
checkIfMsgExists = $(".error-alert").children().length
|
||||||
|
if checkIfMsgExists is 0
|
||||||
|
$(".error-alert").append divAlert
|
||||||
|
$(".div-dropzone-alert").append btnAlert + errorMessage
|
||||||
|
return
|
||||||
|
|
||||||
|
sending: ->
|
||||||
|
$(".div-dropzone-spinner").css
|
||||||
|
"opacity": 0.7
|
||||||
|
"display": "inherit"
|
||||||
|
return
|
||||||
|
|
||||||
|
complete: ->
|
||||||
|
$(".dz-preview").remove()
|
||||||
|
$(".markdown-area").trigger "input"
|
||||||
|
$(".div-dropzone-spinner").css
|
||||||
|
"opacity": 0
|
||||||
|
"display": "none"
|
||||||
|
return
|
||||||
|
)
|
||||||
|
|
||||||
|
child = $(dropzone[0]).children("textarea")
|
||||||
|
|
||||||
|
formatLink = (str) ->
|
||||||
|
"![" + str.alt + "](" + str.url + ")"
|
||||||
|
|
||||||
|
handlePaste = (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
my_event = e.originalEvent
|
||||||
|
|
||||||
|
if my_event.clipboardData and my_event.clipboardData.items
|
||||||
|
processItem(my_event)
|
||||||
|
|
||||||
|
processItem = (e) ->
|
||||||
|
image = isImage(e)
|
||||||
|
if image
|
||||||
|
filename = getFilename(e) or "image.png"
|
||||||
|
text = "{{" + filename + "}}"
|
||||||
|
pasteText(text)
|
||||||
|
uploadFile image.getAsFile(), filename
|
||||||
|
|
||||||
|
else
|
||||||
|
text = e.clipboardData.getData("text/plain")
|
||||||
|
pasteText(text)
|
||||||
|
|
||||||
|
isImage = (data) ->
|
||||||
|
i = 0
|
||||||
|
while i < data.clipboardData.items.length
|
||||||
|
item = data.clipboardData.items[i]
|
||||||
|
if item.type.indexOf("image") isnt -1
|
||||||
|
return item
|
||||||
|
i++
|
||||||
|
return false
|
||||||
|
|
||||||
|
pasteText = (text) ->
|
||||||
|
caretStart = $(child)[0].selectionStart
|
||||||
|
caretEnd = $(child)[0].selectionEnd
|
||||||
|
textEnd = $(child).val().length
|
||||||
|
|
||||||
|
beforeSelection = $(child).val().substring 0, caretStart
|
||||||
|
afterSelection = $(child).val().substring caretEnd, textEnd
|
||||||
|
$(child).val beforeSelection + text + afterSelection
|
||||||
|
$(".markdown-area").trigger "input"
|
||||||
|
|
||||||
|
getFilename = (e) ->
|
||||||
|
if window.clipboardData and window.clipboardData.getData
|
||||||
|
value = window.clipboardData.getData("Text")
|
||||||
|
else if e.clipboardData and e.clipboardData.getData
|
||||||
|
value = e.clipboardData.getData("text/plain")
|
||||||
|
|
||||||
|
value = value.split("\r")
|
||||||
|
value.first()
|
||||||
|
|
||||||
|
uploadFile = (item, filename) ->
|
||||||
|
formData = new FormData()
|
||||||
|
formData.append "markdown_img", item, filename
|
||||||
|
$.ajax
|
||||||
|
url: project_image_path_upload
|
||||||
|
type: "POST"
|
||||||
|
data: formData
|
||||||
|
dataType: "json"
|
||||||
|
processData: false
|
||||||
|
contentType: false
|
||||||
|
headers:
|
||||||
|
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
|
||||||
|
|
||||||
|
beforeSend: ->
|
||||||
|
showSpinner()
|
||||||
|
closeAlertMessage()
|
||||||
|
|
||||||
|
success: (e, textStatus, response) ->
|
||||||
|
insertToTextArea(filename, formatLink(response.responseJSON.link))
|
||||||
|
|
||||||
|
error: (response) ->
|
||||||
|
showError(response.responseJSON.message)
|
||||||
|
|
||||||
|
complete: ->
|
||||||
|
closeSpinner()
|
||||||
|
|
||||||
|
insertToTextArea = (filename, url) ->
|
||||||
|
$(child).val (index, val) ->
|
||||||
|
val.replace("{{" + filename + "}}", url + "\n")
|
||||||
|
|
||||||
|
appendToTextArea = (url) ->
|
||||||
|
$(child).val (index, val) ->
|
||||||
|
val + url + "\n"
|
||||||
|
|
||||||
|
showSpinner = (e) ->
|
||||||
|
$(".div-dropzone-spinner").css
|
||||||
|
"opacity": 0.7
|
||||||
|
"display": "inherit"
|
||||||
|
|
||||||
|
closeSpinner = ->
|
||||||
|
$(".div-dropzone-spinner").css
|
||||||
|
"opacity": 0
|
||||||
|
"display": "none"
|
||||||
|
|
||||||
|
showError = (message) ->
|
||||||
|
checkIfMsgExists = $(".error-alert").children().length
|
||||||
|
if checkIfMsgExists is 0
|
||||||
|
$(".error-alert").append divAlert
|
||||||
|
$(".div-dropzone-alert").append btnAlert + message
|
||||||
|
|
||||||
|
closeAlertMessage = ->
|
||||||
|
$(".div-dropzone-alert").alert "close"
|
||||||
|
|
||||||
|
$(".markdown-selector").click (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
$(@).closest(".div-dropzone-wrapper").find(".div-dropzone").click()
|
||||||
|
return
|
||||||
|
|
||||||
|
return
|
129
app/assets/javascripts/merge_request.js.coffee
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
class MergeRequest
|
||||||
|
constructor: (@opts) ->
|
||||||
|
@initContextWidget()
|
||||||
|
this.$el = $('.merge-request')
|
||||||
|
@diffs_loaded = if @opts.action == 'diffs' then true else false
|
||||||
|
@commits_loaded = false
|
||||||
|
|
||||||
|
this.activateTab(@opts.action)
|
||||||
|
|
||||||
|
this.bindEvents()
|
||||||
|
|
||||||
|
this.initMergeWidget()
|
||||||
|
this.$('.show-all-commits').on 'click', =>
|
||||||
|
this.showAllCommits()
|
||||||
|
|
||||||
|
modal = $('#modal_merge_info').modal(show: false)
|
||||||
|
|
||||||
|
disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request'
|
||||||
|
|
||||||
|
|
||||||
|
# Local jQuery finder
|
||||||
|
$: (selector) ->
|
||||||
|
this.$el.find(selector)
|
||||||
|
|
||||||
|
initContextWidget: ->
|
||||||
|
$('.edit-merge_request.inline-update input[type="submit"]').hide()
|
||||||
|
$(".issue-box .inline-update").on "change", "select", ->
|
||||||
|
$(this).submit()
|
||||||
|
$(".issue-box .inline-update").on "change", "#merge_request_assignee_id", ->
|
||||||
|
$(this).submit()
|
||||||
|
|
||||||
|
initMergeWidget: ->
|
||||||
|
this.showState( @opts.current_status )
|
||||||
|
|
||||||
|
if this.$('.automerge_widget').length and @opts.check_enable
|
||||||
|
$.get @opts.url_to_automerge_check, (data) =>
|
||||||
|
this.showState( data.merge_status )
|
||||||
|
, 'json'
|
||||||
|
|
||||||
|
if @opts.ci_enable
|
||||||
|
$.get @opts.url_to_ci_check, (data) =>
|
||||||
|
this.showCiState data.status
|
||||||
|
, 'json'
|
||||||
|
|
||||||
|
bindEvents: ->
|
||||||
|
this.$('.merge-request-tabs').on 'click', 'a', (event) =>
|
||||||
|
a = $(event.currentTarget)
|
||||||
|
|
||||||
|
href = a.attr('href')
|
||||||
|
History.replaceState {path: href}, document.title, href
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
this.$('.merge-request-tabs').on 'click', 'li', (event) =>
|
||||||
|
this.activateTab($(event.currentTarget).data('action'))
|
||||||
|
|
||||||
|
this.$('.accept_merge_request').on 'click', ->
|
||||||
|
$('.automerge_widget.can_be_merged').hide()
|
||||||
|
$('.merge-in-progress').show()
|
||||||
|
|
||||||
|
this.$('.remove_source_branch').on 'click', ->
|
||||||
|
$('.remove_source_branch_widget').hide()
|
||||||
|
$('.remove_source_branch_in_progress').show()
|
||||||
|
|
||||||
|
this.$(".remove_source_branch").on "ajax:success", (e, data, status, xhr) ->
|
||||||
|
location.reload()
|
||||||
|
|
||||||
|
this.$(".remove_source_branch").on "ajax:error", (e, data, status, xhr) =>
|
||||||
|
this.$('.remove_source_branch_widget').hide()
|
||||||
|
this.$('.remove_source_branch_in_progress').hide()
|
||||||
|
this.$('.remove_source_branch_widget.failed').show()
|
||||||
|
|
||||||
|
activateTab: (action) ->
|
||||||
|
this.$('.merge-request-tabs li').removeClass 'active'
|
||||||
|
this.$('.tab-content').hide()
|
||||||
|
switch action
|
||||||
|
when 'diffs'
|
||||||
|
this.$('.merge-request-tabs .diffs-tab').addClass 'active'
|
||||||
|
this.loadDiff() unless @diffs_loaded
|
||||||
|
this.$('.diffs').show()
|
||||||
|
else
|
||||||
|
this.$('.merge-request-tabs .notes-tab').addClass 'active'
|
||||||
|
this.$('.notes').show()
|
||||||
|
|
||||||
|
showState: (state) ->
|
||||||
|
$('.automerge_widget').hide()
|
||||||
|
$('.automerge_widget.' + state).show()
|
||||||
|
|
||||||
|
showCiState: (state) ->
|
||||||
|
$('.ci_widget').hide()
|
||||||
|
allowed_states = ["failed", "running", "pending", "success"]
|
||||||
|
if state in allowed_states
|
||||||
|
$('.ci_widget.ci-' + state).show()
|
||||||
|
else
|
||||||
|
$('.ci_widget.ci-error').show()
|
||||||
|
|
||||||
|
switch state
|
||||||
|
when "success"
|
||||||
|
$('.mr-state-widget').addClass("panel-success")
|
||||||
|
when "failed"
|
||||||
|
$('.mr-state-widget').addClass("panel-danger")
|
||||||
|
when "running", "pending"
|
||||||
|
$('.mr-state-widget').addClass("panel-warning")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
loadDiff: (event) ->
|
||||||
|
$.ajax
|
||||||
|
type: 'GET'
|
||||||
|
url: this.$('.merge-request-tabs .diffs-tab a').attr('href')
|
||||||
|
beforeSend: =>
|
||||||
|
this.$('.mr-loading-status .loading').show()
|
||||||
|
complete: =>
|
||||||
|
@diffs_loaded = true
|
||||||
|
this.$('.mr-loading-status .loading').hide()
|
||||||
|
success: (data) =>
|
||||||
|
this.$(".diffs").html(data.html)
|
||||||
|
dataType: 'json'
|
||||||
|
|
||||||
|
showAllCommits: ->
|
||||||
|
this.$('.first-commits').remove()
|
||||||
|
this.$('.all-commits').removeClass 'hide'
|
||||||
|
|
||||||
|
alreadyOrCannotBeMerged: ->
|
||||||
|
this.$('.automerge_widget').hide()
|
||||||
|
this.$('.merge-in-progress').hide()
|
||||||
|
this.$('.automerge_widget.already_cannot_be_merged').show()
|
||||||
|
|
||||||
|
this.MergeRequest = MergeRequest
|
8
app/assets/javascripts/merge_requests.js.coffee
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#
|
||||||
|
# * Filter merge requests
|
||||||
|
#
|
||||||
|
@merge_requestsPage = ->
|
||||||
|
$('#assignee_id').select2()
|
||||||
|
$('#milestone_id').select2()
|
||||||
|
$('#milestone_id, #assignee_id').on 'change', ->
|
||||||
|
$(this).closest('form').submit()
|
119
app/assets/javascripts/milestone.js.coffee
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
class Milestone
|
||||||
|
@updateIssue: (li, issue_url, data) ->
|
||||||
|
$.ajax
|
||||||
|
type: "PUT"
|
||||||
|
url: issue_url
|
||||||
|
data: data
|
||||||
|
success: (data) ->
|
||||||
|
if data.saved == true
|
||||||
|
if data.assignee_avatar_url
|
||||||
|
img_tag = $('<img/>')
|
||||||
|
img_tag.attr('src', data.assignee_avatar_url)
|
||||||
|
img_tag.addClass('avatar s16')
|
||||||
|
$(li).find('.assignee-icon').html(img_tag)
|
||||||
|
else
|
||||||
|
$(li).find('.assignee-icon').html('')
|
||||||
|
$(li).effect 'highlight'
|
||||||
|
else
|
||||||
|
new Flash("Issue update failed", 'alert')
|
||||||
|
dataType: "json"
|
||||||
|
|
||||||
|
@sortIssues: (data) ->
|
||||||
|
sort_issues_url = location.href + "/sort_issues"
|
||||||
|
|
||||||
|
$.ajax
|
||||||
|
type: "PUT"
|
||||||
|
url: sort_issues_url
|
||||||
|
data: data
|
||||||
|
success: (data) ->
|
||||||
|
if data.saved != true
|
||||||
|
new Flash("Issues update failed", 'alert')
|
||||||
|
dataType: "json"
|
||||||
|
|
||||||
|
@sortMergeRequests: (data) ->
|
||||||
|
sort_mr_url = location.href + "/sort_merge_requests"
|
||||||
|
|
||||||
|
$.ajax
|
||||||
|
type: "PUT"
|
||||||
|
url: sort_mr_url
|
||||||
|
data: data
|
||||||
|
success: (data) ->
|
||||||
|
if data.saved != true
|
||||||
|
new Flash("MR update failed", 'alert')
|
||||||
|
dataType: "json"
|
||||||
|
|
||||||
|
@updateMergeRequest: (li, merge_request_url, data) ->
|
||||||
|
$.ajax
|
||||||
|
type: "PUT"
|
||||||
|
url: merge_request_url
|
||||||
|
data: data
|
||||||
|
success: (data) ->
|
||||||
|
if data.saved == true
|
||||||
|
$(li).effect 'highlight'
|
||||||
|
else
|
||||||
|
new Flash("Issue update failed", 'alert')
|
||||||
|
dataType: "json"
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
@bindIssuesSorting()
|
||||||
|
@bindMergeRequestSorting()
|
||||||
|
|
||||||
|
bindIssuesSorting: ->
|
||||||
|
$("#issues-list-unassigned, #issues-list-ongoing, #issues-list-closed").sortable(
|
||||||
|
connectWith: ".issues-sortable-list",
|
||||||
|
dropOnEmpty: true,
|
||||||
|
items: "li:not(.ui-sort-disabled)",
|
||||||
|
update: (event, ui) ->
|
||||||
|
data = $(this).sortable("serialize")
|
||||||
|
Milestone.sortIssues(data)
|
||||||
|
|
||||||
|
receive: (event, ui) ->
|
||||||
|
new_state = $(this).data('state')
|
||||||
|
issue_id = ui.item.data('iid')
|
||||||
|
issue_url = ui.item.data('url')
|
||||||
|
|
||||||
|
data = switch new_state
|
||||||
|
when 'ongoing'
|
||||||
|
"issue[assignee_id]=" + gon.current_user_id
|
||||||
|
when 'unassigned'
|
||||||
|
"issue[assignee_id]="
|
||||||
|
when 'closed'
|
||||||
|
"issue[state_event]=close"
|
||||||
|
|
||||||
|
if $(ui.sender).data('state') == "closed"
|
||||||
|
data += "&issue[state_event]=reopen"
|
||||||
|
|
||||||
|
Milestone.updateIssue(ui.item, issue_url, data)
|
||||||
|
|
||||||
|
).disableSelection()
|
||||||
|
|
||||||
|
bindMergeRequestSorting: ->
|
||||||
|
$("#merge_requests-list-unassigned, #merge_requests-list-ongoing, #merge_requests-list-closed").sortable(
|
||||||
|
connectWith: ".merge_requests-sortable-list",
|
||||||
|
dropOnEmpty: true,
|
||||||
|
items: "li:not(.ui-sort-disabled)",
|
||||||
|
update: (event, ui) ->
|
||||||
|
data = $(this).sortable("serialize")
|
||||||
|
Milestone.sortMergeRequests(data)
|
||||||
|
|
||||||
|
receive: (event, ui) ->
|
||||||
|
new_state = $(this).data('state')
|
||||||
|
merge_request_id = ui.item.data('iid')
|
||||||
|
merge_request_url = ui.item.data('url')
|
||||||
|
|
||||||
|
data = switch new_state
|
||||||
|
when 'ongoing'
|
||||||
|
"merge_request[assignee_id]=" + gon.current_user_id
|
||||||
|
when 'unassigned'
|
||||||
|
"merge_request[assignee_id]="
|
||||||
|
when 'closed'
|
||||||
|
"merge_request[state_event]=close"
|
||||||
|
|
||||||
|
if $(ui.sender).data('state') == "closed"
|
||||||
|
data += "&merge_request[state_event]=reopen"
|
||||||
|
|
||||||
|
Milestone.updateMergeRequest(ui.item, merge_request_url, data)
|
||||||
|
|
||||||
|
).disableSelection()
|
||||||
|
|
||||||
|
@Milestone = Milestone
|
24
app/assets/javascripts/namespace_select.js.coffee
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
$ ->
|
||||||
|
namespaceFormatResult = (namespace) ->
|
||||||
|
markup = "<div class='namespace-result'>"
|
||||||
|
markup += "<span class='namespace-kind'>" + namespace.kind + "</span>"
|
||||||
|
markup += "<span class='namespace-path'>" + namespace.path + "</span>"
|
||||||
|
markup += "</div>"
|
||||||
|
markup
|
||||||
|
|
||||||
|
formatSelection = (namespace) ->
|
||||||
|
namespace.kind + ": " + namespace.path
|
||||||
|
|
||||||
|
$('.ajax-namespace-select').each (i, select) ->
|
||||||
|
$(select).select2
|
||||||
|
placeholder: "Search for namespace"
|
||||||
|
multiple: $(select).hasClass('multiselect')
|
||||||
|
minimumInputLength: 0
|
||||||
|
query: (query) ->
|
||||||
|
Api.namespaces query.term, (namespaces) ->
|
||||||
|
data = { results: namespaces }
|
||||||
|
query.callback(data)
|
||||||
|
|
||||||
|
dropdownCssClass: "ajax-namespace-dropdown"
|
||||||
|
formatResult: namespaceFormatResult
|
||||||
|
formatSelection: formatSelection
|
11
app/assets/javascripts/network.js.coffee
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
class Network
|
||||||
|
constructor: (opts) ->
|
||||||
|
$("#filter_ref").click ->
|
||||||
|
$(this).closest('form').submit()
|
||||||
|
|
||||||
|
branch_graph = new BranchGraph($(".network-graph"), opts)
|
||||||
|
|
||||||
|
vph = $(window).height() - 250
|
||||||
|
$('.network-graph').css 'height': (vph + 'px')
|
||||||
|
|
||||||
|
@Network = Network
|
505
app/assets/javascripts/notes.js.coffee
Normal file
|
@ -0,0 +1,505 @@
|
||||||
|
class Notes
|
||||||
|
@interval: null
|
||||||
|
|
||||||
|
constructor: (notes_url, note_ids, last_fetched_at) ->
|
||||||
|
@notes_url = notes_url
|
||||||
|
@notes_url = gon.relative_url_root + @notes_url if gon.relative_url_root?
|
||||||
|
@note_ids = note_ids
|
||||||
|
@last_fetched_at = last_fetched_at
|
||||||
|
@initRefresh()
|
||||||
|
@setupMainTargetNoteForm()
|
||||||
|
@cleanBinding()
|
||||||
|
@addBinding()
|
||||||
|
|
||||||
|
addBinding: ->
|
||||||
|
# add note to UI after creation
|
||||||
|
$(document).on "ajax:success", ".js-main-target-form", @addNote
|
||||||
|
$(document).on "ajax:success", ".js-discussion-note-form", @addDiscussionNote
|
||||||
|
|
||||||
|
# change note in UI after update
|
||||||
|
$(document).on "ajax:success", "form.edit_note", @updateNote
|
||||||
|
|
||||||
|
# Edit note link
|
||||||
|
$(document).on "click", ".js-note-edit", @showEditForm
|
||||||
|
$(document).on "click", ".note-edit-cancel", @cancelEdit
|
||||||
|
|
||||||
|
# remove a note (in general)
|
||||||
|
$(document).on "click", ".js-note-delete", @removeNote
|
||||||
|
|
||||||
|
# delete note attachment
|
||||||
|
$(document).on "click", ".js-note-attachment-delete", @removeAttachment
|
||||||
|
|
||||||
|
# Preview button
|
||||||
|
$(document).on "click", ".js-note-preview-button", @previewNote
|
||||||
|
|
||||||
|
# Preview button
|
||||||
|
$(document).on "click", ".js-note-write-button", @writeNote
|
||||||
|
|
||||||
|
# reset main target form after submit
|
||||||
|
$(document).on "ajax:complete", ".js-main-target-form", @resetMainTargetForm
|
||||||
|
|
||||||
|
# attachment button
|
||||||
|
$(document).on "click", ".js-choose-note-attachment-button", @chooseNoteAttachment
|
||||||
|
|
||||||
|
# update the file name when an attachment is selected
|
||||||
|
$(document).on "change", ".js-note-attachment-input", @updateFormAttachment
|
||||||
|
|
||||||
|
# reply to diff/discussion notes
|
||||||
|
$(document).on "click", ".js-discussion-reply-button", @replyToDiscussionNote
|
||||||
|
|
||||||
|
# add diff note
|
||||||
|
$(document).on "click", ".js-add-diff-note-button", @addDiffNote
|
||||||
|
|
||||||
|
# hide diff note form
|
||||||
|
$(document).on "click", ".js-close-discussion-note-form", @cancelDiscussionForm
|
||||||
|
|
||||||
|
# fetch notes when tab becomes visible
|
||||||
|
$(document).on "visibilitychange", @visibilityChange
|
||||||
|
|
||||||
|
@notes_forms = '.js-main-target-form textarea, .js-discussion-note-form textarea'
|
||||||
|
$(document).on('keypress', @notes_forms, (e)->
|
||||||
|
if e.keyCode == 10 || (e.ctrlKey && e.keyCode == 13)
|
||||||
|
$(@).parents('form').submit()
|
||||||
|
)
|
||||||
|
|
||||||
|
cleanBinding: ->
|
||||||
|
$(document).off "ajax:success", ".js-main-target-form"
|
||||||
|
$(document).off "ajax:success", ".js-discussion-note-form"
|
||||||
|
$(document).off "ajax:success", "form.edit_note"
|
||||||
|
$(document).off "click", ".js-note-edit"
|
||||||
|
$(document).off "click", ".note-edit-cancel"
|
||||||
|
$(document).off "click", ".js-note-delete"
|
||||||
|
$(document).off "click", ".js-note-attachment-delete"
|
||||||
|
$(document).off "click", ".js-note-preview-button"
|
||||||
|
$(document).off "click", ".js-note-write-button"
|
||||||
|
$(document).off "ajax:complete", ".js-main-target-form"
|
||||||
|
$(document).off "click", ".js-choose-note-attachment-button"
|
||||||
|
$(document).off "click", ".js-discussion-reply-button"
|
||||||
|
$(document).off "click", ".js-add-diff-note-button"
|
||||||
|
$(document).off "visibilitychange"
|
||||||
|
$(document).off "keypress", @notes_forms
|
||||||
|
|
||||||
|
|
||||||
|
initRefresh: ->
|
||||||
|
clearInterval(Notes.interval)
|
||||||
|
Notes.interval = setInterval =>
|
||||||
|
@refresh()
|
||||||
|
, 15000
|
||||||
|
|
||||||
|
refresh: ->
|
||||||
|
@getContent() unless document.hidden
|
||||||
|
|
||||||
|
getContent: ->
|
||||||
|
$.ajax
|
||||||
|
url: @notes_url
|
||||||
|
data: "last_fetched_at=" + @last_fetched_at
|
||||||
|
dataType: "json"
|
||||||
|
success: (data) =>
|
||||||
|
notes = data.notes
|
||||||
|
@last_fetched_at = data.last_fetched_at
|
||||||
|
$.each notes, (i, note) =>
|
||||||
|
@renderNote(note)
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
Render note in main comments area.
|
||||||
|
|
||||||
|
Note: for rendering inline notes use renderDiscussionNote
|
||||||
|
###
|
||||||
|
renderNote: (note) ->
|
||||||
|
# render note if it not present in loaded list
|
||||||
|
# or skip if rendered
|
||||||
|
if @isNewNote(note)
|
||||||
|
@note_ids.push(note.id)
|
||||||
|
$('ul.main-notes-list').append(note.html)
|
||||||
|
code = "#note_" + note.id + " .highlight pre code"
|
||||||
|
$(code).each (i, e) ->
|
||||||
|
hljs.highlightBlock(e)
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
Check if note does not exists on page
|
||||||
|
###
|
||||||
|
isNewNote: (note) ->
|
||||||
|
$.inArray(note.id, @note_ids) == -1
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
Render note in discussion area.
|
||||||
|
|
||||||
|
Note: for rendering inline notes use renderDiscussionNote
|
||||||
|
###
|
||||||
|
renderDiscussionNote: (note) ->
|
||||||
|
@note_ids.push(note.id)
|
||||||
|
form = $("form[rel='" + note.discussion_id + "']")
|
||||||
|
row = form.closest("tr")
|
||||||
|
|
||||||
|
# is this the first note of discussion?
|
||||||
|
if row.is(".js-temp-notes-holder")
|
||||||
|
# insert the note and the reply button after the temp row
|
||||||
|
row.after note.discussion_html
|
||||||
|
|
||||||
|
# remove the note (will be added again below)
|
||||||
|
row.next().find(".note").remove()
|
||||||
|
|
||||||
|
# Add note to 'Changes' page discussions
|
||||||
|
$(".notes[rel='" + note.discussion_id + "']").append note.html
|
||||||
|
|
||||||
|
# Init discussion on 'Discussion' page if it is merge request page
|
||||||
|
if $('body').attr('data-page').indexOf('projects:merge_request') == 0
|
||||||
|
$('ul.main-notes-list').append(note.discussion_with_diff_html)
|
||||||
|
else
|
||||||
|
# append new note to all matching discussions
|
||||||
|
$(".notes[rel='" + note.discussion_id + "']").append note.html
|
||||||
|
|
||||||
|
# cleanup after successfully creating a diff/discussion note
|
||||||
|
@removeDiscussionNoteForm(form)
|
||||||
|
|
||||||
|
###
|
||||||
|
Shows write note textarea.
|
||||||
|
###
|
||||||
|
writeNote: (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
form = $(this).closest("form")
|
||||||
|
# toggle tabs
|
||||||
|
form.find(".js-note-write-button").parent().addClass "active"
|
||||||
|
form.find(".js-note-preview-button").parent().removeClass "active"
|
||||||
|
|
||||||
|
# toggle content
|
||||||
|
form.find(".note-write-holder").show()
|
||||||
|
form.find(".note-preview-holder").hide()
|
||||||
|
|
||||||
|
###
|
||||||
|
Shows the note preview.
|
||||||
|
|
||||||
|
Lets the server render GFM into Html and displays it.
|
||||||
|
###
|
||||||
|
previewNote: (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
form = $(this).closest("form")
|
||||||
|
# toggle tabs
|
||||||
|
form.find(".js-note-write-button").parent().removeClass "active"
|
||||||
|
form.find(".js-note-preview-button").parent().addClass "active"
|
||||||
|
|
||||||
|
# toggle content
|
||||||
|
form.find(".note-write-holder").hide()
|
||||||
|
form.find(".note-preview-holder").show()
|
||||||
|
|
||||||
|
preview = form.find(".js-note-preview")
|
||||||
|
noteText = form.find(".js-note-text").val()
|
||||||
|
if noteText.trim().length is 0
|
||||||
|
preview.text "Nothing to preview."
|
||||||
|
else
|
||||||
|
preview.text "Loading..."
|
||||||
|
$.post($(this).data("url"),
|
||||||
|
note: noteText
|
||||||
|
).success (previewData) ->
|
||||||
|
preview.html previewData
|
||||||
|
|
||||||
|
###
|
||||||
|
Called in response the main target form has been successfully submitted.
|
||||||
|
|
||||||
|
Removes any errors.
|
||||||
|
Resets text and preview.
|
||||||
|
Resets buttons.
|
||||||
|
###
|
||||||
|
resetMainTargetForm: ->
|
||||||
|
form = $(".js-main-target-form")
|
||||||
|
|
||||||
|
# remove validation errors
|
||||||
|
form.find(".js-errors").remove()
|
||||||
|
|
||||||
|
# reset text and preview
|
||||||
|
form.find(".js-note-write-button").click()
|
||||||
|
form.find(".js-note-text").val("").trigger "input"
|
||||||
|
|
||||||
|
###
|
||||||
|
Called when clicking the "Choose File" button.
|
||||||
|
|
||||||
|
Opens the file selection dialog.
|
||||||
|
###
|
||||||
|
chooseNoteAttachment: ->
|
||||||
|
form = $(this).closest("form")
|
||||||
|
form.find(".js-note-attachment-input").click()
|
||||||
|
|
||||||
|
###
|
||||||
|
Shows the main form and does some setup on it.
|
||||||
|
|
||||||
|
Sets some hidden fields in the form.
|
||||||
|
###
|
||||||
|
setupMainTargetNoteForm: ->
|
||||||
|
|
||||||
|
# find the form
|
||||||
|
form = $(".js-new-note-form")
|
||||||
|
|
||||||
|
# insert the form after the button
|
||||||
|
form.clone().replaceAll $(".js-main-target-form")
|
||||||
|
form = form.prev("form")
|
||||||
|
|
||||||
|
# show the form
|
||||||
|
@setupNoteForm(form)
|
||||||
|
|
||||||
|
# fix classes
|
||||||
|
form.removeClass "js-new-note-form"
|
||||||
|
form.addClass "js-main-target-form"
|
||||||
|
|
||||||
|
# remove unnecessary fields and buttons
|
||||||
|
form.find("#note_line_code").remove()
|
||||||
|
form.find(".js-close-discussion-note-form").remove()
|
||||||
|
|
||||||
|
###
|
||||||
|
General note form setup.
|
||||||
|
|
||||||
|
deactivates the submit button when text is empty
|
||||||
|
hides the preview button when text is empty
|
||||||
|
setup GFM auto complete
|
||||||
|
show the form
|
||||||
|
###
|
||||||
|
setupNoteForm: (form) ->
|
||||||
|
disableButtonIfEmptyField form.find(".js-note-text"), form.find(".js-comment-button")
|
||||||
|
form.removeClass "js-new-note-form"
|
||||||
|
|
||||||
|
# setup preview buttons
|
||||||
|
form.find(".js-note-write-button, .js-note-preview-button").tooltip placement: "left"
|
||||||
|
previewButton = form.find(".js-note-preview-button")
|
||||||
|
form.find(".js-note-text").on "input", ->
|
||||||
|
if $(this).val().trim() isnt ""
|
||||||
|
previewButton.removeClass("turn-off").addClass "turn-on"
|
||||||
|
else
|
||||||
|
previewButton.removeClass("turn-on").addClass "turn-off"
|
||||||
|
|
||||||
|
|
||||||
|
# remove notify commit author checkbox for non-commit notes
|
||||||
|
form.find(".js-notify-commit-author").remove() if form.find("#note_noteable_type").val() isnt "Commit"
|
||||||
|
GitLab.GfmAutoComplete.setup()
|
||||||
|
form.show()
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
Called in response to the new note form being submitted
|
||||||
|
|
||||||
|
Adds new note to list.
|
||||||
|
###
|
||||||
|
addNote: (xhr, note, status) =>
|
||||||
|
@renderNote(note)
|
||||||
|
@updateVotes()
|
||||||
|
|
||||||
|
###
|
||||||
|
Called in response to the new note form being submitted
|
||||||
|
|
||||||
|
Adds new note to list.
|
||||||
|
###
|
||||||
|
addDiscussionNote: (xhr, note, status) =>
|
||||||
|
@renderDiscussionNote(note)
|
||||||
|
|
||||||
|
###
|
||||||
|
Called in response to the edit note form being submitted
|
||||||
|
|
||||||
|
Updates the current note field.
|
||||||
|
###
|
||||||
|
updateNote: (xhr, note, status) =>
|
||||||
|
note_li = $("#note_" + note.id)
|
||||||
|
note_li.replaceWith(note.html)
|
||||||
|
code = "#note_" + note.id + " .highlight pre code"
|
||||||
|
$(code).each (i, e) ->
|
||||||
|
hljs.highlightBlock(e)
|
||||||
|
|
||||||
|
###
|
||||||
|
Called in response to clicking the edit note link
|
||||||
|
|
||||||
|
Replaces the note text with the note edit form
|
||||||
|
Adds a hidden div with the original content of the note to fill the edit note form with
|
||||||
|
if the user cancels
|
||||||
|
###
|
||||||
|
showEditForm: (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
note = $(this).closest(".note")
|
||||||
|
note.find(".note-text").hide()
|
||||||
|
|
||||||
|
# Show the attachment delete link
|
||||||
|
note.find(".js-note-attachment-delete").show()
|
||||||
|
GitLab.GfmAutoComplete.setup()
|
||||||
|
form = note.find(".note-edit-form")
|
||||||
|
form.show()
|
||||||
|
textarea = form.find("textarea")
|
||||||
|
textarea.focus()
|
||||||
|
disableButtonIfEmptyField textarea, form.find(".js-comment-button")
|
||||||
|
|
||||||
|
###
|
||||||
|
Called in response to clicking the edit note link
|
||||||
|
|
||||||
|
Hides edit form
|
||||||
|
###
|
||||||
|
cancelEdit: (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
note = $(this).closest(".note")
|
||||||
|
note.find(".note-text").show()
|
||||||
|
note.find(".js-note-attachment-delete").hide()
|
||||||
|
note.find(".note-edit-form").hide()
|
||||||
|
|
||||||
|
###
|
||||||
|
Called in response to deleting a note of any kind.
|
||||||
|
|
||||||
|
Removes the actual note from view.
|
||||||
|
Removes the whole discussion if the last note is being removed.
|
||||||
|
###
|
||||||
|
removeNote: ->
|
||||||
|
note = $(this).closest(".note")
|
||||||
|
notes = note.closest(".notes")
|
||||||
|
|
||||||
|
# check if this is the last note for this line
|
||||||
|
if notes.find(".note").length is 1
|
||||||
|
|
||||||
|
# for discussions
|
||||||
|
notes.closest(".discussion").remove()
|
||||||
|
|
||||||
|
# for diff lines
|
||||||
|
notes.closest("tr").remove()
|
||||||
|
|
||||||
|
note.remove()
|
||||||
|
|
||||||
|
###
|
||||||
|
Called in response to clicking the delete attachment link
|
||||||
|
|
||||||
|
Removes the attachment wrapper view, including image tag if it exists
|
||||||
|
Resets the note editing form
|
||||||
|
###
|
||||||
|
removeAttachment: ->
|
||||||
|
note = $(this).closest(".note")
|
||||||
|
note.find(".note-attachment").remove()
|
||||||
|
note.find(".note-text").show()
|
||||||
|
note.find(".js-note-attachment-delete").hide()
|
||||||
|
note.find(".note-edit-form").hide()
|
||||||
|
|
||||||
|
###
|
||||||
|
Called when clicking on the "reply" button for a diff line.
|
||||||
|
|
||||||
|
Shows the note form below the notes.
|
||||||
|
###
|
||||||
|
replyToDiscussionNote: (e) =>
|
||||||
|
form = $(".js-new-note-form")
|
||||||
|
replyLink = $(e.target).closest(".js-discussion-reply-button")
|
||||||
|
replyLink.hide()
|
||||||
|
|
||||||
|
# insert the form after the button
|
||||||
|
form.clone().insertAfter replyLink
|
||||||
|
|
||||||
|
# show the form
|
||||||
|
@setupDiscussionNoteForm(replyLink, replyLink.next("form"))
|
||||||
|
|
||||||
|
###
|
||||||
|
Shows the diff or discussion form and does some setup on it.
|
||||||
|
|
||||||
|
Sets some hidden fields in the form.
|
||||||
|
|
||||||
|
Note: dataHolder must have the "discussionId", "lineCode", "noteableType"
|
||||||
|
and "noteableId" data attributes set.
|
||||||
|
###
|
||||||
|
setupDiscussionNoteForm: (dataHolder, form) =>
|
||||||
|
# setup note target
|
||||||
|
form.attr "rel", dataHolder.data("discussionId")
|
||||||
|
form.find("#note_commit_id").val dataHolder.data("commitId")
|
||||||
|
form.find("#note_line_code").val dataHolder.data("lineCode")
|
||||||
|
form.find("#note_noteable_type").val dataHolder.data("noteableType")
|
||||||
|
form.find("#note_noteable_id").val dataHolder.data("noteableId")
|
||||||
|
@setupNoteForm form
|
||||||
|
form.find(".js-note-text").focus()
|
||||||
|
form.addClass "js-discussion-note-form"
|
||||||
|
|
||||||
|
###
|
||||||
|
General note form setup.
|
||||||
|
|
||||||
|
deactivates the submit button when text is empty
|
||||||
|
hides the preview button when text is empty
|
||||||
|
setup GFM auto complete
|
||||||
|
show the form
|
||||||
|
###
|
||||||
|
setupNoteForm: (form) =>
|
||||||
|
disableButtonIfEmptyField form.find(".js-note-text"), form.find(".js-comment-button")
|
||||||
|
form.removeClass "js-new-note-form"
|
||||||
|
form.removeClass "js-new-note-form"
|
||||||
|
GitLab.GfmAutoComplete.setup()
|
||||||
|
|
||||||
|
# setup preview buttons
|
||||||
|
previewButton = form.find(".js-note-preview-button")
|
||||||
|
form.find(".js-note-text").on "input", ->
|
||||||
|
if $(this).val().trim() isnt ""
|
||||||
|
previewButton.removeClass("turn-off").addClass "turn-on"
|
||||||
|
else
|
||||||
|
previewButton.removeClass("turn-on").addClass "turn-off"
|
||||||
|
|
||||||
|
form.show()
|
||||||
|
|
||||||
|
###
|
||||||
|
Called when clicking on the "add a comment" button on the side of a diff line.
|
||||||
|
|
||||||
|
Inserts a temporary row for the form below the line.
|
||||||
|
Sets up the form and shows it.
|
||||||
|
###
|
||||||
|
addDiffNote: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
link = e.target
|
||||||
|
form = $(".js-new-note-form")
|
||||||
|
row = $(link).closest("tr")
|
||||||
|
nextRow = row.next()
|
||||||
|
|
||||||
|
# does it already have notes?
|
||||||
|
if nextRow.is(".notes_holder")
|
||||||
|
replyButton = nextRow.find(".js-discussion-reply-button")
|
||||||
|
if replyButton.length > 0
|
||||||
|
$.proxy(@replyToDiscussionNote, replyButton).call()
|
||||||
|
else
|
||||||
|
# add a notes row and insert the form
|
||||||
|
row.after "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\" colspan=\"2\"></td><td class=\"notes_content\"></td></tr>"
|
||||||
|
form.clone().appendTo row.next().find(".notes_content")
|
||||||
|
|
||||||
|
# show the form
|
||||||
|
@setupDiscussionNoteForm $(link), row.next().find("form")
|
||||||
|
|
||||||
|
###
|
||||||
|
Called in response to "cancel" on a diff note form.
|
||||||
|
|
||||||
|
Shows the reply button again.
|
||||||
|
Removes the form and if necessary it's temporary row.
|
||||||
|
###
|
||||||
|
removeDiscussionNoteForm: (form)->
|
||||||
|
row = form.closest("tr")
|
||||||
|
|
||||||
|
# show the reply button (will only work for replies)
|
||||||
|
form.prev(".js-discussion-reply-button").show()
|
||||||
|
if row.is(".js-temp-notes-holder")
|
||||||
|
# remove temporary row for diff lines
|
||||||
|
row.remove()
|
||||||
|
else
|
||||||
|
# only remove the form
|
||||||
|
form.remove()
|
||||||
|
|
||||||
|
|
||||||
|
cancelDiscussionForm: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
form = $(".js-new-note-form")
|
||||||
|
form = $(e.target).closest(".js-discussion-note-form")
|
||||||
|
@removeDiscussionNoteForm(form)
|
||||||
|
|
||||||
|
updateVotes: ->
|
||||||
|
(new NotesVotes).updateVotes()
|
||||||
|
|
||||||
|
###
|
||||||
|
Called after an attachment file has been selected.
|
||||||
|
|
||||||
|
Updates the file name for the selected attachment.
|
||||||
|
###
|
||||||
|
updateFormAttachment: ->
|
||||||
|
form = $(this).closest("form")
|
||||||
|
|
||||||
|
# get only the basename
|
||||||
|
filename = $(this).val().replace(/^.*[\\\/]/, "")
|
||||||
|
form.find(".js-attachment-filename").text filename
|
||||||
|
|
||||||
|
###
|
||||||
|
Called when the tab visibility changes
|
||||||
|
###
|
||||||
|
visibilityChange: =>
|
||||||
|
@refresh()
|
||||||
|
|
||||||
|
@Notes = Notes
|
22
app/assets/javascripts/notes_votes.js.coffee
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
class NotesVotes
|
||||||
|
updateVotes: ->
|
||||||
|
votes = $("#votes .votes")
|
||||||
|
notes = $("#notes-list .note .vote")
|
||||||
|
|
||||||
|
# only update if there is a vote display
|
||||||
|
if votes.size()
|
||||||
|
upvotes = notes.filter(".upvote").size()
|
||||||
|
downvotes = notes.filter(".downvote").size()
|
||||||
|
votesCount = upvotes + downvotes
|
||||||
|
upvotesPercent = (if votesCount then (100.0 / votesCount * upvotes) else 0)
|
||||||
|
downvotesPercent = (if votesCount then (100.0 - upvotesPercent) else 0)
|
||||||
|
|
||||||
|
# change vote bar lengths
|
||||||
|
votes.find(".bar-success").css "width", upvotesPercent + "%"
|
||||||
|
votes.find(".bar-danger").css "width", downvotesPercent + "%"
|
||||||
|
|
||||||
|
# replace vote numbers
|
||||||
|
votes.find(".upvotes").text votes.find(".upvotes").text().replace(/\d+/, upvotes)
|
||||||
|
votes.find(".downvotes").text votes.find(".downvotes").text().replace(/\d+/, downvotes)
|
||||||
|
|
||||||
|
@NotesVotes = NotesVotes
|
42
app/assets/javascripts/pager.js.coffee
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
@Pager =
|
||||||
|
init: (@limit = 0, preload, @disable = false) ->
|
||||||
|
@loading = $(".loading")
|
||||||
|
if preload
|
||||||
|
@offset = 0
|
||||||
|
@getOld()
|
||||||
|
else
|
||||||
|
@offset = @limit
|
||||||
|
@initLoadMore()
|
||||||
|
|
||||||
|
getOld: ->
|
||||||
|
@loading.show()
|
||||||
|
$.ajax
|
||||||
|
type: "GET"
|
||||||
|
url: location.href
|
||||||
|
data: "limit=" + @limit + "&offset=" + @offset
|
||||||
|
complete: =>
|
||||||
|
@loading.hide()
|
||||||
|
success: (data) ->
|
||||||
|
Pager.append(data.count, data.html)
|
||||||
|
dataType: "json"
|
||||||
|
|
||||||
|
append: (count, html) ->
|
||||||
|
$(".content_list").append html
|
||||||
|
if count > 0
|
||||||
|
@offset += count
|
||||||
|
else
|
||||||
|
@disable = true
|
||||||
|
|
||||||
|
initLoadMore: ->
|
||||||
|
$(document).unbind('scroll')
|
||||||
|
$(document).endlessScroll
|
||||||
|
bottomPixels: 400
|
||||||
|
fireDelay: 1000
|
||||||
|
fireOnce: true
|
||||||
|
ceaseFire: ->
|
||||||
|
Pager.disable
|
||||||
|
|
||||||
|
callback: (i) =>
|
||||||
|
unless @loading.is(':visible')
|
||||||
|
@loading.show()
|
||||||
|
Pager.getOld()
|
30
app/assets/javascripts/profile.js.coffee
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
$ ->
|
||||||
|
$('.edit_user .application-theme input, .edit_user .code-preview-theme input').click ->
|
||||||
|
# Submit the form
|
||||||
|
$('.edit_user').submit()
|
||||||
|
|
||||||
|
new Flash("Appearance settings saved", "notice")
|
||||||
|
|
||||||
|
$('.update-username form').on 'ajax:before', ->
|
||||||
|
$('.loading-gif').show()
|
||||||
|
$(this).find('.update-success').hide()
|
||||||
|
$(this).find('.update-failed').hide()
|
||||||
|
|
||||||
|
$('.update-username form').on 'ajax:complete', ->
|
||||||
|
$(this).find('.btn-save').enableButton()
|
||||||
|
$(this).find('.loading-gif').hide()
|
||||||
|
|
||||||
|
$('.update-notifications').on 'ajax:complete', ->
|
||||||
|
$(this).find('.btn-save').enableButton()
|
||||||
|
|
||||||
|
|
||||||
|
$('.js-choose-user-avatar-button').bind "click", ->
|
||||||
|
form = $(this).closest("form")
|
||||||
|
form.find(".js-user-avatar-input").click()
|
||||||
|
|
||||||
|
$('.js-user-avatar-input').bind "change", ->
|
||||||
|
form = $(this).closest("form")
|
||||||
|
filename = $(this).val().replace(/^.*[\\\/]/, '')
|
||||||
|
form.find(".js-avatar-filename").text(filename)
|
||||||
|
|
||||||
|
$('.profile-groups-avatars').tooltip("placement": "top")
|
53
app/assets/javascripts/project.js.coffee
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
class Project
|
||||||
|
constructor: ->
|
||||||
|
$('.project-edit-container').on 'ajax:before', =>
|
||||||
|
$('.project-edit-container').hide()
|
||||||
|
$('.save-project-loader').show()
|
||||||
|
|
||||||
|
@initEvents()
|
||||||
|
|
||||||
|
|
||||||
|
initEvents: ->
|
||||||
|
disableButtonIfEmptyField '#project_name', '.project-submit'
|
||||||
|
|
||||||
|
$('#project_issues_enabled').change ->
|
||||||
|
if ($(this).is(':checked') == true)
|
||||||
|
$('#project_issues_tracker').removeAttr('disabled')
|
||||||
|
else
|
||||||
|
$('#project_issues_tracker').attr('disabled', 'disabled')
|
||||||
|
|
||||||
|
$('#project_issues_tracker').change()
|
||||||
|
|
||||||
|
$('#project_issues_tracker').change ->
|
||||||
|
if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
|
||||||
|
$('#project_issues_tracker_id').attr('disabled', 'disabled')
|
||||||
|
else
|
||||||
|
$('#project_issues_tracker_id').removeAttr('disabled')
|
||||||
|
|
||||||
|
|
||||||
|
@Project = Project
|
||||||
|
|
||||||
|
$ ->
|
||||||
|
# Git clone panel switcher
|
||||||
|
scope = $ '.git-clone-holder'
|
||||||
|
if scope.length > 0
|
||||||
|
$('a, button', scope).click ->
|
||||||
|
$('a, button', scope).removeClass 'active'
|
||||||
|
$(@).addClass 'active'
|
||||||
|
$('#project_clone', scope).val $(@).data 'clone'
|
||||||
|
$(".clone").text("").append $(@).data 'clone'
|
||||||
|
|
||||||
|
# Ref switcher
|
||||||
|
$('.project-refs-select').on 'change', ->
|
||||||
|
$(@).parents('form').submit()
|
||||||
|
|
||||||
|
$('.hide-no-ssh-message').on 'click', (e) ->
|
||||||
|
path = '/'
|
||||||
|
$.cookie('hide_no_ssh_message', 'false', { path: path })
|
||||||
|
$(@).parents('.no-ssh-key-message').hide()
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
$('.project-side .star').on 'ajax:success', (e, data, status, xhr) ->
|
||||||
|
$(@).toggleClass('on').find('.count').html(data.star_count)
|
||||||
|
.on 'ajax:error', (e, xhr, status, error) ->
|
||||||
|
new Flash('Star toggle failed. Try again later.', 'alert')
|
7
app/assets/javascripts/project_import.js.coffee
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class ProjectImport
|
||||||
|
constructor: ->
|
||||||
|
setTimeout ->
|
||||||
|
Turbolinks.visit(location.href)
|
||||||
|
, 5000
|
||||||
|
|
||||||
|
@ProjectImport = ProjectImport
|
59
app/assets/javascripts/project_users_select.js.coffee
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
@projectUsersSelect =
|
||||||
|
init: ->
|
||||||
|
$('.ajax-project-users-select').each (i, select) ->
|
||||||
|
project_id = $(select).data('project-id') || $('body').data('project-id')
|
||||||
|
|
||||||
|
$(select).select2
|
||||||
|
placeholder: $(select).data('placeholder') || "Search for a user"
|
||||||
|
multiple: $(select).hasClass('multiselect')
|
||||||
|
minimumInputLength: 0
|
||||||
|
query: (query) ->
|
||||||
|
Api.projectUsers project_id, query.term, (users) ->
|
||||||
|
data = { results: users }
|
||||||
|
|
||||||
|
nullUser = {
|
||||||
|
name: 'Unassigned',
|
||||||
|
avatar: null,
|
||||||
|
username: 'none',
|
||||||
|
id: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
data.results.unshift(nullUser)
|
||||||
|
|
||||||
|
query.callback(data)
|
||||||
|
|
||||||
|
initSelection: (element, callback) ->
|
||||||
|
id = $(element).val()
|
||||||
|
if id isnt ""
|
||||||
|
Api.user(id, callback)
|
||||||
|
|
||||||
|
|
||||||
|
formatResult: projectUsersSelect.projectUserFormatResult
|
||||||
|
formatSelection: projectUsersSelect.projectUserFormatSelection
|
||||||
|
dropdownCssClass: "ajax-project-users-dropdown"
|
||||||
|
dropdownAutoWidth: true
|
||||||
|
escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
|
||||||
|
m
|
||||||
|
|
||||||
|
projectUserFormatResult: (user) ->
|
||||||
|
if user.avatar_url
|
||||||
|
avatar = user.avatar_url
|
||||||
|
else
|
||||||
|
avatar = gon.default_avatar_url
|
||||||
|
|
||||||
|
if user.id == ''
|
||||||
|
avatarMarkup = ''
|
||||||
|
else
|
||||||
|
avatarMarkup = "<div class='user-image'><img class='avatar s24' src='#{avatar}'></div>"
|
||||||
|
|
||||||
|
"<div class='user-result'>
|
||||||
|
#{avatarMarkup}
|
||||||
|
<div class='user-name'>#{user.name}</div>
|
||||||
|
<div class='user-username'>#{user.username}</div>
|
||||||
|
</div>"
|
||||||
|
|
||||||
|
projectUserFormatSelection: (user) ->
|
||||||
|
user.name
|
||||||
|
|
||||||
|
$ ->
|
||||||
|
projectUsersSelect.init()
|
13
app/assets/javascripts/search_autocomplete.js.coffee
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
class SearchAutocomplete
|
||||||
|
constructor: (search_autocomplete_path, project_id, project_ref) ->
|
||||||
|
project_id = '' unless project_id
|
||||||
|
project_ref = '' unless project_ref
|
||||||
|
query = "?project_id=" + project_id + "&project_ref=" + project_ref
|
||||||
|
|
||||||
|
$("#search").autocomplete
|
||||||
|
source: search_autocomplete_path + query
|
||||||
|
minLength: 1
|
||||||
|
select: (event, ui) ->
|
||||||
|
location.href = ui.item.url
|
||||||
|
|
||||||
|
@SearchAutocomplete = SearchAutocomplete
|
11
app/assets/javascripts/shortcuts.js.coffee
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
class Shortcuts
|
||||||
|
constructor: ->
|
||||||
|
if $('#modal-shortcuts').length > 0
|
||||||
|
$('#modal-shortcuts').modal('show')
|
||||||
|
else
|
||||||
|
$.ajax(
|
||||||
|
url: '/help/shortcuts',
|
||||||
|
dataType: "script"
|
||||||
|
)
|
||||||
|
|
||||||
|
@Shortcuts = Shortcuts
|
26
app/assets/javascripts/sidebar.js.coffee
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
responsive_resize = ->
|
||||||
|
current_width = $(window).width()
|
||||||
|
if current_width < 985
|
||||||
|
$('.responsive-side').addClass("ui right wide sidebar")
|
||||||
|
else
|
||||||
|
$('.responsive-side').removeClass("ui right wide sidebar")
|
||||||
|
|
||||||
|
$ ->
|
||||||
|
# Depending on window size, set the sidebar offscreen.
|
||||||
|
responsive_resize()
|
||||||
|
|
||||||
|
$('.sidebar-expand-button').click ->
|
||||||
|
$('.ui.sidebar')
|
||||||
|
.sidebar({overlay: true})
|
||||||
|
.sidebar('toggle')
|
||||||
|
|
||||||
|
# Hide sidebar on click outside of sidebar
|
||||||
|
$(document).mouseup (e) ->
|
||||||
|
container = $(".ui.sidebar")
|
||||||
|
container.sidebar "hide" if not container.is(e.target) and container.has(e.target).length is 0
|
||||||
|
return
|
||||||
|
|
||||||
|
# On resize, check if sidebar should be offscreen.
|
||||||
|
$(window).resize ->
|
||||||
|
responsive_resize()
|
||||||
|
return
|
6
app/assets/javascripts/stat_graph.js.coffee
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class window.StatGraph
|
||||||
|
@log: {}
|
||||||
|
@get_log: ->
|
||||||
|
@log
|
||||||
|
@set_log: (data) ->
|
||||||
|
@log = data
|
84
app/assets/javascripts/stat_graph_contributors.js.coffee
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
class window.ContributorsStatGraph
|
||||||
|
init: (log) ->
|
||||||
|
@parsed_log = ContributorsStatGraphUtil.parse_log(log)
|
||||||
|
@set_current_field("commits")
|
||||||
|
total_commits = ContributorsStatGraphUtil.get_total_data(@parsed_log, @field)
|
||||||
|
author_commits = ContributorsStatGraphUtil.get_author_data(@parsed_log, @field)
|
||||||
|
@add_master_graph(total_commits)
|
||||||
|
@add_authors_graph(author_commits)
|
||||||
|
@change_date_header()
|
||||||
|
add_master_graph: (total_data) ->
|
||||||
|
@master_graph = new ContributorsMasterGraph(total_data)
|
||||||
|
@master_graph.draw()
|
||||||
|
add_authors_graph: (author_data) ->
|
||||||
|
@authors = []
|
||||||
|
limited_author_data = author_data.slice(0, 100)
|
||||||
|
_.each(limited_author_data, (d) =>
|
||||||
|
author_header = @create_author_header(d)
|
||||||
|
$(".contributors-list").append(author_header)
|
||||||
|
@authors[d.author_name] = author_graph = new ContributorsAuthorGraph(d.dates)
|
||||||
|
author_graph.draw()
|
||||||
|
)
|
||||||
|
format_author_commit_info: (author) ->
|
||||||
|
commits = $('<span/>', {
|
||||||
|
class: 'graph-author-commits-count'
|
||||||
|
})
|
||||||
|
commits.text(author.commits + " commits")
|
||||||
|
|
||||||
|
additions = $('<span/>', {
|
||||||
|
class: 'graph-additions'
|
||||||
|
})
|
||||||
|
additions.text(author.additions + " ++")
|
||||||
|
|
||||||
|
deletions = $('<span/>', {
|
||||||
|
class: 'graph-deletions'
|
||||||
|
})
|
||||||
|
deletions.text(author.deletions + " --")
|
||||||
|
|
||||||
|
$('<span/>').append(commits)
|
||||||
|
.append(" / ")
|
||||||
|
.append(additions)
|
||||||
|
.append(" / ")
|
||||||
|
.append(deletions)
|
||||||
|
|
||||||
|
create_author_header: (author) ->
|
||||||
|
list_item = $('<li/>', {
|
||||||
|
class: 'person'
|
||||||
|
style: 'display: block;'
|
||||||
|
})
|
||||||
|
author_name = $('<h4>' + author.author_name + '</h4>')
|
||||||
|
author_email = $('<p class="graph-author-email">' + author.author_email + '</p>')
|
||||||
|
author_commit_info_span = $('<span/>', {
|
||||||
|
class: 'commits'
|
||||||
|
})
|
||||||
|
author_commit_info = @format_author_commit_info(author)
|
||||||
|
author_commit_info_span.html(author_commit_info)
|
||||||
|
list_item.append(author_name)
|
||||||
|
list_item.append(author_email)
|
||||||
|
list_item.append(author_commit_info_span)
|
||||||
|
list_item
|
||||||
|
redraw_master: ->
|
||||||
|
total_data = ContributorsStatGraphUtil.get_total_data(@parsed_log, @field)
|
||||||
|
@master_graph.set_data(total_data)
|
||||||
|
@master_graph.redraw()
|
||||||
|
redraw_authors: ->
|
||||||
|
$("ol").html("")
|
||||||
|
x_domain = ContributorsGraph.prototype.x_domain
|
||||||
|
author_commits = ContributorsStatGraphUtil.get_author_data(@parsed_log, @field, x_domain)
|
||||||
|
_.each(author_commits, (d) =>
|
||||||
|
@redraw_author_commit_info(d)
|
||||||
|
$(@authors[d.author_name].list_item).appendTo("ol")
|
||||||
|
@authors[d.author_name].set_data(d.dates)
|
||||||
|
@authors[d.author_name].redraw()
|
||||||
|
)
|
||||||
|
set_current_field: (field) ->
|
||||||
|
@field = field
|
||||||
|
change_date_header: ->
|
||||||
|
x_domain = ContributorsGraph.prototype.x_domain
|
||||||
|
print_date_format = d3.time.format("%B %e %Y")
|
||||||
|
print = print_date_format(x_domain[0]) + " - " + print_date_format(x_domain[1])
|
||||||
|
$("#date_header").text(print)
|
||||||
|
redraw_author_commit_info: (author) ->
|
||||||
|
author_list_item = $(@authors[author.author_name].list_item)
|
||||||
|
author_commit_info = @format_author_commit_info(author)
|
||||||
|
author_list_item.find("span").html(author_commit_info)
|
167
app/assets/javascripts/stat_graph_contributors_graph.js.coffee
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
class window.ContributorsGraph
|
||||||
|
MARGIN:
|
||||||
|
top: 20
|
||||||
|
right: 20
|
||||||
|
bottom: 30
|
||||||
|
left: 50
|
||||||
|
x_domain: null
|
||||||
|
y_domain: null
|
||||||
|
dates: []
|
||||||
|
@set_x_domain: (data) =>
|
||||||
|
@prototype.x_domain = data
|
||||||
|
@set_y_domain: (data) =>
|
||||||
|
@prototype.y_domain = [0, d3.max(data, (d) ->
|
||||||
|
d.commits = d.commits ? d.additions ? d.deletions
|
||||||
|
)]
|
||||||
|
@init_x_domain: (data) =>
|
||||||
|
@prototype.x_domain = d3.extent(data, (d) ->
|
||||||
|
d.date
|
||||||
|
)
|
||||||
|
@init_y_domain: (data) =>
|
||||||
|
@prototype.y_domain = [0, d3.max(data, (d) ->
|
||||||
|
d.commits = d.commits ? d.additions ? d.deletions
|
||||||
|
)]
|
||||||
|
@init_domain: (data) =>
|
||||||
|
@init_x_domain(data)
|
||||||
|
@init_y_domain(data)
|
||||||
|
@set_dates: (data) =>
|
||||||
|
@prototype.dates = data
|
||||||
|
set_x_domain: ->
|
||||||
|
@x.domain(@x_domain)
|
||||||
|
set_y_domain: ->
|
||||||
|
@y.domain(@y_domain)
|
||||||
|
set_domain: ->
|
||||||
|
@set_x_domain()
|
||||||
|
@set_y_domain()
|
||||||
|
create_scale: (width, height) ->
|
||||||
|
@x = d3.time.scale().range([0, width]).clamp(true)
|
||||||
|
@y = d3.scale.linear().range([height, 0]).nice()
|
||||||
|
draw_x_axis: ->
|
||||||
|
@svg.append("g").attr("class", "x axis").attr("transform", "translate(0, #{@height})")
|
||||||
|
.call(@x_axis)
|
||||||
|
draw_y_axis: ->
|
||||||
|
@svg.append("g").attr("class", "y axis").call(@y_axis)
|
||||||
|
set_data: (data) ->
|
||||||
|
@data = data
|
||||||
|
|
||||||
|
class window.ContributorsMasterGraph extends ContributorsGraph
|
||||||
|
constructor: (@data) ->
|
||||||
|
@width = $('.container').width() - 70
|
||||||
|
@height = 200
|
||||||
|
@x = null
|
||||||
|
@y = null
|
||||||
|
@x_axis = null
|
||||||
|
@y_axis = null
|
||||||
|
@area = null
|
||||||
|
@svg = null
|
||||||
|
@brush = null
|
||||||
|
@x_max_domain = null
|
||||||
|
process_dates: (data) ->
|
||||||
|
dates = @get_dates(data)
|
||||||
|
@parse_dates(data)
|
||||||
|
ContributorsGraph.set_dates(dates)
|
||||||
|
get_dates: (data) ->
|
||||||
|
_.pluck(data, 'date')
|
||||||
|
parse_dates: (data) ->
|
||||||
|
parseDate = d3.time.format("%Y-%m-%d").parse
|
||||||
|
data.forEach((d) ->
|
||||||
|
d.date = parseDate(d.date)
|
||||||
|
)
|
||||||
|
create_scale: ->
|
||||||
|
super @width, @height
|
||||||
|
create_axes: ->
|
||||||
|
@x_axis = d3.svg.axis().scale(@x).orient("bottom")
|
||||||
|
@y_axis = d3.svg.axis().scale(@y).orient("left").ticks(5)
|
||||||
|
create_svg: ->
|
||||||
|
@svg = d3.select("#contributors-master").append("svg")
|
||||||
|
.attr("width", @width + @MARGIN.left + @MARGIN.right)
|
||||||
|
.attr("height", @height + @MARGIN.top + @MARGIN.bottom)
|
||||||
|
.attr("class", "tint-box")
|
||||||
|
.append("g")
|
||||||
|
.attr("transform", "translate(" + @MARGIN.left + "," + @MARGIN.top + ")")
|
||||||
|
create_area: (x, y) ->
|
||||||
|
@area = d3.svg.area().x((d) ->
|
||||||
|
x(d.date)
|
||||||
|
).y0(@height).y1((d) ->
|
||||||
|
xa = d.commits = d.commits ? d.additions ? d.deletions
|
||||||
|
y(xa)
|
||||||
|
).interpolate("basis")
|
||||||
|
create_brush: ->
|
||||||
|
@brush = d3.svg.brush().x(@x).on("brushend", @update_content)
|
||||||
|
draw_path: (data) ->
|
||||||
|
@svg.append("path").datum(data).attr("class", "area").attr("d", @area)
|
||||||
|
add_brush: ->
|
||||||
|
@svg.append("g").attr("class", "selection").call(@brush).selectAll("rect").attr("height", @height)
|
||||||
|
update_content: =>
|
||||||
|
ContributorsGraph.set_x_domain(if @brush.empty() then @x_max_domain else @brush.extent())
|
||||||
|
$("#brush_change").trigger('change')
|
||||||
|
draw: ->
|
||||||
|
@process_dates(@data)
|
||||||
|
@create_scale()
|
||||||
|
@create_axes()
|
||||||
|
ContributorsGraph.init_domain(@data)
|
||||||
|
@x_max_domain = @x_domain
|
||||||
|
@set_domain()
|
||||||
|
@create_area(@x, @y)
|
||||||
|
@create_svg()
|
||||||
|
@create_brush()
|
||||||
|
@draw_path(@data)
|
||||||
|
@draw_x_axis()
|
||||||
|
@draw_y_axis()
|
||||||
|
@add_brush()
|
||||||
|
redraw: ->
|
||||||
|
@process_dates(@data)
|
||||||
|
ContributorsGraph.set_y_domain(@data)
|
||||||
|
@set_y_domain()
|
||||||
|
@svg.select("path").datum(@data)
|
||||||
|
@svg.select("path").attr("d", @area)
|
||||||
|
@svg.select(".y.axis").call(@y_axis)
|
||||||
|
|
||||||
|
class window.ContributorsAuthorGraph extends ContributorsGraph
|
||||||
|
constructor: (@data) ->
|
||||||
|
@width = $('.container').width()/2 - 100
|
||||||
|
@height = 200
|
||||||
|
@x = null
|
||||||
|
@y = null
|
||||||
|
@x_axis = null
|
||||||
|
@y_axis = null
|
||||||
|
@area = null
|
||||||
|
@svg = null
|
||||||
|
@list_item = null
|
||||||
|
create_scale: ->
|
||||||
|
super @width, @height
|
||||||
|
create_axes: ->
|
||||||
|
@x_axis = d3.svg.axis().scale(@x).orient("bottom").ticks(8)
|
||||||
|
@y_axis = d3.svg.axis().scale(@y).orient("left").ticks(5)
|
||||||
|
create_area: (x, y) ->
|
||||||
|
@area = d3.svg.area().x((d) ->
|
||||||
|
parseDate = d3.time.format("%Y-%m-%d").parse
|
||||||
|
x(parseDate(d))
|
||||||
|
).y0(@height).y1((d) =>
|
||||||
|
if @data[d]? then y(@data[d]) else y(0)
|
||||||
|
).interpolate("basis")
|
||||||
|
create_svg: ->
|
||||||
|
@list_item = d3.selectAll(".person")[0].pop()
|
||||||
|
@svg = d3.select(@list_item).append("svg")
|
||||||
|
.attr("width", @width + @MARGIN.left + @MARGIN.right)
|
||||||
|
.attr("height", @height + @MARGIN.top + @MARGIN.bottom)
|
||||||
|
.attr("class", "spark")
|
||||||
|
.append("g")
|
||||||
|
.attr("transform", "translate(" + @MARGIN.left + "," + @MARGIN.top + ")")
|
||||||
|
draw_path: (data) ->
|
||||||
|
@svg.append("path").datum(data).attr("class", "area-contributor").attr("d", @area)
|
||||||
|
draw: ->
|
||||||
|
@create_scale()
|
||||||
|
@create_axes()
|
||||||
|
@set_domain()
|
||||||
|
@create_area(@x, @y)
|
||||||
|
@create_svg()
|
||||||
|
@draw_path(@dates)
|
||||||
|
@draw_x_axis()
|
||||||
|
@draw_y_axis()
|
||||||
|
redraw: ->
|
||||||
|
@set_domain()
|
||||||
|
@svg.select("path").datum(@dates)
|
||||||
|
@svg.select("path").attr("d", @area)
|
||||||
|
@svg.select(".x.axis").call(@x_axis)
|
||||||
|
@svg.select(".y.axis").call(@y_axis)
|
|
@ -0,0 +1,93 @@
|
||||||
|
window.ContributorsStatGraphUtil =
|
||||||
|
parse_log: (log) ->
|
||||||
|
total = {}
|
||||||
|
by_author = {}
|
||||||
|
for entry in log
|
||||||
|
@add_date(entry.date, total) unless total[entry.date]?
|
||||||
|
@add_author(entry, by_author) unless by_author[entry.author_name]?
|
||||||
|
@add_date(entry.date, by_author[entry.author_name]) unless by_author[entry.author_name][entry.date]
|
||||||
|
@store_data(entry, total[entry.date], by_author[entry.author_name][entry.date])
|
||||||
|
total = _.toArray(total)
|
||||||
|
by_author = _.toArray(by_author)
|
||||||
|
total: total, by_author: by_author
|
||||||
|
|
||||||
|
add_date: (date, collection) ->
|
||||||
|
collection[date] = {}
|
||||||
|
collection[date].date = date
|
||||||
|
|
||||||
|
add_author: (author, by_author) ->
|
||||||
|
by_author[author.author_name] = {}
|
||||||
|
by_author[author.author_name].author_name = author.author_name
|
||||||
|
by_author[author.author_name].author_email = author.author_email
|
||||||
|
|
||||||
|
store_data: (entry, total, by_author) ->
|
||||||
|
@store_commits(total, by_author)
|
||||||
|
@store_additions(entry, total, by_author)
|
||||||
|
@store_deletions(entry, total, by_author)
|
||||||
|
|
||||||
|
store_commits: (total, by_author) ->
|
||||||
|
@add(total, "commits", 1)
|
||||||
|
@add(by_author, "commits", 1)
|
||||||
|
|
||||||
|
add: (collection, field, value) ->
|
||||||
|
collection[field] ?= 0
|
||||||
|
collection[field] += value
|
||||||
|
|
||||||
|
store_additions: (entry, total, by_author) ->
|
||||||
|
entry.additions ?= 0
|
||||||
|
@add(total, "additions", entry.additions)
|
||||||
|
@add(by_author, "additions", entry.additions)
|
||||||
|
|
||||||
|
store_deletions: (entry, total, by_author) ->
|
||||||
|
entry.deletions ?= 0
|
||||||
|
@add(total, "deletions", entry.deletions)
|
||||||
|
@add(by_author, "deletions", entry.deletions)
|
||||||
|
|
||||||
|
get_total_data: (parsed_log, field) ->
|
||||||
|
log = parsed_log.total
|
||||||
|
total_data = @pick_field(log, field)
|
||||||
|
_.sortBy(total_data, (d) ->
|
||||||
|
d.date
|
||||||
|
)
|
||||||
|
pick_field: (log, field) ->
|
||||||
|
total_data = []
|
||||||
|
_.each(log, (d) ->
|
||||||
|
total_data.push(_.pick(d, [field, 'date']))
|
||||||
|
)
|
||||||
|
total_data
|
||||||
|
|
||||||
|
get_author_data: (parsed_log, field, date_range = null) ->
|
||||||
|
log = parsed_log.by_author
|
||||||
|
author_data = []
|
||||||
|
|
||||||
|
_.each(log, (log_entry) =>
|
||||||
|
parsed_log_entry = @parse_log_entry(log_entry, field, date_range)
|
||||||
|
if not _.isEmpty(parsed_log_entry.dates)
|
||||||
|
author_data.push(parsed_log_entry)
|
||||||
|
)
|
||||||
|
|
||||||
|
_.sortBy(author_data, (d) ->
|
||||||
|
d[field]
|
||||||
|
).reverse()
|
||||||
|
|
||||||
|
parse_log_entry: (log_entry, field, date_range) ->
|
||||||
|
parsed_entry = {}
|
||||||
|
parsed_entry.author_name = log_entry.author_name
|
||||||
|
parsed_entry.author_email = log_entry.author_email
|
||||||
|
parsed_entry.dates = {}
|
||||||
|
parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0
|
||||||
|
_.each(_.omit(log_entry, 'author_name', 'author_email'), (value, key) =>
|
||||||
|
if @in_range(value.date, date_range)
|
||||||
|
parsed_entry.dates[value.date] = value[field]
|
||||||
|
parsed_entry.commits += value.commits
|
||||||
|
parsed_entry.additions += value.additions
|
||||||
|
parsed_entry.deletions += value.deletions
|
||||||
|
)
|
||||||
|
return parsed_entry
|
||||||
|
|
||||||
|
in_range: (date, date_range) ->
|
||||||
|
if date_range is null || date_range[0] <= new Date(date) <= date_range[1]
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
|
6
app/assets/javascripts/team_members.js.coffee
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class TeamMembers
|
||||||
|
constructor: ->
|
||||||
|
$('.team-members .project-access-select').on "change", ->
|
||||||
|
$(this.form).submit()
|
||||||
|
|
||||||
|
@TeamMembers = TeamMembers
|