diff options
Diffstat (limited to 'doc/development')
121 files changed, 1682 insertions, 92 deletions
diff --git a/doc/development/README.md b/doc/development/README.md index bf1f054b7d5..6f2ca7b8590 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -14,7 +14,7 @@ contributing to documentation. - [SQL Migration Style Guide](migration_style_guide.md) for creating safe SQL migrations - [Testing standards and style guidelines](testing.md) -- [UI guide](ui_guide.md) for building GitLab with existing CSS styles and elements +- [UX guide](ux_guide/index.md) for building GitLab with existing CSS styles and elements - [Frontend guidelines](frontend.md) - [SQL guidelines](sql.md) for working with SQL queries - [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers @@ -22,6 +22,7 @@ ## Process - [Generate a changelog entry with `bin/changelog`](changelog.md) +- [Limit conflicts with EE when developing on CE](limit_ee_conflicts.md) - [Code review guidelines](code_review.md) for reviewing code and having code reviewed. - [Merge request performance guidelines](merge_request_performance_guidelines.md) for ensuring merge requests do not negatively impact GitLab performance @@ -37,6 +38,7 @@ - [Rake tasks](rake_tasks.md) for development - [Shell commands](shell_commands.md) in the GitLab codebase - [Sidekiq debugging](sidekiq_debugging.md) +- [Object state models](object_state_models.md) ## Databases diff --git a/doc/development/architecture.md b/doc/development/architecture.md index 33fd50f4c11..4eb7a8eee48 100644 --- a/doc/development/architecture.md +++ b/doc/development/architecture.md @@ -6,7 +6,7 @@ There are two editions of GitLab: [Enterprise Edition](https://about.gitlab.com/ EE releases are available not long after CE releases. To obtain the GitLab EE there is a [repository at gitlab.com](https://gitlab.com/subscribers/gitlab-ee). For more information about the release process see the section 'New versions and upgrading' in the readme. -Both EE and CE require an add-on component called gitlab-shell. It is obtained from the [gitlab-shell repository](https://gitlab.com/gitlab-org/gitlab-shell/tree/master). New versions are usually tags but staying on the master branch will give you the latest stable version. New releases are generally around the same time as GitLab CE releases with exception for informal security updates deemed critical. +Both EE and CE require some add-on components called gitlab-shell and Gitaly. These components are available from the [gitlab-shell](https://gitlab.com/gitlab-org/gitlab-shell/tree/master) and [gitaly](https://gitlab.com/gitlab-org/gitaly/tree/master) repositories respectively. New versions are usually tags but staying on the master branch will give you the latest stable version. New releases are generally around the same time as GitLab CE releases with exception for informal security updates deemed critical. ## Physical office analogy @@ -35,8 +35,10 @@ Their job description: - make tasks for Sidekiq; - fetch stuff from the warehouse or move things around in there; -**Gitlab-shell** is a third kind of worker that takes orders from a fax machine (SSH) instead of the front desk (HTTP). -Gitlab-shell communicates with Sidekiq via the “communication board” (Redis), and asks quick questions of the Unicorn workers either directly or via the front desk. +**GitLab-shell** is a third kind of worker that takes orders from a fax machine (SSH) instead of the front desk (HTTP). +GitLab-shell communicates with Sidekiq via the “communication board” (Redis), and asks quick questions of the Unicorn workers either directly or via the front desk. + +**Gitaly** is a back desk that is specialized on reaching the disks to perform git operations efficiently and keep a copy of the result of costly operations. All git operations go through Gitaly. **GitLab Enterprise Edition (the application)** is the collection of processes and business practices that the office is run by. @@ -53,7 +55,7 @@ To serve repositories over SSH there's an add-on application called gitlab-shell ### Components ![GitLab Diagram Overview](gitlab_architecture_diagram.png) - + _[edit diagram (for GitLab team members only)](https://docs.google.com/drawings/d/1fBzAyklyveF-i-2q-OHUIqDkYfjjxC4mq5shwKSZHLs/edit)_ A typical install of GitLab will be on GNU/Linux. It uses Nginx or Apache as a web front end to proxypass the Unicorn web server. By default, communication between Unicorn and the front end is via a Unix domain socket but forwarding requests via TCP is also supported. The web front end accesses `/home/git/gitlab/public` bypassing the Unicorn server to serve static pages, uploads (e.g. avatar images or attachments), and precompiled assets. GitLab serves web pages and a [GitLab API](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/api) using the Unicorn web server. It uses Sidekiq as a job queue which, in turn, uses redis as a non-persistent database backend for job information, meta data, and incoming jobs. @@ -62,7 +64,9 @@ The GitLab web app uses MySQL or PostgreSQL for persistent database information When serving repositories over HTTP/HTTPS GitLab utilizes the GitLab API to resolve authorization and access as well as serving git objects. -The add-on component gitlab-shell serves repositories over SSH. It manages the SSH keys within `/home/git/.ssh/authorized_keys` which should not be manually edited. gitlab-shell accesses the bare repositories directly to serve git objects and communicates with redis to submit jobs to Sidekiq for GitLab to process. gitlab-shell queries the GitLab API to determine authorization and access. +The add-on component gitlab-shell serves repositories over SSH. It manages the SSH keys within `/home/git/.ssh/authorized_keys` which should not be manually edited. gitlab-shell accesses the bare repositories through Gitaly to serve git objects and communicates with redis to submit jobs to Sidekiq for GitLab to process. gitlab-shell queries the GitLab API to determine authorization and access. + +Gitaly executes git operations from gitlab-shell and Workhorse, and provides an API to the GitLab web app to get attributes from git (e.g. title, branches, tags, other meta data), and to get blobs (e.g. diffs, commits, files) ### Installation Folder Summary diff --git a/doc/development/changelog.md b/doc/development/changelog.md index 6a97fae9cac..c71858c6a24 100644 --- a/doc/development/changelog.md +++ b/doc/development/changelog.md @@ -40,6 +40,15 @@ Its simplest usage is to provide the value for `title`: ```text $ bin/changelog 'Hey DZ, I added a feature to GitLab!' +``` + +The entry filename is based on the name of the current Git branch. If you run +the command above on a branch called `feature/hey-dz`, it will generate a +`changelogs/unreleased/feature-hey-dz.yml` file. + +The command will output the path of the generated file and its contents: + +```text create changelogs/unreleased/my-feature.yml --- title: Hey DZ, I added a feature to GitLab! @@ -47,10 +56,6 @@ merge_request: author: ``` -The entry filename is based on the name of the current Git branch. If you run -the command above on a branch called `feature/hey-dz`, it will generate a -`changelogs/unreleased/feature-hey-dz.yml` file. - ### Arguments | Argument | Shorthand | Purpose | @@ -139,7 +144,7 @@ Use the **`--git-username`** or **`-u`** argument to automatically fill in the $ git config user.name Jane Doe -$ bin/changelog --u 'Hey DZ, I added a feature to GitLab!' +$ bin/changelog -u 'Hey DZ, I added a feature to GitLab!' create changelogs/unreleased/feature-hey-dz.yml --- title: Hey DZ, I added a feature to GitLab! diff --git a/doc/development/code_review.md b/doc/development/code_review.md index c5c23b5c0b8..e4a0e0b92bc 100644 --- a/doc/development/code_review.md +++ b/doc/development/code_review.md @@ -9,7 +9,7 @@ code is effective, understandable, and maintainable. Any developer can, and is encouraged to, perform code review on merge requests of colleagues and contributors. However, the final decision to accept a merge -request is up to one of our merge request "endbosses", denoted on the +request is up to one the project's maintainers, denoted on the [team page](https://about.gitlab.com/team). ## Everyone @@ -70,10 +70,36 @@ experience, refactors the existing code). Then: - After a round of line notes, it can be helpful to post a summary note such as "LGTM :thumbsup:", or "Just a couple things to address." - Avoid accepting a merge request before the build succeeds. Of course, "Merge - When Build Succeeds" (MWBS) is fine. -- If you set the MR to "Merge When Build Succeeds", you should take over + When Pipeline Succeeds" (MWPS) is fine. +- If you set the MR to "Merge When Pipeline Succeeds", you should take over subsequent revisions for anything that would be spotted after that. +## The right balance + +One of the most difficult things during code review is finding the right +balance in how deep the reviewer can interfere with the code created by a +reviewee. + +- Learning how to find the right balance takes time; that is why we have + reviewers that become maintainers after some time spent on reviewing merge + requests. +- Finding bugs and improving code style is important, but thinking about good + design is important as well. Building abstractions and good design is what + makes it possible to hide complexity and makes future changes easier. +- Asking the reviewee to change the design sometimes means the complete rewrite + of the contributed code. It's usually a good idea to ask another maintainer or + reviewer before doing it, but have the courage to do it when you believe it is + important. +- There is a difference in doing things right and doing things right now. + Ideally, we should do the former, but in the real world we need the latter as + well. A good example is a security fix which should be released as soon as + possible. Asking the reviewee to do the major refactoring in the merge + request that is an urgent fix should be avoided. +- Doing things well today is usually better than doing something perfectly + tomorrow. Shipping a kludge today is usually worse than doing something well + tomorrow. When you are not able to find the right balance, ask other people + about their opinion. + ## Credits Largely based on the [thoughtbot code review guide]. diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md index b137e6ae82e..fc948a7a116 100644 --- a/doc/development/doc_styleguide.md +++ b/doc/development/doc_styleguide.md @@ -113,6 +113,77 @@ merge request. add an alternative text: `[identifier]: https://example.com "Alternative text"` that appears when hovering your mouse on a link +### Linking to inline docs + +Sometimes it's needed to link to the built-in documentation that GitLab provides +under `/help`. This is normally done in files inside the `app/views/` directory +with the help of the `help_page_path` helper method. + +In its simplest form, the HAML code to generate a link to the `/help` page is: + +```haml += link_to 'Help page', help_page_path('user/permissions') +``` + +The `help_page_path` contains the path to the document you want to link to with +the following conventions: + +- it is relative to the `doc/` directory in the GitLab repository +- the `.md` extension must be omitted +- it must not end with a slash (`/`) + +Below are some special cases where should be used depending on the context. +You can combine one or more of the following: + +1. **Linking to an anchor link.** Use `anchor` as part of the `help_page_path` + method: + + ```haml + = link_to 'Help page', help_page_path('user/permissions', anchor: 'anchor-link') + ``` + +1. **Opening links in a new tab.** This should be the default behavior: + + ```haml + = link_to 'Help page', help_page_path('user/permissions'), target: '_blank' + ``` + +1. **Linking to a circle icon.** Usually used in settings where a long + description cannot be used, like near checkboxes. You can basically use + any font awesome icon, but prefer the `question-circle`: + + ```haml + = link_to icon('question-circle'), help_page_path('user/permissions') + ``` + +1. **Using a button link.** Useful in places where text would be out of context + with the rest of the page layout: + + ```haml + = link_to 'Help page', help_page_path('user/permissions'), class: 'btn btn-info' + ``` + +1. **Underlining a link.** + + ```haml + = link_to 'Help page', help_page_path('user/permissions'), class: 'underlined-link' + ``` + +1. **Using links inline of some text.** + + ```haml + Description to #{link_to 'Help page', help_page_path('user/permissions')}. + ``` + +1. **Adding a period at the end of the sentence.** Useful when you don't want + the period to be part of the link: + + ```haml + = succeed '.' do + Learn more in the + = link_to 'Help page', help_page_path('user/permissions') + ``` + ## Images - Place images in a separate directory named `img/` in the same directory where diff --git a/doc/development/frontend.md b/doc/development/frontend.md index ec8f2d6531c..f79bd23dc90 100644 --- a/doc/development/frontend.md +++ b/doc/development/frontend.md @@ -205,6 +205,57 @@ command line. Please note: Not all of the frontend fixtures are generated. Some are still static files. These will not be touched by `rake teaspoon:fixtures`. +## Design Patterns + +### Singletons + +When exactly one object is needed for a given task, prefer to define it as a +`class` rather than as an object literal. Prefer also to explicitly restrict +instantiation, unless flexibility is important (e.g. for testing). + +``` +// bad + +gl.MyThing = { + prop1: 'hello', + method1: () => {} +}; + +// good + +class MyThing { + constructor() { + this.prop1 = 'hello'; + } + method1() {} +} + +gl.MyThing = new MyThing(); + +// best + +let singleton; + +class MyThing { + constructor() { + if (!singleton) { + singleton = this; + singleton.init(); + } + return singleton; + } + + init() { + this.prop1 = 'hello'; + } + + method1() {} +} + +gl.MyThing = MyThing; + +``` + ## Supported browsers For our currently-supported browsers, see our [requirements][requirements]. @@ -246,16 +297,74 @@ For our currently-supported browsers, see our [requirements][requirements]. ## Gotchas -### Phantom.JS (used by Teaspoon & Rspec) chokes, returning vague JavaScript errors - -If you see very generic JavaScript errors (e.g. `jQuery is undefined`) being thrown in tests, but -can't reproduce them manually, you may have included `ES6`-style JavaScript in files that don't -have the `.js.es6` file extension. Either use ES5-friendly JavaScript or rename the file you're -working in (`git mv <file.js> <file.js.es6>`). - -Similar errors will be thrown if you're using -any of the [array methods introduced in ES6](http://www.2ality.com/2014/05/es6-array-methods.html) -whether or not you've updated the file extension. +### Spec errors due to use of ES6 features in `.js` files + +If you see very generic JavaScript errors (e.g. `jQuery is undefined`) being +thrown in Teaspoon, Spinach, or Rspec tests but can't reproduce them manually, +you may have included `ES6`-style JavaScript in files that don't have the +`.js.es6` file extension. Either use ES5-friendly JavaScript or rename the file +you're working in (`git mv <file.js> <file.js.es6>`). + +### Spec errors due to use of unsupported JavaScript + +Similar errors will be thrown if you're using JavaScript features not yet +supported by our test runner's version of webkit, whether or not you've updated +the file extension. Examples of unsupported JavaScript features are: + +- Array.from +- Array.find +- Array.first +- Object.assign +- Async functions +- Generators +- Array destructuring +- For Of +- Symbol/Symbol.iterator +- Spread + +Until these are polyfilled or transpiled appropriately, they should not be used. +Please update this list with additional unsupported features or when any of +these are made usable. + +### Spec errors due to JavaScript not enabled + +If, as a result of a change you've made, a feature now depends on JavaScript to +run correctly, you need to make sure a JavaScript web driver is enabled when +specs are run. If you don't you'll see vague error messages from the spec +runner, and an explosion of vague console errors in the HTML snapshot. + +To enable a JavaScript driver in an `rspec` test, add `js: true` to the +individual spec or the context block containing multiple specs that need +JavaScript enabled: + +```ruby + +# For one spec +it 'presents information about abuse report', js: true do + # assertions... +end + +describe "Admin::AbuseReports", js: true do + it 'presents information about abuse report' do + # assertions... + end + it 'shows buttons for adding to abuse report' do + # assertions... + end +end +``` +In Spinach, the JavaScript driver is enabled differently. In the `*.feature` +file for the failing spec, add the `@javascript` flag above the Scenario: +``` +@javascript +Scenario: Developer can approve merge request + Given I am a "Shop" developer + And I visit project "Shop" merge requests page + And merge request 'Bug NS-04' must be approved + And I click link "Bug NS-04" + When I click link "Approve" + Then I should see approved merge request "Bug NS-04" +``` diff --git a/doc/development/gitlab_architecture_diagram.png b/doc/development/gitlab_architecture_diagram.png Binary files differindex 80e975718e0..378f7384574 100644 --- a/doc/development/gitlab_architecture_diagram.png +++ b/doc/development/gitlab_architecture_diagram.png diff --git a/doc/development/gotchas.md b/doc/development/gotchas.md index b25ce79e89f..0f78e8238af 100644 --- a/doc/development/gotchas.md +++ b/doc/development/gotchas.md @@ -32,71 +32,112 @@ spec/models/user_spec.rb|6 error| Failure/Error: u = described_class.new NoMeth Except for the top-level `describe` block, always provide a String argument to `describe`. -## Don't `rescue Exception` +## Don't assert against the absolute value of a sequence-generated attribute -See ["Why is it bad style to `rescue Exception => e` in Ruby?"][Exception]. +Consider the following factory: -_**Note:** This rule is [enforced automatically by -Rubocop](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-4-stable/.rubocop.yml#L911-914)._ +```ruby +FactoryGirl.define do + factory :label do + sequence(:title) { |n| "label#{n}" } + end +end +``` -[Exception]: http://stackoverflow.com/q/10048173/223897 +Consider the following API spec: -## Don't use inline JavaScript in views +```ruby +require 'rails_helper' -Using the inline `:javascript` Haml filters comes with a -performance overhead. Using inline JavaScript is not a good way to structure your code and should be avoided. +describe API::Labels do + it 'creates a first label' do + create(:label) -_**Note:** We've [removed these two filters](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/initializers/hamlit.rb) -in an initializer._ - -### Further reading + get api("/projects/#{project.id}/labels", user) -- Stack Overflow: [Why you should not write inline JavaScript](http://programmers.stackexchange.com/questions/86589/why-should-i-avoid-inline-scripting) + expect(response).to have_http_status(200) + expect(json_response.first['name']).to eq('label1') + end -## ID-based CSS selectors need to be a bit more specific + it 'creates a second label' do + create(:label) -Normally, because HTML `id` attributes need to be unique to the page, it's -perfectly fine to write some JavaScript like the following: + get api("/projects/#{project.id}/labels", user) -```javascript -$('#js-my-selector').hide(); + expect(response).to have_http_status(200) + expect(json_response.first['name']).to eq('label1') + end +end ``` -However, there's a feature of GitLab's Markdown processing that [automatically -adds anchors to header elements][ToC Processing], with the `id` attribute being -automatically generated based on the content of the header. - -Unfortunately, this feature makes it possible for user-generated content to -create a header element with the same `id` attribute we're using in our -selector, potentially breaking the JavaScript behavior. A user could break the -above example with the following Markdown: +When run, this spec doesn't do what we might expect: -```markdown -## JS My Selector -``` +```sh +1) API::API reproduce sequence issue creates a second label + Failure/Error: expect(json_response.first['name']).to eq('label1') -Which gets converted to the following HTML: + expected: "label1" + got: "label2" -```html -<h2> - <a id="js-my-selector" class="anchor" href="#js-my-selector" aria-hidden="true"></a> - JS My Selector -</h2> + (compared using ==) ``` -[ToC Processing]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-4-stable/lib/banzai/filter/table_of_contents_filter.rb#L31-37 +That's because FactoryGirl sequences are not reseted for each example. + +Please remember that sequence-generated values exist only to avoid having to +explicitly set attributes that have a uniqueness constraint when using a factory. ### Solution -The current recommended fix for this is to make our selectors slightly more -specific: +If you assert against a sequence-generated attribute's value, you should set it +explicitly. Also, the value you set shouldn't match the sequence pattern. + +For instance, using our `:label` factory, writing `create(:label, title: 'foo')` +is ok, but `create(:label, title: 'label1')` is not. + +Following is the fixed API spec: -```javascript -$('div#js-my-selector').hide(); +```ruby +require 'rails_helper' + +describe API::Labels do + it 'creates a first label' do + create(:label, title: 'foo') + + get api("/projects/#{project.id}/labels", user) + + expect(response).to have_http_status(200) + expect(json_response.first['name']).to eq('foo') + end + + it 'creates a second label' do + create(:label, title: 'bar') + + get api("/projects/#{project.id}/labels", user) + + expect(response).to have_http_status(200) + expect(json_response.first['name']).to eq('bar') + end +end ``` +## Don't `rescue Exception` + +See ["Why is it bad style to `rescue Exception => e` in Ruby?"][Exception]. + +_**Note:** This rule is [enforced automatically by +Rubocop](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-4-stable/.rubocop.yml#L911-914)._ + +[Exception]: http://stackoverflow.com/q/10048173/223897 + +## Don't use inline JavaScript in views + +Using the inline `:javascript` Haml filters comes with a +performance overhead. Using inline JavaScript is not a good way to structure your code and should be avoided. + +_**Note:** We've [removed these two filters](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/initializers/hamlit.rb) +in an initializer._ + ### Further reading -- Issue: [Merge request ToC anchor conflicts with tabs](https://gitlab.com/gitlab-org/gitlab-ce/issues/3908) -- Merge Request: [Make tab target selectors less naive](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2023) -- Merge Request: [Make cross-project reference's clipboard target less naive](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2024) +- Stack Overflow: [Why you should not write inline JavaScript](http://programmers.stackexchange.com/questions/86589/why-should-i-avoid-inline-scripting) diff --git a/doc/development/img/state-model-issue.png b/doc/development/img/state-model-issue.png Binary files differnew file mode 100644 index 00000000000..ee33b6886c6 --- /dev/null +++ b/doc/development/img/state-model-issue.png diff --git a/doc/development/img/state-model-legend.png b/doc/development/img/state-model-legend.png Binary files differnew file mode 100644 index 00000000000..1c121f2588c --- /dev/null +++ b/doc/development/img/state-model-legend.png diff --git a/doc/development/img/state-model-merge-request.png b/doc/development/img/state-model-merge-request.png Binary files differnew file mode 100644 index 00000000000..e00da10cac2 --- /dev/null +++ b/doc/development/img/state-model-merge-request.png diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md index 105e2f1242a..b8669964c84 100644 --- a/doc/development/instrumentation.md +++ b/doc/development/instrumentation.md @@ -24,7 +24,7 @@ namespace you can use the `configure` class method. This method simply yields the supplied block while passing `Gitlab::Metrics::Instrumentation` as its argument. An example: -``` +```ruby Gitlab::Metrics::Instrumentation.configure do |conf| conf.instrument_method(Foo, :bar) conf.instrument_method(Foo, :baz) @@ -41,7 +41,7 @@ Method instrumentation should be added in the initializer Instrumenting a single method: -``` +```ruby Gitlab::Metrics::Instrumentation.configure do |conf| conf.instrument_method(User, :find_by) end @@ -49,7 +49,7 @@ end Instrumenting an entire class hierarchy: -``` +```ruby Gitlab::Metrics::Instrumentation.configure do |conf| conf.instrument_class_hierarchy(ActiveRecord::Base) end @@ -57,7 +57,7 @@ end Instrumenting all public class methods: -``` +```ruby Gitlab::Metrics::Instrumentation.configure do |conf| conf.instrument_methods(User) end @@ -68,7 +68,7 @@ end The easiest way to check if a method has been instrumented is to check its source location. For example: -``` +```ruby method = Rugged::TagCollection.instance_method(:[]) method.source_location diff --git a/doc/development/limit_ee_conflicts.md b/doc/development/limit_ee_conflicts.md new file mode 100644 index 00000000000..568dedf1669 --- /dev/null +++ b/doc/development/limit_ee_conflicts.md @@ -0,0 +1,325 @@ +# Limit conflicts with EE when developing on CE + +This guide contains best-practices for avoiding conflicts between CE and EE. + +## Context + +Usually, GitLab Community Edition is merged into the Enterprise Edition once a +week. During these merges, it's very common to get conflicts when some changes +in CE do not apply cleanly to EE. + +There are a few things that can help you as a developer to: + +- know when your merge request to CE will conflict when merged to EE +- avoid such conflicts in the first place +- ease future conflict resolutions if conflict is inevitable + +## Check the `rake ee_compat_check` in your merge requests + +For each commit (except on `master`), the `rake ee_compat_check` CI job tries to +detect if the current branch's changes will conflict during the CE->EE merge. + +The job reports what files are conflicting and how to setup a merge request +against EE. Here is roughly how it works: + +1. Generates the diff between your branch and current CE `master` +1. Tries to apply it to current EE `master` +1. If it applies cleanly, the job succeeds, otherwise... +1. Detects a branch with the `-ee` suffix in EE +1. If it exists, generate the diff between this branch and current EE `master` +1. Tries to apply it to current EE `master` +1. If it applies cleanly, the job succeeds + +In the case where the job fails, it means you should create a `<ce_branch>-ee` +branch, push it to EE and open a merge request against EE `master`. At this +point if you retry the failing job in your CE merge request, it should now pass. + +Notes: + +- This task is not a silver-bullet, its current goal is to bring awareness to + developers that their work needs to be ported to EE. +- Community contributors shouldn't submit merge requests against EE, but + reviewers should take actions by either creating such EE merge request or + asking a GitLab developer to do it once the merge request is merged. +- If you branch is more than 500 commits behind `master`, the job will fail and + you should rebase your branch upon latest `master`. + +## Possible type of conflicts + +### Controllers + +#### List or arrays are augmented in EE + +In controllers, the most common type of conflict is with `before_action` that +has a list of actions in CE but EE adds some actions to that list. + +The same problem often occurs for `params.require` / `params.permit` calls. + +##### Mitigations + +Separate CE and EE actions/keywords. For instance for `params.require` in +`ProjectsController`: + +```ruby +def project_params + params.require(:project).permit(project_params_ce) + # On EE, this is always: + # params.require(:project).permit(project_params_ce << project_params_ee) +end + +# Always returns an array of symbols, created however best fits the use case. +# It _should_ be sorted alphabetically. +def project_params_ce + %i[ + description + name + path + ] +end + +# (On EE) +def project_params_ee + %i[ + approvals_before_merge + approver_group_ids + approver_ids + ... + ] +end +``` + +#### Additional condition(s) in EE + +For instance for LDAP: + +```diff + def destroy + @key = current_user.keys.find(params[:id]) + - @key.destroy + + @key.destroy unless @key.is_a? LDAPKey + + respond_to do |format| +``` + +Or for Geo: + +```diff +def after_sign_out_path_for(resource) +- current_application_settings.after_sign_out_path.presence || new_user_session_path ++ if Gitlab::Geo.secondary? ++ Gitlab::Geo.primary_node.oauth_logout_url(@geo_logout_state) ++ else ++ current_application_settings.after_sign_out_path.presence || new_user_session_path ++ end +end +``` + +Or even for audit log: + +```diff +def approve_access_request +- Members::ApproveAccessRequestService.new(membershipable, current_user, params).execute ++ member = Members::ApproveAccessRequestService.new(membershipable, current_user, params).execute ++ ++ log_audit_event(member, action: :create) + + redirect_to polymorphic_url([membershipable, :members]) +end +``` + +### Views + +#### Additional view code in EE + +A block of code added in CE conflicts because there is already another block +at the same place in EE + +##### Mitigations + +Blocks of code that are EE-specific should be moved to partials as much as +possible to avoid conflicts with big chunks of HAML code that that are not fun +to resolve when you add the indentation to the equation. + +For instance this kind of thing: + +```haml +.form-group.detail-page-description + = form.label :description, 'Description', class: 'control-label' + .col-sm-10 + = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do + = render 'projects/zen', f: form, attr: :description, + classes: 'note-textarea', + placeholder: "Write a comment or drag your files here...", + supports_slash_commands: !issuable.persisted? + = render 'projects/notes/hints', supports_slash_commands: !issuable.persisted? + .clearfix + .error-alert +- if issuable.is_a?(Issue) + .form-group + .col-sm-offset-2.col-sm-10 + .checkbox + = form.label :confidential do + = form.check_box :confidential + This issue is confidential and should only be visible to team members with at least Reporter access. +- if can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project) + - has_due_date = issuable.has_attribute?(:due_date) + %hr + .row + %div{ class: (has_due_date ? "col-lg-6" : "col-sm-12") } + .form-group.issue-assignee + = form.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}" + .col-sm-10{ class: ("col-lg-8" if has_due_date) } + .issuable-form-select-holder + - if issuable.assignee_id + = form.hidden_field :assignee_id + = dropdown_tag(user_dropdown_label(issuable.assignee_id, "Assignee"), options: { toggle_class: "js-dropdown-keep-input js-user-search js-issuable-form-dropdown js-assignee-search", title: "Select assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit", + placeholder: "Search assignee", data: { first_user: current_user.try(:username), null_user: true, current_user: true, project_id: project.try(:id), selected: issuable.assignee_id, field_name: "#{issuable.class.model_name.param_key}[assignee_id]", default_label: "Assignee"} }) + .form-group.issue-milestone + = form.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}" + .col-sm-10{ class: ("col-lg-8" if has_due_date) } + .issuable-form-select-holder + = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, extra_class: "js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone" + .form-group + - has_labels = @labels && @labels.any? + = form.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}" + = form.hidden_field :label_ids, multiple: true, value: '' + .col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" } + .issuable-form-select-holder + = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label" + - if issuable.respond_to?(:weight) + - weight_options = Issue.weight_options + - weight_options.delete(Issue::WEIGHT_ALL) + - weight_options.delete(Issue::WEIGHT_ANY) + .form-group + = form.label :label_ids, class: "control-label #{"col-lg-4" if has_due_date}" do + Weight + .col-sm-10{ class: ("col-lg-8" if has_due_date) } + .issuable-form-select-holder + - if issuable.weight + = form.hidden_field :weight + = dropdown_tag(issuable.weight || "Weight", options: { title: "Select weight", toggle_class: 'js-weight-select js-issuable-form-weight', dropdown_class: "dropdown-menu-selectable dropdown-menu-weight", + placeholder: "Search weight", data: { field_name: "#{issuable.class.model_name.param_key}[weight]" , default_label: "Weight" } }) do + %ul + - weight_options.each do |weight| + %li + %a{href: "#", data: { id: weight, none: weight === Issue::WEIGHT_NONE }, class: ("is-active" if issuable.weight == weight)} + = weight + - if has_due_date + .col-lg-6 + .form-group + = form.label :due_date, "Due date", class: "control-label" + .col-sm-10 + .issuable-form-select-holder + = form.text_field :due_date, id: "issuable-due-date", class: "datepicker form-control", placeholder: "Select due date" +``` + +could be simplified by using partials: + +```haml += render 'shared/issuable/form/description', issuable: issuable, form: form + +- if issuable.respond_to?(:confidential) + .form-group + .col-sm-offset-2.col-sm-10 + .checkbox + = form.label :confidential do + = form.check_box :confidential + This issue is confidential and should only be visible to team members with at least Reporter access. + += render 'shared/issuable/form/metadata', issuable: issuable, form: form +``` + +and then the `app/views/shared/issuable/form/_metadata.html.haml` could be as follows: + +```haml +- issuable = local_assigns.fetch(:issuable) + +- return unless can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project) + +- has_due_date = issuable.has_attribute?(:due_date) +- has_labels = @labels && @labels.any? +- form = local_assigns.fetch(:form) + +%hr +.row + %div{ class: (has_due_date ? "col-lg-6" : "col-sm-12") } + .form-group.issue-assignee + = form.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}" + .col-sm-10{ class: ("col-lg-8" if has_due_date) } + .issuable-form-select-holder + - if issuable.assignee_id + = form.hidden_field :assignee_id + = dropdown_tag(user_dropdown_label(issuable.assignee_id, "Assignee"), options: { toggle_class: "js-dropdown-keep-input js-user-search js-issuable-form-dropdown js-assignee-search", title: "Select assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit", + placeholder: "Search assignee", data: { first_user: current_user.try(:username), null_user: true, current_user: true, project_id: issuable.project.try(:id), selected: issuable.assignee_id, field_name: "#{issuable.class.model_name.param_key}[assignee_id]", default_label: "Assignee"} }) + .form-group.issue-milestone + = form.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}" + .col-sm-10{ class: ("col-lg-8" if has_due_date) } + .issuable-form-select-holder + = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, extra_class: "js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone" + .form-group + - has_labels = @labels && @labels.any? + = form.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}" + = form.hidden_field :label_ids, multiple: true, value: '' + .col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" } + .issuable-form-select-holder + = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label" + + = render "shared/issuable/form/weight", issuable: issuable, form: form + + - if has_due_date + .col-lg-6 + .form-group + = form.label :due_date, "Due date", class: "control-label" + .col-sm-10 + .issuable-form-select-holder + = form.text_field :due_date, id: "issuable-due-date", class: "datepicker form-control", placeholder: "Select due date" +``` + +and then the `app/views/shared/issuable/form/_weight.html.haml` could be as follows: + +```haml +- issuable = local_assigns.fetch(:issuable) + +- return unless issuable.respond_to?(:weight) + +- has_due_date = issuable.has_attribute?(:due_date) +- form = local_assigns.fetch(:form) + +.form-group + = form.label :label_ids, class: "control-label #{"col-lg-4" if has_due_date}" do + Weight + .col-sm-10{ class: ("col-lg-8" if has_due_date) } + .issuable-form-select-holder + - if issuable.weight + = form.hidden_field :weight + + = weight_dropdown_tag(issuable, toggle_class: 'js-issuable-form-weight') do + %ul + - Issue.weight_options.each do |weight| + %li + %a{ href: '#', data: { id: weight, none: weight === Issue::WEIGHT_NONE }, class: ("is-active" if issuable.weight == weight) } + = weight +``` + +Note: + +- The safeguards at the top allow to get rid of an unneccessary indentation level +- Here we only moved the 'Weight' code to a partial since this is the only + EE-specific code in that view, so it's the most likely to conflict, but you + are encouraged to use partials even for code that's in CE to logically split + big views into several smaller files. + +#### Indentation issue + +Sometimes a code block is indented more or less in EE because there's an +additional condition. + +##### Mitigations + +Blocks of code that are EE-specific should be moved to partials as much as +possible to avoid conflicts with big chunks of HAML code that that are not fun +to resolve when you add the indentation in the equation. + +--- + +[Return to Development documentation](README.md) diff --git a/doc/development/merge_request_performance_guidelines.md b/doc/development/merge_request_performance_guidelines.md index 0363bf8c1d5..8232a0a113c 100644 --- a/doc/development/merge_request_performance_guidelines.md +++ b/doc/development/merge_request_performance_guidelines.md @@ -3,7 +3,7 @@ To ensure a merge request does not negatively impact performance of GitLab _every_ merge request **must** adhere to the guidelines outlined in this document. There are no exceptions to this rule unless specifically discussed -with and agreed upon by merge request endbosses and performance specialists. +with and agreed upon by backend maintainers and performance specialists. To measure the impact of a merge request you can use [Sherlock](profiling.md#sherlock). It's also highly recommended that you read @@ -40,9 +40,9 @@ section below for more information. about the impact. Sometimes it's hard to assess the impact of a merge request. In this case you -should ask one of the merge request (mini) endbosses to review your changes. You -can find a list of these endbosses at <https://about.gitlab.com/team/>. An -endboss in turn can request a performance specialist to review the changes. +should ask one of the merge request reviewers to review your changes. You can +find a list of these reviewers at <https://about.gitlab.com/team/>. A reviewer +in turn can request a performance specialist to review the changes. ## Query Counts diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md index 61b0fbc89c9..fd8335d251e 100644 --- a/doc/development/migration_style_guide.md +++ b/doc/development/migration_style_guide.md @@ -60,7 +60,7 @@ migration was tested. If you need to remove index, please add a condition like in following example: -``` +```ruby remove_index :namespaces, column: :name if index_exists?(:namespaces, :name) ``` @@ -75,7 +75,7 @@ need for downtime. To use this method you must disable transactions by calling the method `disable_ddl_transaction!` in the body of your migration class like so: -``` +```ruby class MyMigration < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers disable_ddl_transaction! @@ -96,7 +96,7 @@ the `up` and `down` methods in your migration class. For example, to add the column `foo` to the `projects` table with a default value of `10` you'd write the following: -``` +```ruby class MyMigration < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers disable_ddl_transaction! @@ -125,7 +125,7 @@ set the limit to 8-bytes. This will allow the column to hold a value up to Rails migration example: -``` +```ruby add_column_with_default(:projects, :foo, :integer, default: 10, limit: 8) # or @@ -145,7 +145,7 @@ Please prefer Arel and plain SQL over usual ActiveRecord syntax. In case of usin Example with Arel: -``` +```ruby users = Arel::Table.new(:users) users.group(users[:user_id]).having(users[:id].count.gt(5)) @@ -154,7 +154,7 @@ users.group(users[:user_id]).having(users[:id].count.gt(5)) Example with plain SQL and `quote_string` helper: -``` +```ruby select_all("SELECT name, COUNT(id) as cnt FROM tags GROUP BY name HAVING COUNT(id) > 1").each do |tag| tag_name = quote_string(tag["name"]) duplicate_ids = select_all("SELECT id FROM tags WHERE name = '#{tag_name}'").map{|tag| tag["id"]} diff --git a/doc/development/object_state_models.md b/doc/development/object_state_models.md new file mode 100644 index 00000000000..623bbf143ef --- /dev/null +++ b/doc/development/object_state_models.md @@ -0,0 +1,25 @@ +# Object state models + +## Diagrams + +[GitLab object state models](https://drive.google.com/drive/u/3/folders/0B5tDlHAM4iZINmpvYlJXcDVqMGc) + +--- + +## Legend + +![legend](img/state-model-legend.png) + +--- + +## Issue + +[`app/models/issue.rb`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/models/issue.rb) +![issue](img/state-model-issue.png) + +--- + +## Merge request + +[`app/models/merge_request.rb`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/models/merge_request.rb) +![merge request](img/state-model-merge-request.png)
\ No newline at end of file diff --git a/doc/development/performance.md b/doc/development/performance.md index 8337c2d9cb3..f936a49a2aa 100644 --- a/doc/development/performance.md +++ b/doc/development/performance.md @@ -37,7 +37,7 @@ graphs/dashboards. GitLab provides built-in tools to aid the process of improving performance: * [Sherlock](profiling.md#sherlock) -* [GitLab Performance Monitoring](../administration/monitoring/performance/monitoring.md) +* [GitLab Performance Monitoring](../administration/monitoring/performance/introduction.md) * [Request Profiling](../administration/monitoring/performance/request_profiling.md) GitLab employees can use GitLab.com's performance monitoring systems located at @@ -101,6 +101,116 @@ In short: 5. If you must write a benchmark use the benchmark-ips Gem instead of Ruby's `Benchmark` module. +## Profiling + +By collecting snapshots of process state at regular intervals, profiling allows +you to see where time is spent in a process. The [StackProf](https://github.com/tmm1/stackprof) +gem is included in GitLab's development environment, allowing you to investigate +the behaviour of suspect code in detail. + +It's important to note that profiling an application *alters its performance*, +and will generally be done *in an unrepresentative environment*. In particular, +a method is not necessarily troublesome just because it is executed many times, +or takes a long time to execute. Profiles are tools you can use to better +understand what is happening in an application - using that information wisely +is up to you! + +Keeping that in mind, to create a profile, identify (or create) a spec that +exercises the troublesome code path, then run it using the `bin/rspec-stackprof` +helper, e.g.: + +``` +$ LIMIT=10 bin/rspec-stackprof spec/policies/project_policy_spec.rb +8/8 |====== 100 ======>| Time: 00:00:18 + +Finished in 18.19 seconds (files took 4.8 seconds to load) +8 examples, 0 failures + +================================== + Mode: wall(1000) + Samples: 17033 (5.59% miss rate) + GC: 1901 (11.16%) +================================== + TOTAL (pct) SAMPLES (pct) FRAME + 6000 (35.2%) 2566 (15.1%) Sprockets::Cache::FileStore#get + 2018 (11.8%) 888 (5.2%) ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#exec_no_cache + 1338 (7.9%) 640 (3.8%) ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements#execute + 3125 (18.3%) 394 (2.3%) Sprockets::Cache::FileStore#safe_open + 913 (5.4%) 301 (1.8%) ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#exec_cache + 288 (1.7%) 288 (1.7%) ActiveRecord::Attribute#initialize + 246 (1.4%) 246 (1.4%) Sprockets::Cache::FileStore#safe_stat + 295 (1.7%) 193 (1.1%) block (2 levels) in class_attribute + 187 (1.1%) 187 (1.1%) block (4 levels) in class_attribute +``` + +You can limit the specs that are run by passing any arguments `rspec` would +normally take. + +The output is sorted by the `Samples` column by default. This is the number of +samples taken where the method is the one currently being executed. The `Total` +column shows the number of samples taken where the method, or any of the methods +it calls, were being executed. + +To create a graphical view of the call stack: + +```shell +$ stackprof tmp/project_policy_spec.rb.dump --graphviz > project_policy_spec.dot +$ dot -Tsvg project_policy_spec.dot > project_policy_spec.svg +``` + +To load the profile in [kcachegrind](https://kcachegrind.github.io/): + +``` +$ stackprof tmp/project_policy_spec.dump --callgrind > project_policy_spec.callgrind +$ kcachegrind project_policy_spec.callgrind # Linux +$ qcachegrind project_policy_spec.callgrind # Mac +``` + +It may be useful to zoom in on a specific method, e.g.: + +``` +$ stackprof tmp/project_policy_spec.rb.dump --method warm_asset_cache +TestEnv#warm_asset_cache (/Users/lupine/dev/gitlab.com/gitlab-org/gitlab-development-kit/gitlab/spec/support/test_env.rb:164) + samples: 0 self (0.0%) / 6288 total (36.9%) + callers: + 6288 ( 100.0%) block (2 levels) in <top (required)> + callees (6288 total): + 6288 ( 100.0%) Capybara::RackTest::Driver#visit + code: + | 164 | def warm_asset_cache + | 165 | return if warm_asset_cache? + | 166 | return unless defined?(Capybara) + | 167 | + 6288 (36.9%) | 168 | Capybara.current_session.driver.visit '/' + | 169 | end +$ stackprof tmp/project_policy_spec.rb.dump --method BasePolicy#abilities +BasePolicy#abilities (/Users/lupine/dev/gitlab.com/gitlab-org/gitlab-development-kit/gitlab/app/policies/base_policy.rb:79) + samples: 0 self (0.0%) / 50 total (0.3%) + callers: + 25 ( 50.0%) BasePolicy.abilities + 25 ( 50.0%) BasePolicy#collect_rules + callees (50 total): + 25 ( 50.0%) ProjectPolicy#rules + 25 ( 50.0%) BasePolicy#collect_rules + code: + | 79 | def abilities + | 80 | return RuleSet.empty if @user && @user.blocked? + | 81 | return anonymous_abilities if @user.nil? + 50 (0.3%) | 82 | collect_rules { rules } + | 83 | end +``` + +Since the profile includes the work done by the test suite as well as the +application code, these profiles can be used to investigate slow tests as well. +However, for smaller runs (like this example), this means that the cost of +setting up the test suite will tend to dominate. + +It's also possible to modify the application code in-place to output profiles +whenever a particular code path is triggered without going through the test +suite first. See the +[StackProf documentation](https://github.com/tmm1/stackprof/blob/master/README.md) +for details. + ## Importance of Changes When working on performance improvements, it's important to always ask yourself diff --git a/doc/development/shell_commands.md b/doc/development/shell_commands.md index 65cdd74bdb6..73893f9dd46 100644 --- a/doc/development/shell_commands.md +++ b/doc/development/shell_commands.md @@ -129,7 +129,7 @@ Various methods for opening and reading files in Ruby can be used to read the standard output of a process instead of a file. The following two commands do roughly the same: -``` +```ruby `touch /tmp/pawned-by-backticks` File.read('|touch /tmp/pawned-by-file-read') ``` @@ -142,7 +142,7 @@ attacker cannot control the start of the filename string you are opening. For instance, the following is sufficient to protect against accidentally starting a shell command with `|`: -``` +```ruby # we assume repo_path is not controlled by the attacker (user) path = File.join(repo_path, user_input) # path cannot start with '|' now. @@ -160,7 +160,7 @@ Path traversal is a security where the program (GitLab) tries to restrict user access to a certain directory on disk, but the user manages to open a file outside that directory by taking advantage of the `../` path notation. -``` +```ruby # Suppose the user gave us a path and they are trying to trick us user_input = '../other-repo.git/other-file' @@ -177,7 +177,7 @@ File.open(full_path) do # Oops! A good way to protect against this is to compare the full path with its 'absolute path' according to Ruby's `File.absolute_path`. -``` +```ruby full_path = File.join(repo_path, user_input) if full_path != File.absolute_path(full_path) raise "Invalid path: #{full_path.inspect}" diff --git a/doc/development/sidekiq_debugging.md b/doc/development/sidekiq_debugging.md index cea11e5f126..d6d770e27c1 100644 --- a/doc/development/sidekiq_debugging.md +++ b/doc/development/sidekiq_debugging.md @@ -3,12 +3,15 @@ ## Log arguments to Sidekiq jobs If you want to see what arguments are being passed to Sidekiq jobs you can set -the SIDEKIQ_LOG_ARGUMENTS environment variable. +the `SIDEKIQ_LOG_ARGUMENTS` [environment variable] +(https://docs.gitlab.com/omnibus/settings/environment-variables.html) to `1` (true). + +Example: ``` -SIDEKIQ_LOG_ARGUMENTS=1 bundle exec foreman start +gitlab_rails['env'] = {"SIDEKIQ_LOG_ARGUMENTS" => "1"} ``` -It is not recommend to enable this setting in production because some Sidekiq -jobs (such as sending a password reset email) take secret arguments (for -example the password reset token). +Please note: It is not recommend to enable this setting in production because some +Sidekiq jobs (such as sending a password reset email) take secret arguments (for +example the password reset token).
\ No newline at end of file diff --git a/doc/development/testing.md b/doc/development/testing.md index b0b26ccf57a..dbea6b9c9aa 100644 --- a/doc/development/testing.md +++ b/doc/development/testing.md @@ -63,12 +63,16 @@ the command line via `bundle exec teaspoon`, or via a web browser at - Use `.method` to describe class methods and `#method` to describe instance methods. - Use `context` to test branching logic. +- Use multi-line `do...end` blocks for `before` and `after`, even when it would + fit on a single line. - Don't `describe` symbols (see [Gotchas](gotchas.md#dont-describe-symbols)). +- Don't assert against the absolute value of a sequence-generated attribute (see [Gotchas](gotchas.md#dont-assert-against-the-absolute-value-of-a-sequence-generated-attribute)). - Don't supply the `:each` argument to hooks since it's the default. - Prefer `not_to` to `to_not` (_this is enforced by Rubocop_). - Try to match the ordering of tests to the ordering within the class. - Try to follow the [Four-Phase Test][four-phase-test] pattern, using newlines to separate phases. +- Try to use `Gitlab.config.gitlab.host` rather than hard coding `'localhost'` [four-phase-test]: https://robots.thoughtbot.com/four-phase-test diff --git a/doc/development/ux_guide/animation.md b/doc/development/ux_guide/animation.md new file mode 100644 index 00000000000..903e54bf9dc --- /dev/null +++ b/doc/development/ux_guide/animation.md @@ -0,0 +1,57 @@ +# Animation + +Motion is a tool to help convey important relationships, changes or transitions between elements. It should be used sparingly and intentionally, highlighting the right elements at the right moment. + +## Timings + +The longer distance an object travel, the timing should be longer for the animation. However, when in doubt, we should avoid large, full screen animations. + +Subtle animations, or objects leaving the screen should take **100-200 milliseconds**. Objects entering the screen, or motion we want to use to direct user attention can take between **200-400 milliseconds**. We should avoid animations of longer than 400 milliseconds as they will make the experience appear sluggish. If a specific animation feels like it will need more than 400 milliseconds, revisit the animation to see if there is a simpler, easier, shorter animation to implement. + +## Easing + +Easing specifies the rate of change of a parameter over time (see [easings.net](http://easings.net/)). Adding an easing curve will make the motion feel more natural. Being consistent with the easing curves will make the whole experience feel more cohesive and connected. + +* When an object is entering the screen, or transforming the scale, position, or shape, use the **easeOutQuint** curve (`cubic-bezier(0.23, 1, 0.32, 1)`) +* When an object is leaving the screen, or transforming the opacity or color, no easing curve is needed. It shouldn't _slow down_ as it is exiting the screen, as that draws attention on the leaving object, where we don't want it. Adding easing to opacity and color transitions will make the motion appear less smooth. Therefore, for these cases, motion should just be **linear**. + +## Types of animations + +### Hover + +Interactive elements (links, buttons, etc.) should have a hover state. A subtle animation for this transition adds a polished feel. We should target a `200ms linear` transition for a color hover effect. + +View the [interactive example](http://codepen.io/awhildy/full/GNyEvM/) here. + +![Hover animation](img/animation-hover.gif) + +### Dropdowns + +The dropdown menu should feel like it is appearing from the triggering element. Combining a position shift `400ms cubic-bezier(0.23, 1, 0.32, 1)` with a opacity animation `200ms linear` on the second half of the motion achieves this affect. + +View the [interactive example](http://codepen.io/awhildy/full/jVLJpb/) here. + +![Dropdown animation](img/animation-dropdown.gif) + +### Quick update + +When information is updating in place, a quick, subtle animation is needed. The previous content should cut out, and the new content should have a quick, `200ms linear` fade in. + +![Quick update animation](img/animation-quickupdate.gif) + +### Moving transitions + +When elements move on screen, there should be a quick animation so it is clear to users what moved where. The timing of this animation differs based on the amount of movement and change. Consider animations between `200ms` and `400ms`. + +#### Shifting elements on reorder +An example of a moving transition is when elements have to move out of the way when you drag an element. + +View the [interactive example](http://codepen.io/awhildy/full/ALyKPE/) here. + +![Reorder animation](img/animation-reorder.gif) + +#### Autoscroll the page +Another example of a moving transition is when you have to autoscroll the page to keep an active element visible. + +View the [interactive example](http://codepen.io/awhildy/full/PbxgVo/) here. +![Autoscroll animation](img/animation-autoscroll.gif)
\ No newline at end of file diff --git a/doc/development/ux_guide/basics.md b/doc/development/ux_guide/basics.md new file mode 100644 index 00000000000..259b214bd59 --- /dev/null +++ b/doc/development/ux_guide/basics.md @@ -0,0 +1,84 @@ +# Basics + +## Contents +* [Responsive](#responsive) +* [Typography](#typography) +* [Icons](#icons) +* [Color](#color) +* [Cursors](#cursors) + +--- + +## Responsive +GitLab is a responsive experience that works well across all screen sizes, from mobile devices to large monitors. In order to provide a great user experience, the core functionality (browsing files, creating issues, writing comments, etc.) must be available at all resolutions. However, due to size limitations, some secondary functionality may be hidden on smaller screens. Please keep this functionality limited to rare actions that aren't expected to be needed on small devices. + +--- + +## Typography +### Primary typeface +GitLab's main typeface used throughout the UI is **Source Sans Pro**. We support both the bold and regular weight. + +![Source Sans Pro sample](img/sourcesanspro-sample.png) + + +### Monospace typeface +This is the typeface used for code blocks. GitLab uses the OS default font. +- **Menlo** (Mac) +- **Consolas** (Windows) +- **Liberation Mono** (Linux) + +![Monospace font sample](img/monospacefont-sample.png) + +--- + +## Icons +GitLab uses Font Awesome icons throughout our interface. + +| | | +| :-----------: | :---- | +| ![Trash icon](img/icon-trash.png) | The trash icon is used for destructive actions that deletes information. | +| ![Edit icon](img/icon-edit.png) | The pencil icon is used for editing content such as comments.| +| ![Notification icon](img/icon-notification.png) | The bell icon is for notifications, such as Todos. | +| ![Subscribe icon](img/icon-subscribe.png) | The eye icon is for subscribing to updates. For example, you can subscribe to a label and get updated on issues with that label. | +| ![RSS icon](img/icon-rss.png) | The standard RSS icon is used for linking to RSS/atom feeds. | +| ![Close icon](img/icon-close.png) | An 'x' is used for closing UI elements such as dropdowns. | +| ![Add icon](img/icon-add.png) | A plus is used when creating new objects, such as issues, projects, etc. | + +> TODO: update this section, add more general guidance to icon usage and personality, etc. + +--- + +## Color + +| | State | Action | +| :------: | :------- | :------- | +| ![Blue](img/color-blue.png) | Primary and active (such as the current tab) | Organizational, managing, and retry commands| +| ![Green](img/color-green.png) | Opened | Create new objects | +| ![Orange](img/color-orange.png) | Warning | Non destructive action | +| ![Red](img/color-red.png) | Closed | Delete and other destructive commands | +| ![Grey](img/color-grey.png) | Neutral | Neutral secondary commands | + +### Text colors + +||| +| :---: | :--- | +| ![Text primary](img/color-textprimary.png) | Used for primary body text, such as issue description and comment | +| ![Text secondary](img/color-textsecondary.png) | Used for secondary body text, such as username and date | + +> TODO: Establish a perspective for color in terms of our personality and rationalize with Marketing usage. + +--- + +## Cursors +The mouse cursor is key in helping users understand how to interact with elements on the screen. + +| | | +| :------: | :------- | +| ![Default cursor](img/cursors-default.png) | Default cursor | +| ![Pointer cursor](img/cursors-pointer.png) | Pointer cursor: used to indicate that you can click on an element to invoke a command or navigate, such as links and buttons | +| ![Move cursor](img/cursors-move.png) | Move cursor: used to indicate that you can move an element around on the screen | +| ![Pan opened cursor](img/cursors-panopened.png) | Pan cursor (opened): indicates that you can grab and move the entire canvas, affecting what is seen in the view port. | +| ![Pan closed cursor](img/cursors-panclosed.png) | Pan cursor (closed): indicates that you are actively panning the canvas. | +| ![I-beam cursor](img/cursors-ibeam.png) | I-beam cursor: indicates that this is either text that you can select and copy, or a text field that you can click into to enter text. | + + diff --git a/doc/development/ux_guide/components.md b/doc/development/ux_guide/components.md new file mode 100644 index 00000000000..706bb180912 --- /dev/null +++ b/doc/development/ux_guide/components.md @@ -0,0 +1,280 @@ +# Components + +## Contents +* [Tooltips](#tooltips) +* [Anchor links](#anchor-links) +* [Buttons](#buttons) +* [Dropdowns](#dropdowns) +* [Counts](#counts) +* [Lists](#lists) +* [Tables](#tables) +* [Blocks](#blocks) +* [Panels](#panels) +* [Alerts](#alerts) +* [Forms](#forms) +* [Search box](#search-box) +* [File holders](#file-holders) +* [Data formats](#data-formats) + +--- + +## Tooltips + +### Usage +A tooltip should only be added if additional information is required. + +![Tooltip usage](img/tooltip-usage.png) + +### Placement +By default, tooltips should be placed below the element that they refer to. However, if there is not enough space in the viewpoint, the tooltip should be moved to the side as needed. + +![Tooltip placement location](img/tooltip-placement.png) + +--- + +## Anchor links + +Anchor links are used for navigational actions and lone, secondary commands (such as 'Reset filters' on the Issues List) when deemed appropriate by the UX team. + +### States + +#### Rest + +Primary links are blue in their rest state. Secondary links (such as the time stamp on comments) are a neutral gray color in rest. Details on the main GitLab navigation links can be found on the [features](features.md#navigation) page. + +#### Hover + +On hover, an underline should be added and the color should change. Both the primary and secondary link should become the darker blue color on hover. + +#### Focus + +The focus state should match the hover state. + +![Anchor link states ](img/components-anchorlinks.png) + +--- + +## Buttons + +Buttons communicate the command that will occur when the user clicks on them. + +### Types + +#### Primary +Primary buttons communicate the main call to action. There should only be one call to action in any given experience. Visually, primary buttons are conveyed with a full background fill + +![Primary button example](img/button-primary.png) + +#### Secondary +Secondary buttons are for alternative commands. They should be conveyed by a button with an stroke, and no background fill. + +![Secondary button example](img/button-secondary.png) + +### Icon and text treatment +Text should be in sentence case, where only the first word is capitalized. "Create issue" is correct, not "Create Issue". Buttons should only contain an icon or a text, not both. + +> TODO: Rationalize this. Ensure that we still believe this. + +### Colors +The default color treatment is the white/grey button. Follow the guidance on the [basics](basics.md#color) page to add meaningful color to a button. + +### Secondary states + +Primary buttons darken the color of their background and border for hover, focus and active states. An inner shadow is added to the active state to denote the button being pressed. + +| Values | Info | Success | Warning | Danger | +| :------ | :------: | :------: | :------: | :------: | +| Background: `$color-light` <br> Border: `$border-color-light` | ![](img/button-info--resting.png) | ![](img/button-success--resting.png) | ![](img/button-warning--resting.png) | ![](img/button-danger--resting.png) | +| Background: `$color-normal` <br> Border: `$border-color-normal` | ![](img/button-info--hover.png) | ![](img/button-success--hover.png) | ![](img/button-warning--hover.png) | ![](img/button-danger--hover.png) | +| Background: `$color-dark` <br> Border: `$border-color-dark` | ![](img/button-info--active.png) | ![](img/button-success--active.png) | ![](img/button-warning--active.png) | ![](img/button-danger--active.png) | + +Since secondary buttons only have a border on their resting state, their hover and focus states add a background color, which gets darkened on active. + +| Values | Success Secondary | Close | Spam | +| :------ | :------: | :------: | :------: | +| Font: `$border-color-light` <br> Border: `$border-color-light` | ![](img/button-success-secondary--resting.png) | ![](img/button-close--resting.png) | ![](img/button-spam--resting.png) | +| Background: `$color-light` <br> Border: `$border-color-light` | ![](img/button-success-secondary--hover.png) | ![](img/button-close--hover.png) | ![](img/button-spam--hover.png) | +| Background: `$color-normal` <br> Border: `$border-color-normal` | ![](img/button-success-secondary--active.png) | ![](img/button-close--active.png) | ![](img/button-spam--active.png) | + +--- + + +## Dropdowns + +Dropdowns are used to allow users to choose one (or many) options from a list of options. If this list of options is more 20, there should generally be a way to search through and filter the options (see the complex filter dropdowns below.) + +> TODO: Will update this section when the new filters UI is implemented. + +![Dropdown states](img/components-dropdown.png) + +### Max size + +The max height for dropdowns should target **10-15 items**. If the height of the dropdown is too large, the list becomes very hard to parse and it is easy to visually lose track of the item you are looking for. Usability also suffers as more mouse movement is required, and you have a larger area in which you hijack the scroll away from the page level. While it may initially seem counterintuitive to not show as many items as you can, it is actually quicker and easier to process the information when it is cropped at a reasonable height. + +--- + +## Counts + +A count element is used in navigation contexts where it is helpful to indicate the count, or number of items, in a list. Always use the [`number_with_delimiter`][number_with_delimiter] helper to display counts in the UI. + +![Counts example](img/components-counts.png) + +[number_with_delimiter]: http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html#method-i-number_with_delimiter + +--- + +## Lists + +Lists are used where ever there is a single column of information to display. Ths [issues list](https://gitlab.com/gitlab-org/gitlab-ce/issues) is an example of a important list in the GitLab UI. + +### Types + +Simple list using .content-list + +![Simple list](img/components-simplelist.png) + +List with avatar, title and description using .content-list + +![List with avatar](img/components-listwithavatar.png) + +List with hover effect .well-list + +![List with hover effect](img/components-listwithhover.png) + +List inside panel + +![List inside panel](img/components-listinsidepanel.png) + +--- + +## Tables + +When the information is too complex for a list, with multiple columns of information, a table can be used. For example, the [pipelines page](https://gitlab.com/gitlab-org/gitlab-ce/pipelines) uses a table. + +![Table](img/components-table.png) + +--- + +## Blocks + +Blocks are a way to group related information. + +### Types + +#### Content blocks + +Content blocks (`.content-block`) are the basic grouping of content. They are commonly used in [lists](#lists), and are separated by a botton border. + +![Content block](img/components-contentblock.png) + +#### Row content blocks + +A background color can be added to this blocks. For example, items in the [issue list](https://gitlab.com/gitlab-org/gitlab-ce/issues) have a green background if they were created recently. Below is an example of a gray content block with side padding using `.row-content-block`. + +![Row content block](img/components-rowcontentblock.png) + +#### Cover blocks +Cover blocks are generally used to create a heading element for a page, such as a new project, or a user profile page. Below is a cover block (`.cover-block`) for the profile page with an avatar, name and description. + +![Cover block](img/components-coverblock.png) + +--- + +## Panels + +> TODO: Catalog how we are currently using panels and rationalize how they relate to alerts + +![Panels](img/components-panels.png) + +--- + +## Alerts + +> TODO: Catalog how we are currently using alerts + +![Alerts](img/components-alerts.png) + +--- + +## Forms + +There are two options shown below regarding the positioning of labels in forms. Both are options to consider based on context and available size. However, it is important to have a consistent treatment of labels in the same form. + +### Types + +#### Labels stack vertically + +Form (`form`) with label rendered above input. + +![Vertical form](img/components-verticalform.png) + +#### Labels side-by-side + +Horizontal form (`form.horizontal-form`) with label rendered inline with input. + +![Horizontal form](img/components-horizontalform.png) + +--- + +## Search box + +Search boxes across GitLab have a consistent rest, active and text entered state. When text isn't entered in the box, there should be a magnifying glass right aligned with the input field. When text is entered, the magnifying glass should become a x, allowing users to clear their text. + +![Search box](img/components-searchbox.png) + +If needed, we indicate the scope of the search in the search box. + +![Scoped Search box](img/components-searchboxscoped.png) + +--- + +## File holders +A file holder (`.file-holder`) is used to show the contents of a file inline on a page of GitLab. + +![File Holder component](img/components-fileholder.png) + +--- + +## Data formats + +### Dates + +#### Exact + +Format for exacts dates should be ‘Mon DD, YYYY’, such as the examples below. + +![Exact date](img/components-dateexact.png) + +#### Relative + +This format relates how long since an action has occurred. The exact date can be shown as a tooltip on hover. + +![Relative date](img/components-daterelative.png) + +### References + +Referencing GitLab items depends on a symbol for each type of item. Typing that symbol will invoke a dropdown that allows you to search for and autocomplete the item you were looking for. References are shown as [links](#links) in context, and hovering on them shows the full title or name of the item. + +![Hovering on a reference](img/components-referencehover.png) + +#### `%` Milestones + +![Milestone reference](img/components-referencemilestone.png) + +#### `#` Issues + +![Issue reference](img/components-referenceissues.png) + +#### `!` Merge Requests + +![Merge request reference](img/components-referencemrs.png) + +#### `~` Labels + +![Labels reference](img/components-referencelabels.png) + +#### `@` People + +![People reference](img/components-referencepeople.png) + +> TODO: Open issue: Some commit references use monospace fonts, but others don't. Need to standardize this. diff --git a/doc/development/ux_guide/copy.md b/doc/development/ux_guide/copy.md new file mode 100644 index 00000000000..31cc9dd2a53 --- /dev/null +++ b/doc/development/ux_guide/copy.md @@ -0,0 +1,187 @@ +# Copy + +The copy for GitLab is clear and direct. We strike a clear balance between professional and friendly. We can empathesize with users (such as celebrating completing all Todos), and remain respectful of the importance of the work. We are that trusted, friendly coworker that is helpful and understanding. + +The copy and messaging is a core part of the experience of GitLab and the conversation with our users. Follow the below conventions throughout GitLab. + +Portions of this page are inspired by work found in the [Material Design guidelines][material design]. + +>**Note:** +We are currently inconsistent with this guidance. Images below are created to illustrate the point. As this guidance is refined, we will ensure that our experiences align. + +## Contents +* [Brevity](#brevity) +* [Capitalization and punctuation](#capitalization-and-punctuation) +* [Terminology](#terminology) + +--- + +## Brevity +Users will skim content, rather than read text carefully. +When familiar with a web app, users rely on muscle memory, and may read even less when moving quickly. +A good experience should quickly orient a user, regardless of their experience, to the purpose of the current screen. This should happen without the user having to consciously read long strings of text. +In general, text is burdensome and adds cognitive load. This is especially pronounced in a powerful productivity tool such as GitLab. +We should _not_ rely on words as a crutch to explain the purpose of a screen. +The current navigation and composition of the elements on the screen should get the user 95% there, with the remaining 5% being specific elements such as text. +This means that, as a rule, copy should be very short. A long message or label is a red flag hinting at design that needs improvement. + +>**Example:** +Use `Add` instead of `Add issue` as a button label. +Preferrably use context and placement of controls to make it obvious what clicking on them will do. + +--- + +## Capitalization and punctuation + +### Case +Use sentence case for titles, headings, labels, menu items, and buttons. Use title case when referring to [features][features] or [products][products]. Note that some features are also objects (e.g. “Merge Requests” and “merge requests”). + +| :white_check_mark: Do | :no_entry_sign: Don’t | +| --- | --- | +| Add issues to the Issue Board feature in GitLab Hosted | Add Issues To The Issue Board Feature In GitLab Hosted | + +### Avoid periods +Avoid using periods in solitary sentences in these elements: + +* Labels +* Hover text +* Bulleted lists +* Dialog body text + +Periods should be used for: + +* Lists or dialogs with multiple sentences +* Any sentence followed by a link + +| :white_check_mark: **Do** place periods after sentences followed by a link | :no_entry_sign: **Don’t** place periods after a link if it‘s not followed by a sentence | +| --- | --- | +| Mention someone to notify them. [Learn more](#) | Mention someone to notify them. [Learn more](#). | + +| :white_check_mark: **Do** skip periods after solo sentences of body text | :no_entry_sign: **Don’t** place periods after body text if there is only a single sentence | +| --- | --- | +| To see the available commands, enter `/gitlab help` | To see the available commands, enter `/gitlab help`. | + +### Use contractions +Don’t make a sentence harder to understand just to follow this rule. For example, “do not” can give more emphasis than “don’t” when needed. + +| :white_check_mark: Do | :no_entry_sign: Don’t | +| --- | --- | +| it’s, can’t, wouldn’t, you’re, you’ve, haven’t, don’t | it is, cannot, would not, it’ll, should’ve | + +### Use numerals for numbers +Use “1, 2, 3” instead of “one, two, three” for numbers. One exception is when mixing uses of numbers, such as “Enter two 3s.” + +| :white_check_mark: Do | :no_entry_sign: Don’t | +| --- | --- | +| 3 new commits | Three new commits | + +### Punctuation +Omit punctuation after phrases and labels to create a cleaner and more readable interface. Use punctuation to add clarity or be grammatically correct. + +| Punctuation mark | Copy and paste | HTML entity | Unicode | Mac shortcut | Windows shortcut | Description | +|---|---|---|---|---|---|---| +| Period | **.** | | | | | Omit for single sentences in affordances like labels, hover text, bulleted lists, and dialog body text.<br><br>Use in lists or dialogs with multiple sentences, and any sentence followed by a link or inline code.<br><br>Place inside quotation marks unless you’re telling the reader what to enter and it’s ambiguous whether to include the period. | +| Comma | **,** | | | | | Place inside quotation marks.<br><br>Use a [serial comma][serial comma] in lists of three or more terms. | +| Exclamation point | **!** | | | | | Avoid exclamation points as they tend to come across as shouting. Some exceptions include greetings or congratulatory messages. | +| Colon | **:** | `:` | `\u003A` | | | Omit from labels, for example, in the labels for fields in a form. | +| Apostrophe | **’** | `’` | `\u2019` | <kbd>⌥ Option</kbd>+<kbd>⇧ Shift</kbd>+<kbd>]</kbd> | <kbd>Alt</kbd>+<kbd>0 1 4 6</kbd> | Use for contractions (I’m, you’re, ’89) and to show possession.<br><br>To show possession, add an *’s* to all single nouns and names, even if they already end in an *s*: “Your issues’s status was changed.” For singular proper names ending in *s*, use only an apostrophe: “James’ commits.” For plurals of a single letter, add an *’s*: “Dot your i’s and cross your t’s.”<br><br>Omit for decades or acronyms: “the 1990s”, “MRs.” | +| Quotation marks | **“**<br><br>**”**<br><br>**‘**<br><br>**’** | `“`<br><br>`”`<br><br>`‘`<br><br>`’` | `\u201C`<br><br>`\u201D`<br><br>`\u2018`<br><br>`\u2019` | <kbd>⌥ Option</kbd>+<kbd>[</kbd><br><br><kbd>⌥ Option</kbd>+<kbd>⇧ Shift</kbd>+<kbd>[</kbd><br><br><kbd>⌥ Option</kbd>+<kbd>]</kbd><br><br><kbd>⌥ Option</kbd>+<kbd>⇧ Shift</kbd>+<kbd>]</kbd> | <kbd>Alt</kbd>+<kbd>0 1 4 7</kbd><br><br><kbd>Alt</kbd>+<kbd>0 1 4 8</kbd><br><br><kbd>Alt</kbd>+<kbd>0 1 4 5</kbd><br><br><kbd>Alt</kbd>+<kbd>0 1 4 6</kbd> | Use proper quotation marks (also known as smart quotes, curly quotes, or typographer’s quotes) for quotes. Single quotation marks are used for quotes inside of quotes.<br><br>The right single quotation mark symbol is also used for apostrophes.<br><br>Don’t use primes, straight quotes, or free-standing accents for quotation marks. | +| Primes | **′**<br><br>**″** | `′`<br><br>`″` | `\u2032`<br><br>`\u2033` | | <kbd>Alt</kbd>+<kbd>8 2 4 2</kbd><br><br><kbd>Alt</kbd>+<kbd>8 2 4 3</kbd> | Use prime (′) only in abbreviations for feet, arcminutes, and minutes: 3° 15′<br><br>Use double-prime (″) only in abbreviations for inches, arcseconds, and seconds: 3° 15′ 35″<br><br>Don’t use quotation marks, straight quotes, or free-standing accents for primes. | +| Straight quotes and accents | **"**<br><br>**'**<br><br>**`**<br><br>**´** | `"`<br><br>`'`<br><br>```<br><br>`´` | `\u0022`<br><br>`\u0027`<br><br>`\u0060`<br><br>`\u00B4` | | | Don’t use straight quotes or free-standing accents for primes or quotation marks.<br><br>Proper typography never uses straight quotes. They are left over from the age of typewriters and their only modern use is for code. | +| Ellipsis | **…** | `…` | | <kbd>⌥ Option</kbd>+<kbd>;</kbd> | <kbd>Alt</kbd>+<kbd>0 1 3 3</kbd> | Use to indicate an action in progress (“Downloading…”) or incomplete or truncated text. No space before the ellipsis.<br><br>Omit from menu items or buttons that open a dialog or start some other process. | +| Chevrons | **«**<br><br>**»**<br><br>**‹**<br><br>**›**<br><br>**<**<br><br>**>** | `«`<br><br>`»`<br><br>`‹`<br><br>`›`<br><br>`<`<br><br>`>` | `\u00AB`<br><br>`\u00BB`<br><br>`\u2039`<br><br>`\u203A`<br><br>`\u003C`<br><br>`\u003E`<br><br> | | | Omit from links or buttons that open another page or move to the next or previous step in a process. Also known as angle brackets, angular quote brackets, or guillemets. | +| Em dash | **—** | `—` | `\u2014` | <kbd>⌥ Option</kbd>+<kbd>⇧ Shift</kbd>+<kbd>-</kbd> | <kbd>Alt</kbd>+<kbd>0 1 5 1</kbd> | Avoid using dashes to separate text. If you must use dashes for this purpose — like this — use an em dash surrounded by spaces. | +| En dash | **–** | `–` | `\u2013` | <kbd>⌥ Option</kbd>+<kbd>-</kbd> | <kbd>Alt</kbd>+<kbd>0 1 5 0</kbd> | Use an en dash without spaces instead of a hyphen to indicate a range of values, such as numbers, times, and dates: “3–5 kg”, “8:00 AM–12:30 PM”, “10–17 Jan” | +| Hyphen | **-** | | | | | Use to represent negative numbers, or to avoid ambiguity in adjective-noun or noun-participle pairs. Example: “anti-inflammatory”; “5-mile walk.”<br><br>Omit in commonly understood terms and adverbs that end in *ly*: “frontend”, “greatly improved performance.”<br><br>Omit in the term “open source.” | +| Parentheses | **( )** | | | | | Use only to define acronyms or jargon: “Secure web connections are based on a technology called SSL (the secure sockets layer).”<br><br>Avoid other uses and instead rewrite the text, or use dashes or commas to set off the information. If parentheses are required: If the parenthetical is a complete, independent sentence, place the period inside the parentheses; if not, the period goes outside. | + +When using the <kbd>Alt</kbd> keystrokes in Windows, use the numeric keypad, not the row of numbers above the alphabet, and be sure Num Lock is turned on. + +--- + +## Terminology +Only use the terms in the tables below. + +### Issues + +#### Adjectives (states) + +| Term | +| ---- | +| Open | +| Closed | +| Deleted | + +>**Example:** +Use `5 open issues` and don’t use `5 pending issues`. + +#### Verbs (actions) + +| Term | Use | Don’t | +| ---- | --- | --- | +| Add | Add an issue | Don’t use `create` or `new` | +| View | View an open or closed issue || +| Edit | Edit an open or closed issue | Don’t use `update` | +| Close | Close an open issue || +| Re-open | Re-open a closed issue | There should never be a need to use `open` as a verb | +| Delete | Delete an open or closed issue || + +#### Add issue + +When viewing a list of issues, there is a button that is labeled `Add`. Given the context in the example, it is clearly referring to issues. If the context were not clear enough, the label could be `Add issue`. Clicking the button will bring you to the `Add issue` form. Other add flows should be similar. + +![Add issue button](img/copy-form-addissuebutton.png) + +The form should be titled `Add issue`. The submit button should be labeled `Submit`. Don’t use `Add`, `Create`, `New`, or `Save changes`. The cancel button should be labeled `Cancel`. Don’t use `Back`. + +![Add issue form](img/copy-form-addissueform.png) + +#### Edit issue + +When in context of an issue, the affordance to edit it is labeled `Edit`. If the context is not clear enough, `Edit issue` could be considered. Other edit flows should be similar. + +![Edit issue button](img/copy-form-editissuebutton.png) + +The form should be titled `Edit issue`. The submit button should be labeled `Save`. Don’t use `Edit`, `Update`, `Submit`, or `Save changes`. The cancel button should be labeled `Cancel`. Don’t use `Back`. + +![Edit issue form](img/copy-form-editissueform.png) + + +### Merge requests + +#### Adjectives (states) + +| Term | +| ---- | +| Open | +| Merged | + +#### Verbs (actions) + +| Term | Use | Don’t | +| ---- | --- | --- | +| Add | Add a merge request | Do not use `create` or `new` | +| View | View an open or merged merge request || +| Edit | Edit an open or merged merge request| Do not use `update` | +| Approve | Approve an open merge request || +| Remove approval, unapproved | Remove approval of an open merge request | Do not use `unapprove` as that is not an English word| +| Merge | Merge an open merge request || + +### Comments & Discussions + +#### Comment +A **comment** is a written piece of text that users of GitLab can create. Comments have the meta data of author and timestamp. Comments can be added in a variety of contexts, such as issues, merge requests, and discussions. + +#### Discussion +A **discussion** is a group of 1 or more comments. A discussion can include subdiscussions. Some discussions have the special capability of being able to be **resolved**. Both the comments in the discussion and the discussion itself can be resolved. + +--- + +Portions of this page are modifications based on work created and shared by the [Android Open Source Project][android project] and used according to terms described in the [Creative Commons 2.5 Attribution License][creative commons]. + +[material design]: https://material.io/guidelines/ +[features]: https://about.gitlab.com/features/ "GitLab features page" +[products]: https://about.gitlab.com/products/ "GitLab products page" +[serial comma]: https://en.wikipedia.org/wiki/Serial_comma "“Serial comma” in Wikipedia" +[android project]: http://source.android.com/ +[creative commons]: http://creativecommons.org/licenses/by/2.5/
\ No newline at end of file diff --git a/doc/development/ux_guide/features.md b/doc/development/ux_guide/features.md new file mode 100644 index 00000000000..9472995c68c --- /dev/null +++ b/doc/development/ux_guide/features.md @@ -0,0 +1,57 @@ +# Features + +## Contents +* [Navigation](#navigation) +* [Filtering](#filtering) +* [Search results](#search-results) +* [Conversations](#conversations) +* [Empty states](#empty-states) + +--- + +## Navigation + +### Global navigation + +The global navigation is accessible via the menu button on the top left of the screen, and can be pinned to keep it open. It contains a consistent list of pages that allow you to view content that is across GitLab. For example, you can view your todos, issues and merge requests across projects and groups. + +![Global nav](img/features-globalnav.png) + + +### Contextual navigation + +The navigation in the header is contextual to each page. These options change depending on if you are looking at a project, group, or settings page. There should be no more than 10 items on a level in the contextual navigation, allowing it to comfortably fit on a typical laptop screen. There can be up to too levels of navigation. Each sub nav group should be a self-contained group of functionality. For example, everything related to the issue tracker should be under the 'Issue' tab, while everything relating to the wiki will be grouped under the 'Wiki' tab. The names used for each section should be short and easy to remember, ideally 1-2 words in length. + +![Contextual nav](img/features-contextualnav.png) + +### Information architecture + +The [GitLab Product Map](https://gitlab.com/gitlab-org/gitlab-design/raw/master/production/resources/gitlab-map.png) shows a visual representation of the information architecture for GitLab. + +--- + +## Filtering + +Today, lists are filtered by a series of dropdowns. Some of these dropdowns allow multiselect (labels), while others allow you to filter to one option (milestones). However, we are currently implementing a [new model](https://gitlab.com/gitlab-org/gitlab-ce/issues/21747) for this, and will update the guide when it is ready. + +![Filters](img/features-filters.png) + +--- + +## Search results + +### Global search + +[Global search](https://gitlab.com/search?group_id=&project_id=13083&repository_ref=&scope=issues&search=mobile) allows you to search across items in a project, or even across multiple projects. You can switch tabs to filter on type of object, or filter by group. + +### List search + +There are several core lists in the GitLab experience, such as the Issue list and the Merge Request list. You are also able to [filter and search these lists](https://gitlab.com/gitlab-org/gitlab-ce/issues?utf8=%E2%9C%93&search=mobile). This UI will be updated with the [new filtering model](https://gitlab.com/gitlab-org/gitlab-ce/issues/21747). + +--- + +## Empty states + +Empty states need to be considered in the design of features. They are vital to helping onboard new users, making the experience feel more approachable and understandable. Empty states should feel inviting and provide just enough information to get people started. There should be a single call to action and a clear explanation of what to use the feature for. + +![Empty states](img/features-emptystates.png) diff --git a/doc/development/ux_guide/img/animation-autoscroll.gif b/doc/development/ux_guide/img/animation-autoscroll.gif Binary files differnew file mode 100644 index 00000000000..155b0234c64 --- /dev/null +++ b/doc/development/ux_guide/img/animation-autoscroll.gif diff --git a/doc/development/ux_guide/img/animation-dropdown.gif b/doc/development/ux_guide/img/animation-dropdown.gif Binary files differnew file mode 100644 index 00000000000..c9b31d26165 --- /dev/null +++ b/doc/development/ux_guide/img/animation-dropdown.gif diff --git a/doc/development/ux_guide/img/animation-hover.gif b/doc/development/ux_guide/img/animation-hover.gif Binary files differnew file mode 100644 index 00000000000..37ad9c76828 --- /dev/null +++ b/doc/development/ux_guide/img/animation-hover.gif diff --git a/doc/development/ux_guide/img/animation-quickupdate.gif b/doc/development/ux_guide/img/animation-quickupdate.gif Binary files differnew file mode 100644 index 00000000000..8db70bc3d24 --- /dev/null +++ b/doc/development/ux_guide/img/animation-quickupdate.gif diff --git a/doc/development/ux_guide/img/animation-reorder.gif b/doc/development/ux_guide/img/animation-reorder.gif Binary files differnew file mode 100644 index 00000000000..ccdeb3d396f --- /dev/null +++ b/doc/development/ux_guide/img/animation-reorder.gif diff --git a/doc/development/ux_guide/img/button-close--active.png b/doc/development/ux_guide/img/button-close--active.png Binary files differnew file mode 100644 index 00000000000..824bfc8f31b --- /dev/null +++ b/doc/development/ux_guide/img/button-close--active.png diff --git a/doc/development/ux_guide/img/button-close--hover.png b/doc/development/ux_guide/img/button-close--hover.png Binary files differnew file mode 100644 index 00000000000..0291e121894 --- /dev/null +++ b/doc/development/ux_guide/img/button-close--hover.png diff --git a/doc/development/ux_guide/img/button-close--resting.png b/doc/development/ux_guide/img/button-close--resting.png Binary files differnew file mode 100644 index 00000000000..986d7174ce7 --- /dev/null +++ b/doc/development/ux_guide/img/button-close--resting.png diff --git a/doc/development/ux_guide/img/button-danger--active.png b/doc/development/ux_guide/img/button-danger--active.png Binary files differnew file mode 100644 index 00000000000..d3c64424b26 --- /dev/null +++ b/doc/development/ux_guide/img/button-danger--active.png diff --git a/doc/development/ux_guide/img/button-danger--hover.png b/doc/development/ux_guide/img/button-danger--hover.png Binary files differnew file mode 100644 index 00000000000..8506e093306 --- /dev/null +++ b/doc/development/ux_guide/img/button-danger--hover.png diff --git a/doc/development/ux_guide/img/button-danger--resting.png b/doc/development/ux_guide/img/button-danger--resting.png Binary files differnew file mode 100644 index 00000000000..69ad6bb796b --- /dev/null +++ b/doc/development/ux_guide/img/button-danger--resting.png diff --git a/doc/development/ux_guide/img/button-info--active.png b/doc/development/ux_guide/img/button-info--active.png Binary files differnew file mode 100644 index 00000000000..23be20b225c --- /dev/null +++ b/doc/development/ux_guide/img/button-info--active.png diff --git a/doc/development/ux_guide/img/button-info--hover.png b/doc/development/ux_guide/img/button-info--hover.png Binary files differnew file mode 100644 index 00000000000..4cb4e38558c --- /dev/null +++ b/doc/development/ux_guide/img/button-info--hover.png diff --git a/doc/development/ux_guide/img/button-info--resting.png b/doc/development/ux_guide/img/button-info--resting.png Binary files differnew file mode 100644 index 00000000000..5883340aa83 --- /dev/null +++ b/doc/development/ux_guide/img/button-info--resting.png diff --git a/doc/development/ux_guide/img/button-primary.png b/doc/development/ux_guide/img/button-primary.png Binary files differnew file mode 100644 index 00000000000..eda5ed84aec --- /dev/null +++ b/doc/development/ux_guide/img/button-primary.png diff --git a/doc/development/ux_guide/img/button-secondary.png b/doc/development/ux_guide/img/button-secondary.png Binary files differnew file mode 100644 index 00000000000..26d4e8cf43d --- /dev/null +++ b/doc/development/ux_guide/img/button-secondary.png diff --git a/doc/development/ux_guide/img/button-spam--active.png b/doc/development/ux_guide/img/button-spam--active.png Binary files differnew file mode 100644 index 00000000000..55b44898684 --- /dev/null +++ b/doc/development/ux_guide/img/button-spam--active.png diff --git a/doc/development/ux_guide/img/button-spam--hover.png b/doc/development/ux_guide/img/button-spam--hover.png Binary files differnew file mode 100644 index 00000000000..3dc8ed34c54 --- /dev/null +++ b/doc/development/ux_guide/img/button-spam--hover.png diff --git a/doc/development/ux_guide/img/button-spam--resting.png b/doc/development/ux_guide/img/button-spam--resting.png Binary files differnew file mode 100644 index 00000000000..b6bf10a5b64 --- /dev/null +++ b/doc/development/ux_guide/img/button-spam--resting.png diff --git a/doc/development/ux_guide/img/button-success--active.png b/doc/development/ux_guide/img/button-success--active.png Binary files differnew file mode 100644 index 00000000000..895a52831cb --- /dev/null +++ b/doc/development/ux_guide/img/button-success--active.png diff --git a/doc/development/ux_guide/img/button-success--hover.png b/doc/development/ux_guide/img/button-success--hover.png Binary files differnew file mode 100644 index 00000000000..e4c74bd9778 --- /dev/null +++ b/doc/development/ux_guide/img/button-success--hover.png diff --git a/doc/development/ux_guide/img/button-success--resting.png b/doc/development/ux_guide/img/button-success--resting.png Binary files differnew file mode 100644 index 00000000000..2fa971b5347 --- /dev/null +++ b/doc/development/ux_guide/img/button-success--resting.png diff --git a/doc/development/ux_guide/img/button-success-secondary--active.png b/doc/development/ux_guide/img/button-success-secondary--active.png Binary files differnew file mode 100644 index 00000000000..e7383b36946 --- /dev/null +++ b/doc/development/ux_guide/img/button-success-secondary--active.png diff --git a/doc/development/ux_guide/img/button-success-secondary--hover.png b/doc/development/ux_guide/img/button-success-secondary--hover.png Binary files differnew file mode 100644 index 00000000000..4af2a68cf1b --- /dev/null +++ b/doc/development/ux_guide/img/button-success-secondary--hover.png diff --git a/doc/development/ux_guide/img/button-success-secondary--resting.png b/doc/development/ux_guide/img/button-success-secondary--resting.png Binary files differnew file mode 100644 index 00000000000..a5a4ec512c8 --- /dev/null +++ b/doc/development/ux_guide/img/button-success-secondary--resting.png diff --git a/doc/development/ux_guide/img/button-warning--active.png b/doc/development/ux_guide/img/button-warning--active.png Binary files differnew file mode 100644 index 00000000000..5877d46c94d --- /dev/null +++ b/doc/development/ux_guide/img/button-warning--active.png diff --git a/doc/development/ux_guide/img/button-warning--hover.png b/doc/development/ux_guide/img/button-warning--hover.png Binary files differnew file mode 100644 index 00000000000..308e1adc8a3 --- /dev/null +++ b/doc/development/ux_guide/img/button-warning--hover.png diff --git a/doc/development/ux_guide/img/button-warning--resting.png b/doc/development/ux_guide/img/button-warning--resting.png Binary files differnew file mode 100644 index 00000000000..28e5e601520 --- /dev/null +++ b/doc/development/ux_guide/img/button-warning--resting.png diff --git a/doc/development/ux_guide/img/color-blue.png b/doc/development/ux_guide/img/color-blue.png Binary files differnew file mode 100644 index 00000000000..844e926f1f5 --- /dev/null +++ b/doc/development/ux_guide/img/color-blue.png diff --git a/doc/development/ux_guide/img/color-green.png b/doc/development/ux_guide/img/color-green.png Binary files differnew file mode 100644 index 00000000000..5c4c23c7067 --- /dev/null +++ b/doc/development/ux_guide/img/color-green.png diff --git a/doc/development/ux_guide/img/color-grey.png b/doc/development/ux_guide/img/color-grey.png Binary files differnew file mode 100644 index 00000000000..5247649a0ce --- /dev/null +++ b/doc/development/ux_guide/img/color-grey.png diff --git a/doc/development/ux_guide/img/color-orange.png b/doc/development/ux_guide/img/color-orange.png Binary files differnew file mode 100644 index 00000000000..1103c715225 --- /dev/null +++ b/doc/development/ux_guide/img/color-orange.png diff --git a/doc/development/ux_guide/img/color-red.png b/doc/development/ux_guide/img/color-red.png Binary files differnew file mode 100644 index 00000000000..77ecbbc0a20 --- /dev/null +++ b/doc/development/ux_guide/img/color-red.png diff --git a/doc/development/ux_guide/img/color-textprimary.png b/doc/development/ux_guide/img/color-textprimary.png Binary files differnew file mode 100644 index 00000000000..90f2821f0cf --- /dev/null +++ b/doc/development/ux_guide/img/color-textprimary.png diff --git a/doc/development/ux_guide/img/color-textsecondary.png b/doc/development/ux_guide/img/color-textsecondary.png Binary files differnew file mode 100644 index 00000000000..61cb8a13c45 --- /dev/null +++ b/doc/development/ux_guide/img/color-textsecondary.png diff --git a/doc/development/ux_guide/img/components-alerts.png b/doc/development/ux_guide/img/components-alerts.png Binary files differnew file mode 100644 index 00000000000..66a43ac69e1 --- /dev/null +++ b/doc/development/ux_guide/img/components-alerts.png diff --git a/doc/development/ux_guide/img/components-anchorlinks.png b/doc/development/ux_guide/img/components-anchorlinks.png Binary files differnew file mode 100644 index 00000000000..4a9c730566c --- /dev/null +++ b/doc/development/ux_guide/img/components-anchorlinks.png diff --git a/doc/development/ux_guide/img/components-contentblock.png b/doc/development/ux_guide/img/components-contentblock.png Binary files differnew file mode 100644 index 00000000000..58d87729701 --- /dev/null +++ b/doc/development/ux_guide/img/components-contentblock.png diff --git a/doc/development/ux_guide/img/components-counts.png b/doc/development/ux_guide/img/components-counts.png Binary files differnew file mode 100644 index 00000000000..19280e988a0 --- /dev/null +++ b/doc/development/ux_guide/img/components-counts.png diff --git a/doc/development/ux_guide/img/components-coverblock.png b/doc/development/ux_guide/img/components-coverblock.png Binary files differnew file mode 100644 index 00000000000..fb135f9648a --- /dev/null +++ b/doc/development/ux_guide/img/components-coverblock.png diff --git a/doc/development/ux_guide/img/components-dateexact.png b/doc/development/ux_guide/img/components-dateexact.png Binary files differnew file mode 100644 index 00000000000..686ca727293 --- /dev/null +++ b/doc/development/ux_guide/img/components-dateexact.png diff --git a/doc/development/ux_guide/img/components-daterelative.png b/doc/development/ux_guide/img/components-daterelative.png Binary files differnew file mode 100644 index 00000000000..4954dfb51b3 --- /dev/null +++ b/doc/development/ux_guide/img/components-daterelative.png diff --git a/doc/development/ux_guide/img/components-dropdown.png b/doc/development/ux_guide/img/components-dropdown.png Binary files differnew file mode 100644 index 00000000000..7f9a701c089 --- /dev/null +++ b/doc/development/ux_guide/img/components-dropdown.png diff --git a/doc/development/ux_guide/img/components-fileholder.png b/doc/development/ux_guide/img/components-fileholder.png Binary files differnew file mode 100644 index 00000000000..ec2911a1232 --- /dev/null +++ b/doc/development/ux_guide/img/components-fileholder.png diff --git a/doc/development/ux_guide/img/components-horizontalform.png b/doc/development/ux_guide/img/components-horizontalform.png Binary files differnew file mode 100644 index 00000000000..c57dceda43a --- /dev/null +++ b/doc/development/ux_guide/img/components-horizontalform.png diff --git a/doc/development/ux_guide/img/components-listinsidepanel.png b/doc/development/ux_guide/img/components-listinsidepanel.png Binary files differnew file mode 100644 index 00000000000..3a72d39bb5d --- /dev/null +++ b/doc/development/ux_guide/img/components-listinsidepanel.png diff --git a/doc/development/ux_guide/img/components-listwithavatar.png b/doc/development/ux_guide/img/components-listwithavatar.png Binary files differnew file mode 100644 index 00000000000..f6db575433c --- /dev/null +++ b/doc/development/ux_guide/img/components-listwithavatar.png diff --git a/doc/development/ux_guide/img/components-listwithhover.png b/doc/development/ux_guide/img/components-listwithhover.png Binary files differnew file mode 100644 index 00000000000..8521a8ad53e --- /dev/null +++ b/doc/development/ux_guide/img/components-listwithhover.png diff --git a/doc/development/ux_guide/img/components-panels.png b/doc/development/ux_guide/img/components-panels.png Binary files differnew file mode 100644 index 00000000000..c1391ca07e5 --- /dev/null +++ b/doc/development/ux_guide/img/components-panels.png diff --git a/doc/development/ux_guide/img/components-referencehover.png b/doc/development/ux_guide/img/components-referencehover.png Binary files differnew file mode 100644 index 00000000000..f80564dbb16 --- /dev/null +++ b/doc/development/ux_guide/img/components-referencehover.png diff --git a/doc/development/ux_guide/img/components-referenceissues.png b/doc/development/ux_guide/img/components-referenceissues.png Binary files differnew file mode 100644 index 00000000000..51fb2cf3e43 --- /dev/null +++ b/doc/development/ux_guide/img/components-referenceissues.png diff --git a/doc/development/ux_guide/img/components-referencelabels.png b/doc/development/ux_guide/img/components-referencelabels.png Binary files differnew file mode 100644 index 00000000000..aba450cc3ba --- /dev/null +++ b/doc/development/ux_guide/img/components-referencelabels.png diff --git a/doc/development/ux_guide/img/components-referencemilestone.png b/doc/development/ux_guide/img/components-referencemilestone.png Binary files differnew file mode 100644 index 00000000000..adf2555ccf8 --- /dev/null +++ b/doc/development/ux_guide/img/components-referencemilestone.png diff --git a/doc/development/ux_guide/img/components-referencemrs.png b/doc/development/ux_guide/img/components-referencemrs.png Binary files differnew file mode 100644 index 00000000000..6c3375f1ea1 --- /dev/null +++ b/doc/development/ux_guide/img/components-referencemrs.png diff --git a/doc/development/ux_guide/img/components-referencepeople.png b/doc/development/ux_guide/img/components-referencepeople.png Binary files differnew file mode 100644 index 00000000000..b8dd431e2e6 --- /dev/null +++ b/doc/development/ux_guide/img/components-referencepeople.png diff --git a/doc/development/ux_guide/img/components-rowcontentblock.png b/doc/development/ux_guide/img/components-rowcontentblock.png Binary files differnew file mode 100644 index 00000000000..c66a50f9564 --- /dev/null +++ b/doc/development/ux_guide/img/components-rowcontentblock.png diff --git a/doc/development/ux_guide/img/components-searchbox.png b/doc/development/ux_guide/img/components-searchbox.png Binary files differnew file mode 100644 index 00000000000..a25189296ba --- /dev/null +++ b/doc/development/ux_guide/img/components-searchbox.png diff --git a/doc/development/ux_guide/img/components-searchboxscoped.png b/doc/development/ux_guide/img/components-searchboxscoped.png Binary files differnew file mode 100644 index 00000000000..b116d714848 --- /dev/null +++ b/doc/development/ux_guide/img/components-searchboxscoped.png diff --git a/doc/development/ux_guide/img/components-simplelist.png b/doc/development/ux_guide/img/components-simplelist.png Binary files differnew file mode 100644 index 00000000000..858e5064c25 --- /dev/null +++ b/doc/development/ux_guide/img/components-simplelist.png diff --git a/doc/development/ux_guide/img/components-table.png b/doc/development/ux_guide/img/components-table.png Binary files differnew file mode 100644 index 00000000000..cedc55758a9 --- /dev/null +++ b/doc/development/ux_guide/img/components-table.png diff --git a/doc/development/ux_guide/img/components-verticalform.png b/doc/development/ux_guide/img/components-verticalform.png Binary files differnew file mode 100644 index 00000000000..489ae6f862f --- /dev/null +++ b/doc/development/ux_guide/img/components-verticalform.png diff --git a/doc/development/ux_guide/img/copy-form-addissuebutton.png b/doc/development/ux_guide/img/copy-form-addissuebutton.png Binary files differnew file mode 100644 index 00000000000..8457f0ab2ab --- /dev/null +++ b/doc/development/ux_guide/img/copy-form-addissuebutton.png diff --git a/doc/development/ux_guide/img/copy-form-addissueform.png b/doc/development/ux_guide/img/copy-form-addissueform.png Binary files differnew file mode 100644 index 00000000000..89c6b4acdfb --- /dev/null +++ b/doc/development/ux_guide/img/copy-form-addissueform.png diff --git a/doc/development/ux_guide/img/copy-form-editissuebutton.png b/doc/development/ux_guide/img/copy-form-editissuebutton.png Binary files differnew file mode 100644 index 00000000000..04bcc2bf831 --- /dev/null +++ b/doc/development/ux_guide/img/copy-form-editissuebutton.png diff --git a/doc/development/ux_guide/img/copy-form-editissueform.png b/doc/development/ux_guide/img/copy-form-editissueform.png Binary files differnew file mode 100644 index 00000000000..126ef34ea7e --- /dev/null +++ b/doc/development/ux_guide/img/copy-form-editissueform.png diff --git a/doc/development/ux_guide/img/cursors-default.png b/doc/development/ux_guide/img/cursors-default.png Binary files differnew file mode 100644 index 00000000000..c188ec4e351 --- /dev/null +++ b/doc/development/ux_guide/img/cursors-default.png diff --git a/doc/development/ux_guide/img/cursors-ibeam.png b/doc/development/ux_guide/img/cursors-ibeam.png Binary files differnew file mode 100644 index 00000000000..86f28639982 --- /dev/null +++ b/doc/development/ux_guide/img/cursors-ibeam.png diff --git a/doc/development/ux_guide/img/cursors-move.png b/doc/development/ux_guide/img/cursors-move.png Binary files differnew file mode 100644 index 00000000000..a9c610eaa88 --- /dev/null +++ b/doc/development/ux_guide/img/cursors-move.png diff --git a/doc/development/ux_guide/img/cursors-panclosed.png b/doc/development/ux_guide/img/cursors-panclosed.png Binary files differnew file mode 100644 index 00000000000..6d247a765ac --- /dev/null +++ b/doc/development/ux_guide/img/cursors-panclosed.png diff --git a/doc/development/ux_guide/img/cursors-panopened.png b/doc/development/ux_guide/img/cursors-panopened.png Binary files differnew file mode 100644 index 00000000000..76f2eeda831 --- /dev/null +++ b/doc/development/ux_guide/img/cursors-panopened.png diff --git a/doc/development/ux_guide/img/cursors-pointer.png b/doc/development/ux_guide/img/cursors-pointer.png Binary files differnew file mode 100644 index 00000000000..d86dd955fa7 --- /dev/null +++ b/doc/development/ux_guide/img/cursors-pointer.png diff --git a/doc/development/ux_guide/img/features-contextualnav.png b/doc/development/ux_guide/img/features-contextualnav.png Binary files differnew file mode 100644 index 00000000000..f8466f28627 --- /dev/null +++ b/doc/development/ux_guide/img/features-contextualnav.png diff --git a/doc/development/ux_guide/img/features-emptystates.png b/doc/development/ux_guide/img/features-emptystates.png Binary files differnew file mode 100644 index 00000000000..51835a7080b --- /dev/null +++ b/doc/development/ux_guide/img/features-emptystates.png diff --git a/doc/development/ux_guide/img/features-filters.png b/doc/development/ux_guide/img/features-filters.png Binary files differnew file mode 100644 index 00000000000..41db76db938 --- /dev/null +++ b/doc/development/ux_guide/img/features-filters.png diff --git a/doc/development/ux_guide/img/features-globalnav.png b/doc/development/ux_guide/img/features-globalnav.png Binary files differnew file mode 100644 index 00000000000..73294d1b524 --- /dev/null +++ b/doc/development/ux_guide/img/features-globalnav.png diff --git a/doc/development/ux_guide/img/icon-add.png b/doc/development/ux_guide/img/icon-add.png Binary files differnew file mode 100644 index 00000000000..bcad5e84591 --- /dev/null +++ b/doc/development/ux_guide/img/icon-add.png diff --git a/doc/development/ux_guide/img/icon-close.png b/doc/development/ux_guide/img/icon-close.png Binary files differnew file mode 100644 index 00000000000..dfe1495f5fa --- /dev/null +++ b/doc/development/ux_guide/img/icon-close.png diff --git a/doc/development/ux_guide/img/icon-edit.png b/doc/development/ux_guide/img/icon-edit.png Binary files differnew file mode 100644 index 00000000000..50f6f841868 --- /dev/null +++ b/doc/development/ux_guide/img/icon-edit.png diff --git a/doc/development/ux_guide/img/icon-notification.png b/doc/development/ux_guide/img/icon-notification.png Binary files differnew file mode 100644 index 00000000000..6ddfaa44f66 --- /dev/null +++ b/doc/development/ux_guide/img/icon-notification.png diff --git a/doc/development/ux_guide/img/icon-rss.png b/doc/development/ux_guide/img/icon-rss.png Binary files differnew file mode 100644 index 00000000000..b766488b32d --- /dev/null +++ b/doc/development/ux_guide/img/icon-rss.png diff --git a/doc/development/ux_guide/img/icon-subscribe.png b/doc/development/ux_guide/img/icon-subscribe.png Binary files differnew file mode 100644 index 00000000000..650168296c6 --- /dev/null +++ b/doc/development/ux_guide/img/icon-subscribe.png diff --git a/doc/development/ux_guide/img/icon-trash.png b/doc/development/ux_guide/img/icon-trash.png Binary files differnew file mode 100644 index 00000000000..b02178ca992 --- /dev/null +++ b/doc/development/ux_guide/img/icon-trash.png diff --git a/doc/development/ux_guide/img/monospacefont-sample.png b/doc/development/ux_guide/img/monospacefont-sample.png Binary files differnew file mode 100644 index 00000000000..1cd290b713c --- /dev/null +++ b/doc/development/ux_guide/img/monospacefont-sample.png diff --git a/doc/development/ux_guide/img/sourcesanspro-sample.png b/doc/development/ux_guide/img/sourcesanspro-sample.png Binary files differnew file mode 100644 index 00000000000..f7ecf0c7c66 --- /dev/null +++ b/doc/development/ux_guide/img/sourcesanspro-sample.png diff --git a/doc/development/ux_guide/img/surfaces-contentitemtitle.png b/doc/development/ux_guide/img/surfaces-contentitemtitle.png Binary files differnew file mode 100644 index 00000000000..3af0b56c8fb --- /dev/null +++ b/doc/development/ux_guide/img/surfaces-contentitemtitle.png diff --git a/doc/development/ux_guide/img/surfaces-header.png b/doc/development/ux_guide/img/surfaces-header.png Binary files differnew file mode 100644 index 00000000000..ba616388003 --- /dev/null +++ b/doc/development/ux_guide/img/surfaces-header.png diff --git a/doc/development/ux_guide/img/surfaces-systeminformationblock.png b/doc/development/ux_guide/img/surfaces-systeminformationblock.png Binary files differnew file mode 100644 index 00000000000..9f42f1d4dd0 --- /dev/null +++ b/doc/development/ux_guide/img/surfaces-systeminformationblock.png diff --git a/doc/development/ux_guide/img/surfaces-ux.png b/doc/development/ux_guide/img/surfaces-ux.png Binary files differnew file mode 100644 index 00000000000..53208727c64 --- /dev/null +++ b/doc/development/ux_guide/img/surfaces-ux.png diff --git a/doc/development/ux_guide/img/tooltip-placement.png b/doc/development/ux_guide/img/tooltip-placement.png Binary files differnew file mode 100644 index 00000000000..061f82e4df0 --- /dev/null +++ b/doc/development/ux_guide/img/tooltip-placement.png diff --git a/doc/development/ux_guide/img/tooltip-usage.png b/doc/development/ux_guide/img/tooltip-usage.png Binary files differnew file mode 100644 index 00000000000..40c4f051cd0 --- /dev/null +++ b/doc/development/ux_guide/img/tooltip-usage.png diff --git a/doc/development/ux_guide/index.md b/doc/development/ux_guide/index.md new file mode 100644 index 00000000000..8a849f239dc --- /dev/null +++ b/doc/development/ux_guide/index.md @@ -0,0 +1,63 @@ +# GitLab UX Guide + +The goal of this guide is to provide standards, principles and in-depth information to design beautiful and effective GitLab features. This will be a living document, and we welcome contributions, feedback and suggestions. + +## Design + +--- + +### [Principles](principles.md) +These guiding principles set a solid foundation for our design system, and should remain relatively stable over multiple releases. They should be referenced as new design patterns are created. + +--- + +### [Basics](basics.md) +The basic ingredients of our experience establish our personality and feel. This section includes details about typography, iconography, and color. + +--- + +### [Animation](animation.md) +Guidance on the timing, curving and motion for GitLab. + +--- + +### [Copy](copy.md) +Conventions on text and messaging within labels, buttons, and other components. + +--- + +### [Components](components.md) +Components are the controls that make up the GitLab experience, including guidance around buttons, links, dropdowns, etc. + +--- + +### [Surfaces](surfaces.md) +The GitLab experience is broken apart into several surfaces. Each of these surfaces is designated for a specific scope or type of content. Examples include the header, global menu, side pane, etc. + +--- + +### [Features](features.md) +The previous building blocks are combined into complete features in the GitLab UX. Examples include our navigation, filters, search results, and empty states. + +--- + +## Research + +--- + +### [Users](users.md) +How we think about the variety of users of GitLab, from small to large teams, comparing opensource usage to enterprise, etc. + +--- + +## Other + +--- + +### [Tips for designers](tips.md) +Tips for exporting assets, and other guidance. + +--- + +### [Resources](resources.md) +Resources for GitLab UX diff --git a/doc/development/ux_guide/principles.md b/doc/development/ux_guide/principles.md new file mode 100644 index 00000000000..1a297cba2cc --- /dev/null +++ b/doc/development/ux_guide/principles.md @@ -0,0 +1,17 @@ +# Principles + +These are the guiding principles that we should strive for to establish a solid foundation for the GitLab experience. + +## Professional and productive +GitLab is a tool to support what people do, day in, day out. We need to respect the importance of their work, and avoid gimicky details. + +## Minimal and efficient +While work can get complicated, GitLab is about bringing a sharp focus, helping our customers know what matters now. + +## Immediately recognizable +When you look at any screen, you should know immediately that it is GitLab. Our personality is strong and consistent across product and marketing experiences. + +## Human and quirky +We need to build empathy with our users, understanding their state of mind, and connect with them at a human level. Quirkiness is part of our DNA, and we should embrace it in the right moments and contexts. + +> TODO: Ensure these principles align well with the goals of the Marketing team diff --git a/doc/development/ux_guide/resources.md b/doc/development/ux_guide/resources.md new file mode 100644 index 00000000000..2f760c94414 --- /dev/null +++ b/doc/development/ux_guide/resources.md @@ -0,0 +1,13 @@ +# Resources + +## GitLab UI development kit + +We created a page inside GitLab where you can check commonly used html and css elements. + +When you run GitLab instance locally - just visit http://localhost:3000/help/ui page to see UI examples +you can use during GitLab development. + +## Design repository + +All design files are stored in the [gitlab-design](https://gitlab.com/gitlab-org/gitlab-design) +repository and maintained by GitLab UX designers.
\ No newline at end of file diff --git a/doc/development/ux_guide/surfaces.md b/doc/development/ux_guide/surfaces.md new file mode 100644 index 00000000000..881d6aa4cd6 --- /dev/null +++ b/doc/development/ux_guide/surfaces.md @@ -0,0 +1,47 @@ +# Surfaces + +## Contents +* [Header](#header) +* [Global menu](#global-menu) +* [Side pane](#side-pane) +* [Content area](#content-area) + +--- + +![Surfaces UX](img/surfaces-ux.png) + +## Global menu + +This menu is to navigate to pages that contain content global to GitLab. + +--- + +## Header + +The header contains 3 main elements: Project switching and searching, user account avatar and settings, and a contextual menu that changes based on the current page. + +![Surfaces Header](img/surfaces-header.png) + +--- + +## Side pane + +The side pane holds supporting information and meta data for the information in the content area. + +--- + +## Content area + +The main content of the page. The content area can include other surfaces. + +### Item title bar + +The item title bar contains the top level information to identify the item, such as the name, id and status. + +![Item title](img/surfaces-contentitemtitle.png) + +### Item system information + +The system information block contains relevant system controlled information. + +![Item system information](img/surfaces-systeminformationblock.png) diff --git a/doc/development/ux_guide/tips.md b/doc/development/ux_guide/tips.md new file mode 100644 index 00000000000..8348de4f8a2 --- /dev/null +++ b/doc/development/ux_guide/tips.md @@ -0,0 +1,44 @@ +# Tips + +## Contents +* [SVGs](#svgs) + +--- + +## SVGs + +When exporting SVGs, be sure to follow the following guidelines: + +1. Convert all strokes to outlines. +2. Use pathfinder tools to combine overlapping paths and create compound paths. +3. SVGs that are limited to one color should be exported without a fill color so the color can be set using CSS. +4. Ensure that exported SVGs have been run through an [SVG cleaner](https://github.com/RazrFalcon/SVGCleaner) to remove unused elements and attributes. + +You can open your svg in a text editor to ensure that it is clean. +Incorrect files will look like this: + +```xml +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg width="16px" height="17px" viewBox="0 0 16 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <!-- Generator: Sketch 3.7.2 (28276) - http://www.bohemiancoding.com/sketch --> + <title>Group</title> + <desc>Created with Sketch.</desc> + <defs></defs> + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> + <g id="Group" fill="#7E7C7C"> + <path d="M15.1111,1 L0.8891,1 C0.3981,1 0.0001,1.446 0.0001,1.996 L0.0001,15.945 C0.0001,16.495 0.3981,16.941 0.8891,16.941 L15.1111,16.941 C15.6021,16.941 16.0001,16.495 16.0001,15.945 L16.0001,1.996 C16.0001,1.446 15.6021,1 15.1111,1 L15.1111,1 L15.1111,1 Z M14.0001,6.0002 L14.0001,14.949 L2.0001,14.949 L2.0001,6.0002 L14.0001,6.0002 Z M14.0001,4.0002 L14.0001,2.993 L2.0001,2.993 L2.0001,4.0002 L14.0001,4.0002 Z" id="Combined-Shape"></path> + <polygon id="Fill-11" points="3 2.0002 5 2.0002 5 0.0002 3 0.0002"></polygon> + <polygon id="Fill-16" points="11 2.0002 13 2.0002 13 0.0002 11 0.0002"></polygon> + <path d="M5.37709616,11.5511984 L6.92309616,12.7821984 C7.35112915,13.123019 7.97359761,13.0565604 8.32002627,12.6330535 L10.7740263,9.63305349 C11.1237073,9.20557058 11.0606364,8.57555475 10.6331535,8.22587373 C10.2056706,7.87619272 9.57565475,7.93926361 9.22597373,8.36674651 L6.77197373,11.3667465 L8.16890384,11.2176016 L6.62290384,9.98660159 C6.19085236,9.6425813 5.56172188,9.71394467 5.21770159,10.1459962 C4.8736813,10.5780476 4.94504467,11.2071781 5.37709616,11.5511984 L5.37709616,11.5511984 Z" id="Stroke-21"></path> + </g> + </g> +</svg> +``` + +Correct file will look like this: + +```xml +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 17" enable-background="new 0 0 16 17"><path d="m15.1 1h-2.1v-1h-2v1h-6v-1h-2v1h-2.1c-.5 0-.9.5-.9 1v14c0 .6.4 1 .9 1h14.2c.5 0 .9-.4.9-1v-14c0-.5-.4-1-.9-1m-1.1 14h-12v-9h12v9m0-11h-12v-1h12v1"/><path d="m5.4 11.6l1.5 1.2c.4.3 1.1.3 1.4-.1l2.5-3c.3-.4.3-1.1-.1-1.4-.5-.4-1.1-.3-1.5.1l-1.8 2.2-.8-.6c-.4-.3-1.1-.3-1.4.2-.3.4-.3 1 .2 1.4"/></svg> +``` + +> TODO: Checkout [https://github.com/svg/svgo](https://github.com/svg/svgo) diff --git a/doc/development/ux_guide/users.md b/doc/development/ux_guide/users.md new file mode 100644 index 00000000000..717a902c424 --- /dev/null +++ b/doc/development/ux_guide/users.md @@ -0,0 +1,16 @@ +# Users + +> TODO: Create personas. Understand the similarities and differences across the below spectrums. + +## Users by organization + +- Enterprise +- Medium company +- Small company +- Open source communities + +## Users by role + +- Admin +- Manager +- Developer |