summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/README.md6
-rw-r--r--doc/administration/high_availability/redis.md2
-rw-r--r--doc/administration/integration/plantuml.md4
-rw-r--r--doc/api/users.md69
-rw-r--r--doc/articles/index.md16
-rw-r--r--doc/ci/autodeploy/img/auto_deploy_dropdown.pngbin44380 -> 99422 bytes
-rw-r--r--doc/ci/autodeploy/index.md34
-rw-r--r--doc/ci/triggers/README.md28
-rw-r--r--doc/ci/triggers/img/trigger_schedule_create.pngbin0 -> 34264 bytes
-rw-r--r--doc/ci/triggers/img/trigger_schedule_edit.pngbin0 -> 18524 bytes
-rw-r--r--doc/ci/triggers/img/trigger_schedule_updated_next_run_at.pngbin0 -> 21896 bytes
-rw-r--r--doc/development/doc_styleguide.md7
-rw-r--r--doc/development/fe_guide/droplab/droplab.md256
-rw-r--r--doc/development/fe_guide/droplab/plugins/ajax.md37
-rw-r--r--doc/development/fe_guide/droplab/plugins/filter.md45
-rw-r--r--doc/development/fe_guide/droplab/plugins/input_setter.md60
-rw-r--r--doc/development/fe_guide/img/boards_diagram.pngbin0 -> 30538 bytes
-rw-r--r--doc/development/fe_guide/img/vue_arch.pngbin0 -> 9848 bytes
-rw-r--r--doc/development/fe_guide/index.md63
-rw-r--r--doc/development/fe_guide/style_guide_js.md50
-rw-r--r--doc/development/fe_guide/testing.md5
-rw-r--r--doc/development/fe_guide/vue.md355
-rw-r--r--doc/development/writing_documentation.md4
-rw-r--r--doc/intro/README.md2
-rw-r--r--doc/university/glossary/README.md2
-rw-r--r--doc/user/admin_area/img/cohorts.pngbin0 -> 439635 bytes
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md102
-rw-r--r--doc/user/admin_area/user_cohorts.md37
-rw-r--r--doc/user/discussions/img/btn_new_issue_for_all_discussions.png (renamed from doc/user/project/merge_requests/img/btn_new_issue_for_all_discussions.png)bin29007 -> 29007 bytes
-rw-r--r--doc/user/discussions/img/comment_type_toggle.gifbin0 -> 70796 bytes
-rw-r--r--doc/user/discussions/img/discussion_comment.pngbin0 -> 57189 bytes
-rw-r--r--doc/user/discussions/img/discussion_view.png (renamed from doc/user/project/merge_requests/img/discussion_view.png)bin73821 -> 73821 bytes
-rw-r--r--doc/user/discussions/img/discussions_resolved.png (renamed from doc/user/project/merge_requests/img/discussions_resolved.png)bin4152 -> 4152 bytes
-rw-r--r--doc/user/discussions/img/new_issue_for_discussion.png (renamed from doc/user/project/merge_requests/img/new_issue_for_discussion.png)bin39563 -> 39563 bytes
-rw-r--r--doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved.png (renamed from doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved.png)bin17888 -> 17888 bytes
-rw-r--r--doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png (renamed from doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved_msg.png)bin4962 -> 4962 bytes
-rw-r--r--doc/user/discussions/img/preview_issue_for_discussion.png (renamed from doc/user/project/merge_requests/img/preview_issue_for_discussion.png)bin82412 -> 82412 bytes
-rw-r--r--doc/user/discussions/img/preview_issue_for_discussions.png (renamed from doc/user/project/merge_requests/img/preview_issue_for_discussions.png)bin143871 -> 143871 bytes
-rw-r--r--doc/user/discussions/img/resolve_comment_button.png (renamed from doc/user/project/merge_requests/img/resolve_comment_button.png)bin4722 -> 4722 bytes
-rw-r--r--doc/user/discussions/img/resolve_discussion_button.png (renamed from doc/user/project/merge_requests/img/resolve_discussion_button.png)bin4683 -> 4683 bytes
-rw-r--r--doc/user/discussions/img/resolve_discussion_issue_notice.png (renamed from doc/user/project/merge_requests/img/resolve_discussion_issue_notice.png)bin10307 -> 10307 bytes
-rw-r--r--doc/user/discussions/img/resolve_discussion_open_issue.png (renamed from doc/user/project/merge_requests/img/resolve_discussion_open_issue.png)bin20967 -> 20967 bytes
-rw-r--r--doc/user/discussions/index.md150
-rw-r--r--doc/user/permissions.md3
-rw-r--r--doc/user/project/integrations/kubernetes.md8
-rw-r--r--doc/user/project/integrations/microsoft_teams.md6
-rw-r--r--doc/user/project/integrations/project_services.md1
-rw-r--r--doc/user/project/merge_requests/index.md2
-rw-r--r--doc/user/project/merge_requests/merge_request_discussion_resolution.md107
-rw-r--r--doc/user/project/milestones/img/milestone_create.pngbin0 -> 40591 bytes
-rw-r--r--doc/user/project/milestones/img/milestone_group_create.pngbin0 -> 35526 bytes
-rw-r--r--doc/user/project/milestones/index.md46
-rw-r--r--doc/user/search/img/search_history.gifbin0 -> 265970 bytes
-rw-r--r--doc/user/search/index.md6
-rw-r--r--doc/workflow/README.md4
-rw-r--r--doc/workflow/groups.md2
-rw-r--r--doc/workflow/milestones.md29
-rw-r--r--doc/workflow/milestones/form.pngbin40414 -> 0 bytes
-rw-r--r--doc/workflow/milestones/group_form.pngbin35820 -> 0 bytes
-rw-r--r--doc/workflow/shortcuts.md6
60 files changed, 1382 insertions, 172 deletions
diff --git a/doc/README.md b/doc/README.md
index b6790b4d008..fb393aa09a1 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -6,10 +6,6 @@ All technical content published by GitLab lives in the documentation, including:
- [User docs](#user-documentation): general documentation dedicated to regular users of GitLab
- [Admin docs](#administrator-documentation): general documentation dedicated to administrators of GitLab instances
- [Contributor docs](#contributor-documentation): general documentation on how to develop and contribute to GitLab
-- [Topics](topics/index.md): pages organized per topic, gathering all the
- resources already published by GitLab related to a specific subject, including
- general docs, [technical articles](development/writing_documentation.md#technical-articles),
- blog posts and video tutorials.
- [GitLab University](university/README.md): guides to learn Git and GitLab
through courses and videos.
@@ -19,6 +15,7 @@ All technical content published by GitLab lives in the documentation, including:
- [API](api/README.md) Automate GitLab via a simple and powerful API.
- [CI/CD](ci/README.md) GitLab Continuous Integration (CI) and Continuous Delivery (CD) getting started, `.gitlab-ci.yml` options, and examples.
- [Container Registry](user/project/container_registry.md) Learn how to use GitLab Container Registry.
+- [Discussions](user/discussions/index.md) Threads, comments, and resolvable discussions in issues, commits, and merge requests.
- [Git Attributes](user/project/git_attributes.md) Managing Git attributes using a `.gitattributes` file.
- [Git cheatsheet](https://gitlab.com/gitlab-com/marketing/raw/master/design/print/git-cheatsheet/print-pdf/git-cheatsheet.pdf) Download a PDF describing the most used Git operations.
- [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab.
@@ -73,6 +70,7 @@ All technical content published by GitLab lives in the documentation, including:
- [Sidekiq Troubleshooting](administration/troubleshooting/sidekiq.md) Debug when Sidekiq appears hung and is not processing jobs.
- [System hooks](system_hooks/system_hooks.md) Notifications when users, projects and keys are changed.
- [Update](update/README.md) Update guides to upgrade your installation.
+- [User cohorts](user/admin_area/user_cohorts.md) View user activity over time.
- [Web terminals](administration/integration/terminal.md) Provide terminal access to environments from within GitLab.
- [Welcome message](customization/welcome_message.md) Add a custom welcome message to the sign-in page.
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
index b4e7bf21e35..4638a9c9782 100644
--- a/doc/administration/high_availability/redis.md
+++ b/doc/administration/high_availability/redis.md
@@ -492,7 +492,7 @@ which ideally should not have Redis or Sentinels on it for a HA setup.
redis['master_name'] = 'gitlab-redis'
## The same password for Redis authentication you set up for the master node.
- redis['password'] = 'redis-password-goes-here'
+ redis['master_password'] = 'redis-password-goes-here'
## A list of sentinels with `host` and `port`
gitlab_rails['redis_sentinels'] = [
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 6515b1a264a..5c856835039 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -1,6 +1,6 @@
# PlantUML & GitLab
-> [Introduced][ce-7810] in GitLab 8.16.
+> [Introduced][ce-8537] in GitLab 8.16.
When [PlantUML](http://plantuml.com) integration is enabled and configured in
GitLab we are able to create simple diagrams in AsciiDoc and Markdown documents
@@ -93,3 +93,5 @@ Some parameters can be added to the AsciiDoc block definition:
- *height*: Height attribute added to the img tag.
Markdown does not support any parameters and will always use PNG format.
+
+[ce-8537]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8537 \ No newline at end of file
diff --git a/doc/api/users.md b/doc/api/users.md
index 2ada4d09c84..e7ef68cffbc 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -72,6 +72,7 @@ GET /users
"organization": "",
"last_sign_in_at": "2012-06-01T11:41:01Z",
"confirmed_at": "2012-05-23T09:05:22Z",
+ "last_activity_on": "2012-05-23",
"color_scheme_id": 2,
"projects_limit": 100,
"current_sign_in_at": "2012-06-02T06:36:55Z",
@@ -104,6 +105,7 @@ GET /users
"organization": "",
"last_sign_in_at": null,
"confirmed_at": "2012-05-30T16:53:06.148Z",
+ "last_activity_on": "2012-05-23",
"color_scheme_id": 3,
"projects_limit": 100,
"current_sign_in_at": "2014-03-19T17:54:13Z",
@@ -130,6 +132,18 @@ For example:
GET /users?username=jack_smith
```
+You can also lookup users by external UID and provider:
+
+```
+GET /users?extern_uid=:extern_uid&provider=:provider
+```
+
+For example:
+
+```
+GET /users?extern_uid=1234567&provider=github
+```
+
You can search for users who are external with: `/users?external=true`
## Single user
@@ -196,6 +210,7 @@ Parameters:
"organization": "",
"last_sign_in_at": "2012-06-01T11:41:01Z",
"confirmed_at": "2012-05-23T09:05:22Z",
+ "last_activity_on": "2012-05-23",
"color_scheme_id": 2,
"projects_limit": 100,
"current_sign_in_at": "2012-06-02T06:36:55Z",
@@ -320,6 +335,7 @@ GET /user
"organization": "",
"last_sign_in_at": "2012-06-01T11:41:01Z",
"confirmed_at": "2012-05-23T09:05:22Z",
+ "last_activity_on": "2012-05-23",
"color_scheme_id": 2,
"projects_limit": 100,
"current_sign_in_at": "2012-06-02T06:36:55Z",
@@ -365,6 +381,7 @@ GET /user
"organization": "",
"last_sign_in_at": "2012-06-01T11:41:01Z",
"confirmed_at": "2012-05-23T09:05:22Z",
+ "last_activity_on": "2012-05-23",
"color_scheme_id": 2,
"projects_limit": 100,
"current_sign_in_at": "2012-06-02T06:36:55Z",
@@ -986,3 +1003,55 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `user_id` | integer | yes | The ID of the user |
| `impersonation_token_id` | integer | yes | The ID of the impersonation token |
+
+### Get user activities (admin only)
+
+>**Note:** This API endpoint is only available on 8.15 (EE) and 9.1 (CE) and above.
+
+Get the last activity date for all users, sorted from oldest to newest.
+
+The activities that update the timestamp are:
+
+ - Git HTTP/SSH activities (such as clone, push)
+ - User logging in into GitLab
+
+By default, it shows the activity for all users in the last 6 months, but this can be
+amended by using the `from` parameter.
+
+```
+GET /user/activities
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `from` | string | no | Date string in the format YEAR-MONTH-DAY, e.g. `2016-03-11`. Defaults to 6 months ago. |
+
+```bash
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/user/activities
+```
+
+Example response:
+
+```json
+[
+ {
+ "username": "user1",
+ "last_activity_on": "2015-12-14",
+ "last_activity_at": "2015-12-14"
+ },
+ {
+ "username": "user2",
+ "last_activity_on": "2015-12-15",
+ "last_activity_at": "2015-12-15"
+ },
+ {
+ "username": "user3",
+ "last_activity_on": "2015-12-16",
+ "last_activity_at": "2015-12-16"
+ }
+]
+```
+
+Please note that `last_activity_at` is deprecated, please use `last_activity_on`.
diff --git a/doc/articles/index.md b/doc/articles/index.md
new file mode 100644
index 00000000000..67eab36bf2c
--- /dev/null
+++ b/doc/articles/index.md
@@ -0,0 +1,16 @@
+# Technical Articles
+
+[Technical Articles](../development/writing_documentation.md#technical-articles) are
+topic-related documentation, written with an user-friendly approach and language, aiming
+to provide the community with guidance on specific processes to achieve certain objectives.
+
+They are written by members of the GitLab Team and by
+[Community Writers](https://about.gitlab.com/handbook/product/technical-writing/community-writers/).
+
+## GitLab Pages
+
+- **GitLab Pages from A to Z**
+ - [Part 1: Static sites and GitLab Pages domains](../user/project/pages/getting_started_part_one.md)
+ - [Part 2: Quick start guide - Setting up GitLab Pages](../user/project/pages/getting_started_part_two.md)
+ - [Part 3: Setting Up Custom Domains - DNS Records and SSL/TLS Certificates](../user/project/pages/getting_started_part_three.md)
+ - [Part 4: Creating and tweaking `.gitlab-ci.yml` for GitLab Pages](../user/project/pages/getting_started_part_four.md)
diff --git a/doc/ci/autodeploy/img/auto_deploy_dropdown.png b/doc/ci/autodeploy/img/auto_deploy_dropdown.png
index 957870ec8c7..b93b0a08fea 100644
--- a/doc/ci/autodeploy/img/auto_deploy_dropdown.png
+++ b/doc/ci/autodeploy/img/auto_deploy_dropdown.png
Binary files differ
diff --git a/doc/ci/autodeploy/index.md b/doc/ci/autodeploy/index.md
index 4028a5efa9e..9fa2b2c4969 100644
--- a/doc/ci/autodeploy/index.md
+++ b/doc/ci/autodeploy/index.md
@@ -1,6 +1,8 @@
# Auto deploy
-> [Introduced][mr-8135] in GitLab 8.15. Currently requires a [Public project][project-settings].
+> [Introduced][mr-8135] in GitLab 8.15.
+> Auto deploy is an experimental feature and is not recommended for Production use at this time.
+> As of GitLab 9.1, access to the container registry is only available while the Pipeline is running. Restarting a pod, scaling a service, or other actions which require on-going access will fail. On-going secure access is planned for a subsequent release.
Auto deploy is an easy way to configure GitLab CI for the deployment of your
application. GitLab Community maintains a list of `.gitlab-ci.yml`
@@ -15,7 +17,8 @@ deployment.
## Supported templates
-The list of supported auto deploy templates is available [here][auto-deploy-templates].
+The list of supported auto deploy templates is available in the
+[gitlab-ci-yml project][auto-deploy-templates].
## Configuration
@@ -32,10 +35,37 @@ enable [Kubernetes service][kubernetes-service].
1. Test your deployment configuration using a [Review App][review-app] that was
created automatically for you.
+## Private Project Support
+
+> Experimental support [introduced][mr-2] in GitLab 9.1.
+
+When a project has been marked as private, GitLab's [Container Registry][container-registry] requires authentication when downloading containers. Auto deploy will automatically provide the required authentication information to Kubernetes, allowing temporary access to the registry. Authentication credentials will be valid while the pipeline is running, allowing for a successful initial deployment.
+
+After the pipeline completes, Kubernetes will no longer be able to access the container registry. Restarting a pod, scaling a service, or other actions which require on-going access to the registry will fail. On-going secure access is planned for a subsequent release.
+
+## PostgreSQL Database Support
+
+> Experimental support [introduced][mr-8] in GitLab 9.1.
+
+In order to support applications that require a database, [PostgreSQL][postgresql] is provisioned by default. Credentials to access the database are preconfigured, but can be customized by setting the associated [variables](#postgresql-variables). These credentials can be used for defining a `DATABASE_URL` of the format: `postgres://user:password@postgres-host:postgres-port/postgres-database`. It is important to note that the database itself is temporary, and contents will be not be saved.
+
+PostgreSQL provisioning can be disabled by setting the variable `DISABLE_POSTGRES` to `"yes"`.
+
+### PostgreSQL Variables
+
+1. `DISABLE_POSTGRES: "yes"`: disable automatic deployment of PostgreSQL
+1. `POSTGRES_USER: "my-user"`: use custom username for PostgreSQL
+1. `POSTGRES_PASSWORD: "password"`: use custom password for PostgreSQL
+1. `POSTGRES_DB: "my database"`: use custom database name for PostgreSQL
+
[mr-8135]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8135
+[mr-2]: https://gitlab.com/gitlab-examples/kubernetes-deploy/merge_requests/2
+[mr-8]: https://gitlab.com/gitlab-examples/kubernetes-deploy/merge_requests/8
[project-settings]: https://docs.gitlab.com/ce/public_access/public_access.html
[project-services]: ../../user/project/integrations/project_services.md
[auto-deploy-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml/tree/master/autodeploy
[kubernetes-service]: ../../user/project/integrations/kubernetes.md
[docker-in-docker]: ../docker/using_docker_build.md#use-docker-in-docker-executor
[review-app]: ../review_apps/index.md
+[container-registry]: https://docs.gitlab.com/ce/user/project/container_registry.html
+[postgresql]: https://www.postgresql.org/
diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md
index e380282f910..5f611314d09 100644
--- a/doc/ci/triggers/README.md
+++ b/doc/ci/triggers/README.md
@@ -227,3 +227,31 @@ branch of project with ID `9` every night at `00:30`:
```
[ci-229]: https://gitlab.com/gitlab-org/gitlab-ci/merge_requests/229
+
+## Using scheduled triggers
+
+> [Introduced][ci-10533] in GitLab CE 9.1 as experimental.
+
+In order to schedule a trigger, navigate to your project's **Settings ➔ CI/CD Pipelines ➔ Triggers** and edit an existing trigger token.
+
+![Triggers Schedule edit](img/trigger_schedule_edit.png)
+
+To set up a scheduled trigger:
+
+1. Check the **Schedule trigger (experimental)** checkbox
+1. Enter a cron value for the frequency of the trigger ([learn more about cron notation](http://www.nncron.ru/help/EN/working/cron-format.htm))
+1. Enter the timezone of the cron trigger ([see a list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones))
+1. Enter the branch or tag that the trigger will target
+1. Hit **Save trigger** for the changes to take effect
+
+![Triggers Schedule create](img/trigger_schedule_create.png)
+
+You can check a next execution date of the scheduled trigger, which is automatically calculated by a server.
+
+![Triggers Schedule create](img/trigger_schedule_updated_next_run_at.png)
+
+> **Notes**:
+- Those triggers won't be executed precicely. Because scheduled triggers are handled by Sidekiq, which runs according to its interval. For exmaple, if you set a trigger to be executed every minute (`* * * * *`) and the Sidekiq worker performs 00:00 and 12:00 o'clock every day (`0 */12 * * *`), then your trigger will be executed only 00:00 and 12:00 o'clock every day. To change the Sidekiq worker's frequency, you have to edit the `trigger_schedule_worker` value in `config/gitlab.yml` and restart GitLab. The Sidekiq worker's configuration on GiLab.com is able to be looked up at [here](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/gitlab.yml.example#L185).
+- Cron notation is parsed by [Rufus-Scheduler](https://github.com/jmettraux/rufus-scheduler).
+
+[ci-10533]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10533
diff --git a/doc/ci/triggers/img/trigger_schedule_create.png b/doc/ci/triggers/img/trigger_schedule_create.png
new file mode 100644
index 00000000000..3cfdc00b7a7
--- /dev/null
+++ b/doc/ci/triggers/img/trigger_schedule_create.png
Binary files differ
diff --git a/doc/ci/triggers/img/trigger_schedule_edit.png b/doc/ci/triggers/img/trigger_schedule_edit.png
new file mode 100644
index 00000000000..647eac0a5d0
--- /dev/null
+++ b/doc/ci/triggers/img/trigger_schedule_edit.png
Binary files differ
diff --git a/doc/ci/triggers/img/trigger_schedule_updated_next_run_at.png b/doc/ci/triggers/img/trigger_schedule_updated_next_run_at.png
new file mode 100644
index 00000000000..71d08d04c37
--- /dev/null
+++ b/doc/ci/triggers/img/trigger_schedule_updated_next_run_at.png
Binary files differ
diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md
index bb78a0de0c5..1e81905c081 100644
--- a/doc/development/doc_styleguide.md
+++ b/doc/development/doc_styleguide.md
@@ -29,7 +29,8 @@ The table below shows what kind of documentation goes where.
| `doc/legal/` | Legal documents about contributing to GitLab. |
| `doc/install/`| Probably the most visited directory, since `installation.md` is there. Ideally this should go under `doc/administration/`, but it's best to leave it as-is in order to avoid confusion (still debated though). |
| `doc/update/` | Same with `doc/install/`. Should be under `administration/`, but this is a well known location, better leave as-is, at least for now. |
-| `doc/topics/` | Indexes per Topic (`doc/topics/topic-name/index.md`); Technical Articles: user guides, admin guides, technical overviews, tutorials (`doc/topics/topic-name/`). |
+| `doc/topics/` | Indexes per Topic (`doc/topics/topic-name/index.md`): all resources for that topic (user and admin documentation, articles, and third-party docs) |
+| `doc/articles/` | [Technical Articles](writing_documentation.md#technical-articles): user guides, admin guides, technical overviews, tutorials (`doc/articles/article-title/index.md`). |
---
@@ -61,8 +62,8 @@ The table below shows what kind of documentation goes where.
located at `doc/user/admin_area/settings/visibility_and_access_controls.md`.
1. The `doc/topics/` directory holds topic-related technical content. Create
`doc/topics/topic-name/subtopic-name/index.md` when subtopics become necessary.
- Note that `topics` holds the index page per topic, and technical articles. General
- user- and admin- related documentation, should be placed accordingly.
+ General user- and admin- related documentation, should be placed accordingly.
+1. For technical articles, place their images under `doc/articles/article-title/img/`.
---
diff --git a/doc/development/fe_guide/droplab/droplab.md b/doc/development/fe_guide/droplab/droplab.md
new file mode 100644
index 00000000000..8f0b6b21953
--- /dev/null
+++ b/doc/development/fe_guide/droplab/droplab.md
@@ -0,0 +1,256 @@
+# DropLab
+
+A generic dropdown for all of your custom dropdown needs.
+
+## Usage
+
+DropLab can be used by simply adding a `data-dropdown-trigger` HTML attribute.
+This attribute allows us to find the "trigger" _(toggle)_ for the dropdown,
+whether that is a button, link or input.
+
+The value of the `data-dropdown-trigger` should be a CSS selector that
+DropLab can use to find the trigger's dropdown list.
+
+You should also add the `data-dropdown` attribute to declare the dropdown list.
+The value is irrelevant.
+
+The DropLab class has no side effects, so you must always call `.init` when
+the DOM is ready. `DropLab.prototype.init` takes the same arguments as `DropLab.prototype.addHook`.
+If you do not provide any arguments, it will globally query and instantiate all droplab compatible dropdowns.
+
+```html
+<a href="#" data-dropdown-trigger="#list">Toggle</a>
+
+<ul id="list" data-dropdown>
+ <!-- ... -->
+<ul>
+```
+```js
+const droplab = new DropLab();
+droplab.init();
+```
+
+As you can see, we have a "Toggle" link, that is declared as a trigger.
+It provides a selector to find the dropdown list it should control.
+
+### Static data
+
+You can add static list items.
+
+```html
+<a href="#" data-dropdown-trigger="#list">Toggle</a>
+
+<ul id="list" data-dropdown>
+ <li>Static value 1</li>
+ <li>Static value 2</li>
+<ul>
+```
+```js
+const droplab = new DropLab();
+droplab.init();
+```
+
+### Explicit instantiation
+
+You can pass the trigger and list elements as constructor arguments to return
+a non-global instance of DropLab using the `DropLab.prototype.init` method.
+
+```html
+<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>
+
+<ul id="list" data-dropdown>
+ <!-- ... -->
+<ul>
+```
+```js
+const trigger = document.getElementById('trigger');
+const list = document.getElementById('list');
+
+const droplab = new DropLab();
+droplab.init(trigger, list);
+```
+
+You can also add hooks to an existing DropLab instance using `DropLab.prototype.addHook`.
+
+```html
+<a href="#" data-dropdown-trigger="#auto-dropdown">Toggle</a>
+<ul id="auto-dropdown" data-dropdown><!-- ... --><ul>
+
+<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>
+<ul id="list" data-dropdown><!-- ... --><ul>
+```
+```js
+const droplab = new DropLab();
+
+droplab.init();
+
+const trigger = document.getElementById('trigger');
+const list = document.getElementById('list');
+
+droplab.addHook(trigger, list);
+```
+
+
+### Dynamic data
+
+Adding `data-dynamic` to your dropdown element will enable dynamic list rendering.
+
+You can template a list item using the keys of the data object provided.
+Use the handlebars syntax `{{ value }}` to HTML escape the value.
+Use the `<%= value %>` syntax to simply interpolate the value.
+Use the `<%= value %>` syntax to evaluate the value.
+
+Passing an array of objects to `DropLab.prototype.addData` will render that data
+for all `data-dynamic` dropdown lists tracked by that DropLab instance.
+
+```html
+<a href="#" data-dropdown-trigger="#list">Toggle</a>
+
+<ul id="list" data-dropdown data-dynamic>
+ <li><a href="#" data-id="{{id}}">{{text}}</a></li>
+</ul>
+```
+```js
+const droplab = new DropLab();
+
+droplab.init().addData([{
+ id: 0,
+ text: 'Jacob',
+}, {
+ id: 1,
+ text: 'Jeff',
+}]);
+```
+
+Alternatively, you can specify a specific dropdown to add this data to but passing
+the data as the second argument and and the `id` of the trigger element as the first argument.
+
+```html
+<a href="#" data-dropdown-trigger="#list" id="trigger">Toggle</a>
+
+<ul id="list" data-dropdown data-dynamic>
+ <li><a href="#" data-id="{{id}}">{{text}}</a></li>
+</ul>
+```
+```js
+const droplab = new DropLab();
+
+droplab.init().addData('trigger', [{
+ id: 0,
+ text: 'Jacob',
+}, {
+ id: 1,
+ text: 'Jeff',
+}]);
+```
+
+This allows you to mix static and dynamic content with ease, even with one trigger.
+
+Note the use of scoping regarding the `data-dropdown` attribute to capture both
+dropdown lists, one of which is dynamic.
+
+```html
+<input id="trigger" data-dropdown-trigger="#list">
+<div id="list" data-dropdown>
+ <ul>
+ <li><a href="#">Static item 1</a></li>
+ <li><a href="#">Static item 2</a></li>
+ </ul>
+ <ul data-dynamic>
+ <li><a href="#" data-id="{{id}}">{{text}}</a></li>
+ </ul>
+</div>
+```
+```js
+const droplab = new DropLab();
+
+droplab.init().addData('trigger', [{
+ id: 0,
+ text: 'Jacob',
+}, {
+ id: 1,
+ text: 'Jeff',
+}]);
+```
+
+## Internal selectors
+
+DropLab adds some CSS classes to help lower the barrier to integration.
+
+For example,
+
+* The `droplab-item-selected` css class is added to items that have been selected
+either by a mouse click or by enter key selection.
+* The `droplab-item-active` css class is added to items that have been selected
+using arrow key navigation.
+
+## Internal events
+
+DropLab uses some custom events to help lower the barrier to integration.
+
+For example,
+
+* The `click.dl` event is fired when an `li` list item has been clicked. It is also
+fired when a list item has been selected with the keyboard. It is also fired when a
+`HookButton` button is clicked (a registered `button` tag or `a` tag trigger).
+* The `input.dl` event is fired when a `HookInput` (a registered `input` tag trigger) triggers an `input` event.
+* The `mousedown.dl` event is fired when a `HookInput` triggers a `mousedown` event.
+* The `keyup.dl` event is fired when a `HookInput` triggers a `keyup` event.
+* The `keydown.dl` event is fired when a `HookInput` triggers a `keydown` event.
+
+These custom events add a `detail` object to the vanilla `Event` object that provides some potentially useful data.
+
+## Plugins
+
+Plugins are objects that are registered to be executed when a hook is added (when a droplab trigger and dropdown are instantiated).
+
+If no modules API is detected, the library will fall back as it does with `window.DropLab` and will add `window.DropLab.plugins.PluginName`.
+
+### Usage
+
+To use plugins, you can pass them in an array as the third argument of `DropLab.prototype.init` or `DropLab.prototype.addHook`.
+Some plugins require configuration values, the config object can be passed as the fourth argument.
+
+```html
+<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>
+<ul id="list" data-dropdown><!-- ... --><ul>
+```
+```js
+const droplab = new DropLab();
+
+const trigger = document.getElementById('trigger');
+const list = document.getElementById('list');
+
+droplab.init(trigger, list, [droplabAjax], {
+ droplabAjax: {
+ endpoint: '/some-endpoint',
+ method: 'setData',
+ },
+});
+```
+
+### Documentation
+
+* [Ajax plugin](plugins/ajax.md)
+* [Filter plugin](plugins/filter.md)
+* [InputSetter plugin](plugins/input_setter.md)
+
+### Development
+
+When plugins are initialised for a droplab trigger+dropdown, DropLab will
+call the plugins `init` function, so this must be implemented in the plugin.
+
+```js
+class MyPlugin {
+ static init() {
+ this.someProp = 'someProp';
+ this.someMethod();
+ }
+
+ static someMethod() {
+ this.otherProp = 'otherProp';
+ }
+}
+
+export default MyPlugin;
+```
diff --git a/doc/development/fe_guide/droplab/plugins/ajax.md b/doc/development/fe_guide/droplab/plugins/ajax.md
new file mode 100644
index 00000000000..9c7e56fa448
--- /dev/null
+++ b/doc/development/fe_guide/droplab/plugins/ajax.md
@@ -0,0 +1,37 @@
+# Ajax
+
+`Ajax` is a droplab plugin that allows for retrieving and rendering list data from a server.
+
+## Usage
+
+Add the `Ajax` object to the plugins array of a `DropLab.prototype.init` or `DropLab.prototype.addHook` call.
+
+`Ajax` requires 2 config values, the `endpoint` and `method`.
+
+* `endpoint` should be a URL to the request endpoint.
+* `method` should be `setData` or `addData`.
+* `setData` completely replaces the dropdown with the response data.
+* `addData` appends the response data to the current dropdown list.
+
+```html
+<a href="#" id="trigger" data-dropdown-trigger="#list">Toggle</a>
+<ul id="list" data-dropdown><!-- ... --><ul>
+```
+```js
+ const droplab = new DropLab();
+
+ const trigger = document.getElementById('trigger');
+ const list = document.getElementById('list');
+
+ droplab.addHook(trigger, list, [Ajax], {
+ Ajax: {
+ endpoint: '/some-endpoint',
+ method: 'setData',
+ },
+ });
+```
+
+Optionally you can set `loadingTemplate` to a HTML string. This HTML string will
+replace the dropdown list whilst the request is pending.
+
+Additionally, you can set `onError` to a function to catch any XHR errors.
diff --git a/doc/development/fe_guide/droplab/plugins/filter.md b/doc/development/fe_guide/droplab/plugins/filter.md
new file mode 100644
index 00000000000..0853ea4d320
--- /dev/null
+++ b/doc/development/fe_guide/droplab/plugins/filter.md
@@ -0,0 +1,45 @@
+# Filter
+
+`Filter` is a plugin that allows for filtering data that has been added
+to the dropdown using a simple fuzzy string search of an input value.
+
+## Usage
+
+Add the `Filter` object to the plugins array of a `DropLab.prototype.init` or `DropLab.prototype.addHook` call.
+
+* `Filter` requires a config value for `template`.
+* `template` should be the key of the objects within your data array that you want to compare
+to the user input string, for filtering.
+
+```html
+<input href="#" id="trigger" data-dropdown-trigger="#list">
+<ul id="list" data-dropdown data-dynamic>
+ <li><a href="#" data-id="{{id}}">{{text}}</a></li>
+<ul>
+```
+```js
+ const droplab = new DropLab();
+
+ const trigger = document.getElementById('trigger');
+ const list = document.getElementById('list');
+
+ droplab.init(trigger, list, [Filter], {
+ Filter: {
+ template: 'text',
+ },
+ });
+
+ droplab.addData('trigger', [{
+ id: 0,
+ text: 'Jacob',
+ }, {
+ id: 1,
+ text: 'Jeff',
+ }]);
+```
+
+Above, the input string will be compared against the `test` key of the passed data objects.
+
+Optionally you can set `filterFunction` to a function. This function will be used instead
+of `Filter`'s built in string search. `filterFunction` is passed 2 arguments, the first
+is one of the data objects, the second is the current input value.
diff --git a/doc/development/fe_guide/droplab/plugins/input_setter.md b/doc/development/fe_guide/droplab/plugins/input_setter.md
new file mode 100644
index 00000000000..a549603c20d
--- /dev/null
+++ b/doc/development/fe_guide/droplab/plugins/input_setter.md
@@ -0,0 +1,60 @@
+# InputSetter
+
+`InputSetter` is a plugin that allows for udating DOM out of the scope of droplab when a list item is clicked.
+
+## Usage
+
+Add the `InputSetter` object to the plugins array of a `DropLab.prototype.init` or `DropLab.prototype.addHook` call.
+
+* `InputSetter` requires a config value for `input` and `valueAttribute`.
+* `input` should be the DOM element that you want to manipulate.
+* `valueAttribute` should be a string that is the name of an attribute on your list items that is used to get the value
+to update the `input` element with.
+
+You can also set the `InputSetter` config to an array of objects, which will allow you to update multiple elements.
+
+
+```html
+<input id="input" value="">
+<div id="div" data-selected-id=""></div>
+
+<input href="#" id="trigger" data-dropdown-trigger="#list">
+<ul id="list" data-dropdown data-dynamic>
+ <li><a href="#" data-id="{{id}}">{{text}}</a></li>
+<ul>
+```
+```js
+ const droplab = new DropLab();
+
+ const trigger = document.getElementById('trigger');
+ const list = document.getElementById('list');
+
+ const input = document.getElementById('input');
+ const div = document.getElementById('div');
+
+ droplab.init(trigger, list, [InputSetter], {
+ InputSetter: [{
+ input: input,
+ valueAttribute: 'data-id',
+ } {
+ input: div,
+ valueAttribute: 'data-id',
+ inputAttribute: 'data-selected-id',
+ }],
+ });
+
+ droplab.addData('trigger', [{
+ id: 0,
+ text: 'Jacob',
+ }, {
+ id: 1,
+ text: 'Jeff',
+ }]);
+```
+
+Above, if the second list item was clicked, it would update the `#input` element
+to have a `value` of `1`, it would also update the `#div` element's `data-selected-id` to `1`.
+
+Optionally you can set `inputAttribute` to a string that is the name of an attribute on your `input` element that you want to update.
+If you do not provide an `inputAttribute`, `InputSetter` will update the `value` of the `input` element if it is an `INPUT` element,
+or the `textContent` of the `input` element if it is not an `INPUT` element.
diff --git a/doc/development/fe_guide/img/boards_diagram.png b/doc/development/fe_guide/img/boards_diagram.png
new file mode 100644
index 00000000000..7a2cf972fd0
--- /dev/null
+++ b/doc/development/fe_guide/img/boards_diagram.png
Binary files differ
diff --git a/doc/development/fe_guide/img/vue_arch.png b/doc/development/fe_guide/img/vue_arch.png
new file mode 100644
index 00000000000..a67706c7c1e
--- /dev/null
+++ b/doc/development/fe_guide/img/vue_arch.png
Binary files differ
diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md
index f963bffde37..e2a198f637f 100644
--- a/doc/development/fe_guide/index.md
+++ b/doc/development/fe_guide/index.md
@@ -27,6 +27,59 @@ For our currently-supported browsers, see our [requirements][requirements].
---
+## Development Process
+
+When you are assigned an issue please follow the next steps:
+
+### Divide a big feature into small Merge Requests
+1. Big Merge Request are painful to review. In order to make this process easier we
+must break a big feature into smaller ones and create a Merge Request for each step.
+1. First step is to create a branch from `master`, let's call it `new-feature`. This branch
+will be the recipient of all the smaller Merge Requests. Only this one will be merged to master.
+1. Don't do any work on this one, let's keep it synced with master.
+1. Create a new branch from `new-feature`, let's call it `new-feature-step-1`. We advise you
+to clearly identify which step the branch represents.
+1. Do the first part of the modifications in this branch. The target branch of this Merge Request
+should be `new-feature`.
+1. Once `new-feature-step-1` gets merged into `new-feature` we can continue our work. Create a new
+branch from `new-feature`, let's call it `new-feature-step-2` and repeat the process done before.
+
+```shell
+* master
+|\
+| * new-feature
+| |\
+| | * new-feature-step-1
+| |\
+| | * new-feature-step-2
+| |\
+| | * new-feature-step-3
+```
+
+**Tips**
+- Make sure `new-feature` branch is always synced with `master`: merge master frequently.
+- Do the same for the feature branch you have opened. This can be accomplished by merging `master` into `new-feature` and `new-feature` into `new-feature-step-*`
+- Avoid rewriting history.
+
+### Share your work early
+1. Before writing code guarantee your vision of the architecture is aligned with
+GitLab's architecture.
+1. Add a diagram to the issue and ask a Frontend Architecture about it.
+
+ ![Diagram of Issue Boards Architecture](img/boards_diagram.png)
+
+1. Don't take more than one week between starting work on a feature and
+sharing a Merge Request with a reviewer or a maintainer.
+
+### Vue features
+1. Follow the steps in [Vue.js Best Practices](vue.md)
+1. Follow the style guide.
+1. Only a handful of people are allowed to merge Vue related features.
+Reach out to @jschatz, @iamphill, @fatihacet or @filipa early in this process.
+
+
+---
+
## [Architecture](architecture.md)
How we go about making fundamental design decisions in GitLab's frontend team
or make changes to our frontend development guidelines.
@@ -90,3 +143,13 @@ Our accessibility standards and resources.
[scss-lint]: https://github.com/brigade/scss-lint
[install]: ../../install/installation.md#4-node
[requirements]: ../../install/requirements.md#supported-web-browsers
+
+---
+
+## [DropLab](droplab/droplab.md)
+Our internal `DropLab` dropdown library.
+
+* [DropLab](droplab/droplab.md)
+* [Ajax plugin](droplab/plugins/ajax.md)
+* [Filter plugin](droplab/plugins/filter.md)
+* [InputSetter plugin](droplab/plugins/input_setter.md)
diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md
index abd241c0bc8..1d2b0558948 100644
--- a/doc/development/fe_guide/style_guide_js.md
+++ b/doc/development/fe_guide/style_guide_js.md
@@ -58,7 +58,7 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns.
import Bar from './bar';
```
-- **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead.
+- **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead.
- When declaring multiple globals, always use one `/* global [name] */` line per variable.
@@ -71,6 +71,16 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns.
/* global Cookies */
/* global jQuery */
```
+
+- Use up to 3 parameters for a function or class. If you need more accept an Object instead.
+
+ ```javascript
+ // bad
+ fn(p1, p2, p3, p4) {}
+
+ // good
+ fn(options) {}
+ ```
#### Modules, Imports, and Exports
- Use ES module syntax to import modules
@@ -168,6 +178,23 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns.
- Avoid constructors with side-effects
+- Prefer `.map`, `.reduce` or `.filter` over `.forEach`
+A forEach will cause side effects, it will be mutating the array being iterated. Prefer using `.map`,
+`.reduce` or `.filter`
+
+ ```javascript
+ const users = [ { name: 'Foo' }, { name: 'Bar' } ];
+
+ // bad
+ users.forEach((user, index) => {
+ user.id = index;
+ });
+
+ // good
+ const usersWithId = users.map((user, index) => {
+ return Object.assign({}, user, { id: index });
+ });
+ ```
#### Parse Strings into Numbers
- `parseInt()` is preferable over `Number()` or `+`
@@ -183,6 +210,19 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns.
parseInt('10', 10);
```
+#### CSS classes used for JavaScript
+- If the class is being used in Javascript it needs to be prepend with `js-`
+ ```html
+ // bad
+ <button class="add-user">
+ Add User
+ </button>
+
+ // good
+ <button class="js-add-user">
+ Add User
+ </button>
+ ```
### Vue.js
@@ -200,6 +240,7 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns.
#### Naming
- **Extensions**: Use `.vue` extension for Vue components.
- **Reference Naming**: Use PascalCase for Vue components and camelCase for their instances:
+
```javascript
// bad
import cardBoard from 'cardBoard';
@@ -217,6 +258,7 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns.
cardBoard: CardBoard
};
```
+
- **Props Naming:**
- Avoid using DOM component prop names.
- Use kebab-case instead of camelCase to provide props in templates.
@@ -243,12 +285,18 @@ See [our current .eslintrc][eslintrc] for specific rules and patterns.
<component v-if="bar"
param="baz" />
+ <button class="btn">Click me</button>
+
// good
<component
v-if="bar"
param="baz"
/>
+ <button class="btn">
+ Click me
+ </button>
+
// if props fit in one line then keep it on the same line
<component bar="bar" />
```
diff --git a/doc/development/fe_guide/testing.md b/doc/development/fe_guide/testing.md
index a4631fd0073..66afbf4db4d 100644
--- a/doc/development/fe_guide/testing.md
+++ b/doc/development/fe_guide/testing.md
@@ -26,6 +26,10 @@ browser and you will not have access to certain APIs, such as
[`Notification`](https://developer.mozilla.org/en-US/docs/Web/API/notification),
which will have to be stubbed.
+### Writing tests
+### Vue.js unit tests
+See this [section][vue-test].
+
### Running frontend tests
`rake karma` runs the frontend-only (JavaScript) tests.
@@ -134,3 +138,4 @@ Scenario: Developer can approve merge request
[jasmine-focus]: https://jasmine.github.io/2.5/focused_specs.html
[jasmine-jquery]: https://github.com/velesin/jasmine-jquery
[karma]: http://karma-runner.github.io/
+[vue-test]:https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index 3e3406e7d6a..73d2ffc1bdc 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -19,13 +19,31 @@ We don't want to refactor all GitLab frontend code into Vue.js, here are some gu
when not to use Vue.js:
- Adding or changing static information;
-- Features that highly depend on jQuery will be hard to work with Vue.js
+- Features that highly depend on jQuery will be hard to work with Vue.js;
+- Features without reactive data;
As always, the Frontend Architectural Experts are available to help with any Vue or JavaScript questions.
-## How to build a new feature with Vue.js
+## Vue architecture
-**Components, Stores and Services**
+All new features built with Vue.js must follow a [Flux architecture][flux].
+The main goal we are trying to achieve is to have only one data flow and only one data entry.
+In order to achieve this goal, each Vue bundle needs a Store - where we keep all the data -,
+a Service - that we use to communicate with the server - and a main Vue component.
+
+Think of the Main Vue Component as the entry point of your application. This is the only smart
+component that should exist in each Vue feature.
+This component is responsible for:
+1. Calling the Service to get data from the server
+1. Calling the Store to store the data received
+1. Mounting all the other components
+
+ ![Vue Architecture](img/vue_arch.png)
+
+You can also read about this architecture in vue docs about [state management][state-management]
+and about [one way data flow][one-way-data-flow].
+
+### Components, Stores and Services
In some features implemented with Vue.js, like the [issue board][issue-boards]
or [environments table][environments-table]
@@ -46,16 +64,17 @@ _For consistency purposes, we recommend you to follow the same structure._
Let's look into each of them:
-**A `*_bundle.js` file**
+### A `*_bundle.js` file
This is the index file of your new feature. This is where the root Vue instance
of the new feature should be.
-The Store and the Service should be imported and initialized in this file and provided as a prop to the main component.
+The Store and the Service should be imported and initialized in this file and
+provided as a prop to the main component.
Don't forget to follow [these steps.][page_specific_javascript]
-**A folder for Components**
+### A folder for Components
This folder holds all components that are specific of this new feature.
If you need to use or create a component that will probably be used somewhere
@@ -70,20 +89,219 @@ in one table would not be a good use of this pattern.
You can read more about components in Vue.js site, [Component System][component-system]
-**A folder for the Store**
+### A folder for the Store
The Store is a class that allows us to manage the state in a single
-source of truth.
+source of truth. It is not aware of the service or the components.
The concept we are trying to follow is better explained by Vue documentation
itself, please read this guide: [State Management][state-management]
-**A folder for the Service**
+### A folder for the Service
+
+The Service is a class used only to communicate with the server.
+It does not store or manipulate any data. It is not aware of the store or the components.
+We use [vue-resource][vue-resource-repo] to communicate with the server.
+
+Vue Resource should only be imported in the service file.
+
+ ```javascript
+ import Vue from 'vue';
+ import VueResource from 'vue-resource';
+
+ Vue.use(VueResource);
+ ```
+
+### CSRF token
+We use a Vue Resource interceptor to manage the CSRF token.
+`app/assets/javascripts/vue_shared/vue_resource_interceptor.js` holds all our common interceptors.
+Note: You don't need to load `app/assets/javascripts/vue_shared/vue_resource_interceptor.js`
+since it's already being loaded by `common_vue.js`.
+
+### End Result
+
+The following example shows an application:
+
+```javascript
+// store.js
+export default class Store {
+
+ /**
+ * This is where we will iniatialize the state of our data.
+ * Usually in a small SPA you don't need any options when starting the store. In the case you do
+ * need guarantee it's an Object and it's documented.
+ *
+ * @param {Object} options
+ */
+ constructor(options) {
+ this.options = options;
+
+ // Create a state object to handle all our data in the same place
+ this.todos = []:
+ }
+
+ setTodos(todos = []) {
+ this.todos = todos;
+ }
+
+ addTodo(todo) {
+ this.todos.push(todo);
+ }
+
+ removeTodo(todoID) {
+ const state = this.todos;
+
+ const newState = state.filter((element) => {element.id !== todoID});
+
+ this.todos = newState;
+ }
+}
+
+// service.js
+import Vue from 'vue';
+import VueResource from 'vue-resource';
+import 'vue_shared/vue_resource_interceptor';
+
+Vue.use(VueResource);
+
+export default class Service {
+ constructor(options) {
+ this.todos = Vue.resource(endpoint.todosEndpoint);
+ }
+
+ getTodos() {
+ return this.todos.get();
+ }
+
+ addTodo(todo) {
+ return this.todos.put(todo);
+ }
+}
+// todo_component.vue
+<script>
+export default {
+ props: {
+ data: {
+ type: Object,
+ required: true,
+ },
+ }
+}
+</script>
+<template>
+ <div>
+ <h1>
+ Title: {{data.title}}
+ </h1>
+ <p>
+ {{data.text}}
+ </p>
+ </div>
+</template>
+
+// todos_main_component.vue
+<script>
+import Store from 'store';
+import Service from 'service';
+import TodoComponent from 'todoComponent';
+export default {
+ /**
+ * Although most data belongs in the store, each component it's own state.
+ * We want to show a loading spinner while we are fetching the todos, this state belong
+ * in the component.
+ *
+ * We need to access the store methods through all methods of our component.
+ * We need to access the state of our store.
+ */
+ data() {
+ const store = new Store();
+
+ return {
+ isLoading: false,
+ store: store,
+ todos: store.todos,
+ };
+ },
+
+ components: {
+ todo: TodoComponent,
+ },
+
+ created() {
+ this.service = new Service('todos');
+
+ this.getTodos();
+ },
+
+ methods: {
+ getTodos() {
+ this.isLoading = true;
+
+ this.service.getTodos()
+ .then(response => response.json())
+ .then((response) => {
+ this.store.setTodos(response);
+ this.isLoading = false;
+ })
+ .catch(() => {
+ this.isLoading = false;
+ // Show an error
+ });
+ },
+
+ addTodo(todo) {
+ this.service.addTodo(todo)
+ then(response => response.json())
+ .then((response) => {
+ this.store.addTodo(response);
+ })
+ .catch(() => {
+ // Show an error
+ });
+ }
+ }
+}
+</script>
+<template>
+ <div class="container">
+ <div v-if="isLoading">
+ <i
+ class="fa fa-spin fa-spinner"
+ aria-hidden="true" />
+ </div>
+
+ <div
+ v-if="!isLoading"
+ class="js-todo-list">
+ <template v-for='todo in todos'>
+ <todo :data="todo" />
+ </template>
+
+ <button
+ @click="addTodo"
+ class="js-add-todo">
+ Add Todo
+ </button>
+ </div>
+ <div>
+</template>
+
+// bundle.js
+import todoComponent from 'todos_main_component.vue';
+
+new Vue({
+ el: '.js-todo-app',
+ components: {
+ todoComponent,
+ },
+ render: createElement => createElement('todo-component' {
+ props: {
+ someProp: [],
+ }
+ }),
+});
-The Service is used only to communicate with the server.
-It does not store or manipulate any data.
-We use [vue-resource][vue-resource-repo] to
-communicate with the server.
+```
The [issue boards service][issue-boards-service]
is a good example of this pattern.
@@ -93,6 +311,114 @@ is a good example of this pattern.
Please refer to the Vue section of our [style guide](style_guide_js.md#vuejs)
for best practices while writing your Vue components and templates.
+## Testing Vue Components
+
+Each Vue component has a unique output. This output is always present in the render function.
+
+Although we can test each method of a Vue component individually, our goal must be to test the output
+of the render/template function, which represents the state at all times.
+
+Make use of Vue Resource Interceptors to mock data returned by the service.
+
+Here's how we would test the Todo App above:
+
+```javascript
+import component from 'todos_main_component';
+
+describe('Todos App', () => {
+ it('should render the loading state while the request is being made', () => {
+ const Component = Vue.extend(component);
+
+ const vm = new Component().$mount();
+
+ expect(vm.$el.querySelector('i.fa-spin')).toBeDefined();
+ });
+
+ describe('with data', () => {
+ // Mock the service to return data
+ const interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify([{
+ title: 'This is a todo',
+ body: 'This is the text'
+ }]), {
+ status: 200,
+ }));
+ };
+
+ let vm;
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+
+ const Component = Vue.extend(component);
+
+ vm = new Component().$mount();
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+
+ it('should render todos', (done) => {
+ setTimeout(() => {
+ expect(vm.$el.querySelectorAll('.js-todo-list div').length).toBe(1);
+ done();
+ }, 0);
+ });
+ });
+
+ describe('add todo', () => {
+ let vm;
+ beforeEach(() => {
+ const Component = Vue.extend(component);
+ vm = new Component().$mount();
+ });
+ it('should add a todos', (done) => {
+ setTimeout(() => {
+ vm.$el.querySelector('.js-add-todo').click();
+
+ // Add a new interceptor to mock the add Todo request
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelectorAll('.js-todo-list div').length).toBe(2);
+ });
+ }, 0);
+ });
+ });
+});
+```
+
+### Stubbing API responses
+[Vue Resource Interceptors][vue-resource-interceptor] allow us to add a interceptor with
+the response we need:
+
+```javascript
+ // Mock the service to return data
+ const interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify([{
+ title: 'This is a todo',
+ body: 'This is the text'
+ }]), {
+ status: 200,
+ }));
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ it('should do something', (done) => {
+ setTimeout(() => {
+ // Test received data
+ done();
+ }, 0);
+ });
+```
+
[vue-docs]: http://vuejs.org/guide/index.html
[issue-boards]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/boards
@@ -100,5 +426,8 @@ for best practices while writing your Vue components and templates.
[page_specific_javascript]: https://docs.gitlab.com/ce/development/frontend.html#page-specific-javascript
[component-system]: https://vuejs.org/v2/guide/#Composing-with-Components
[state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch
+[one-way-data-flow]: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow
[vue-resource-repo]: https://github.com/pagekit/vue-resource
+[vue-resource-interceptor]: https://github.com/pagekit/vue-resource/blob/develop/docs/http.md#interceptors
[issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6
+[flux]: https://facebook.github.io/flux
diff --git a/doc/development/writing_documentation.md b/doc/development/writing_documentation.md
index 482ec54207b..166a10293c3 100644
--- a/doc/development/writing_documentation.md
+++ b/doc/development/writing_documentation.md
@@ -2,7 +2,7 @@
- **General Documentation**: written by the developers responsible by creating features. Should be submitted in the same merge request containing code. Feature proposals (by GitLab contributors) should also be accompanied by its respective documentation. They can be later improved by PMs and Technical Writers.
- **Technical Articles**: written by any [GitLab Team](https://about.gitlab.com/team/) member, GitLab contributors, or [Community Writers](https://about.gitlab.com/handbook/product/technical-writing/community-writers/).
- - **Indexes per topic**: initially prepared by the Technical Writing Team, and kept up-to-date by developers and PMs, in the same merge request containing code.
+ - **Indexes per topic**: initially prepared by the Technical Writing Team, and kept up-to-date by developers and PMs in the same merge request containing code. They gather all resources for that topic in a single page (user and admin documentation, articles, and third-party docs).
## Distinction between General Documentation and Technical Articles
@@ -18,7 +18,7 @@ They are topic-related documentation, written with an user-friendly approach and
A technical article guides users and/or admins to achieve certain objectives (within guides and tutorials), or provide an overview of that particular topic or feature (within technical overviews). It can also describe the use, implementation, or integration of third-party tools with GitLab.
-They live under `doc/topics/topic-name/`, and can be searched per topic, within "Indexes per Topic" pages. The topics are listed on the main [Indexes per Topic](../topics/index.md) page.
+They live under `doc/articles/article-title/index.md`, and their images should be placed under `doc/articles/article-title/img/`. Find a list of existing [technical articles](../articles/index.md) here.
#### Types of Technical Articles
diff --git a/doc/intro/README.md b/doc/intro/README.md
index 1df6a52ce8a..d52b180a076 100644
--- a/doc/intro/README.md
+++ b/doc/intro/README.md
@@ -13,7 +13,7 @@ Create issues, labels, milestones, cast your vote, and review issues.
- [Create a new issue](../gitlab-basics/create-issue.md)
- [Assign labels to issues](../user/project/labels.md)
-- [Use milestones as an overview of your project's tracker](../workflow/milestones.md)
+- [Use milestones as an overview of your project's tracker](../user/project/milestones/index.md)
- [Use voting to express your like/dislike to issues and merge requests](../workflow/award_emoji.md)
## Collaborate
diff --git a/doc/university/glossary/README.md b/doc/university/glossary/README.md
index 0b17e4ff7c1..591d1524061 100644
--- a/doc/university/glossary/README.md
+++ b/doc/university/glossary/README.md
@@ -333,7 +333,7 @@ A [platform](https://www.meteor.com) for building javascript apps.
### Milestones
-Allow you to [organize issues](https://docs.gitlab.com/ce/workflow/milestones.html) and merge requests in GitLab into a cohesive group, optionally setting a due date. A common use is keeping track of an upcoming software version. Milestones are created per-project.
+Allow you to [organize issues](../../user/project/milestones/index.md) and merge requests in GitLab into a cohesive group, optionally setting a due date. A common use is keeping track of an upcoming software version. Milestones are created per-project.
### Mirror Repositories
diff --git a/doc/user/admin_area/img/cohorts.png b/doc/user/admin_area/img/cohorts.png
new file mode 100644
index 00000000000..8bae7faff07
--- /dev/null
+++ b/doc/user/admin_area/img/cohorts.png
Binary files differ
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
new file mode 100644
index 00000000000..c3f3179d99e
--- /dev/null
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -0,0 +1,102 @@
+# Usage statistics
+
+GitLab Inc. will periodically collect information about your instance in order
+to perform various actions.
+
+All statistics are opt-in and you can always disable them from the admin panel.
+
+## Version check
+
+GitLab can inform you when an update is available and the importance of it.
+
+No information other than the GitLab version and the instance's domain name
+are collected.
+
+In the **Overview** tab you can see if your GitLab version is up to date. There
+are three cases: 1) you are up to date (green), 2) there is an update available
+(yellow) and 3) your version is vulnerable and a security fix is released (red).
+
+In any case, you will see a message informing you of the state and the
+importance of the update.
+
+If enabled, the version status will also be shown in the help page (`/help`)
+for all signed in users.
+
+## Usage ping
+
+> [Introduced][ee-557] in GitLab Enterprise Edition 8.10. More statistics
+[were added][ee-735] in GitLab Enterprise Edition
+8.12. [Moved to GitLab Community Edition][ce-23361] in 9.1.
+
+GitLab Inc. can collect non-sensitive information about how GitLab users
+use their GitLab instance upon the activation of a ping feature
+located in the admin panel (`/admin/application_settings`).
+
+You can see the **exact** JSON payload that your instance sends to GitLab
+in the "Usage statistics" section of the admin panel.
+
+Nothing qualitative is collected. Only quantitative. That means no project
+names, author names, comment bodies, names of labels, etc.
+
+The usage ping is sent in order for GitLab Inc. to have a better understanding
+of how our users use our product, and to be more data-driven when creating or
+changing features.
+
+The total number of the following is sent back to GitLab Inc.:
+
+- Comments
+- Groups
+- Users
+- Projects
+- Issues
+- Labels
+- CI builds
+- Snippets
+- Milestones
+- Todos
+- Pushes
+- Merge requests
+- Environments
+- Triggers
+- Deploy keys
+- Pages
+- Project Services
+- Projects using the Prometheus service
+- Issue Boards
+- CI Runners
+- Deployments
+- Geo Nodes
+- LDAP Groups
+- LDAP Keys
+- LDAP Users
+- LFS objects
+- Protected branches
+- Releases
+- Remote mirrors
+- Uploads
+- Web hooks
+
+Also, we track if you've installed Mattermost with GitLab.
+For example: `"mattermost_enabled":true"`.
+
+More data will be added over time. The goal of this ping is to be as light as
+possible, so it won't have any performance impact on your installation when
+the calculation is made.
+
+### Deactivate the usage ping
+
+By default, usage ping is opt-out. If you want to deactivate this feature, go to
+the Settings page of your administration panel and uncheck the Usage ping
+checkbox.
+
+## Privacy policy
+
+GitLab Inc. does **not** collect any sensitive information, like project names
+or the content of the comments. GitLab Inc. does not disclose or otherwise make
+available any of the data collected on a customer specific basis.
+
+Read more about this in the [Privacy policy](https://about.gitlab.com/privacy).
+
+[ee-557]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/557
+[ee-735]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/735
+[ce-23361]: https://gitlab.com/gitlab-org/gitlab-ce/issues/23361
diff --git a/doc/user/admin_area/user_cohorts.md b/doc/user/admin_area/user_cohorts.md
new file mode 100644
index 00000000000..e25e7a8bbc3
--- /dev/null
+++ b/doc/user/admin_area/user_cohorts.md
@@ -0,0 +1,37 @@
+# Cohorts
+
+> **Notes:**
+> [Introduced][ce-23361] in GitLab 9.1.
+
+As a benefit of having the [usage ping active](settings/usage_statistics.md),
+GitLab lets you analyze the users' activities of your GitLab installation.
+Under `/admin/cohorts`, when the usage ping is active, GitLab will show the
+monthly cohorts of new users and their activities over time.
+
+## Overview
+
+How do we read the user cohorts table? Let's take an example with the following
+user cohorts.
+
+![User cohort example](img/cohorts.png)
+
+For the cohort of June 2016, 163 users have been added on this server and have
+been active since this month. One month later, in July 2016, out of
+these 163 users, 155 users (or 95% of the June cohort) are still active. Two
+months later, 139 users (or 85%) are still active. 9 months later, we can see
+that only 6% of this cohort are still active.
+
+The Inactive users column shows the number of users who have been added during
+the month, but who have never actually had any activity in the instance.
+
+How do we measure the activity of users? GitLab considers a user active if:
+
+* the user signs in
+* the user has Git activity (whether push or pull).
+
+## Setup
+
+1. [Activate the usage ping](settings/usage_statistics.md)
+2. Go to `/admin/cohorts` to see the user cohorts of the server
+
+[ce-23361]: https://gitlab.com/gitlab-org/gitlab-ce/issues/23361
diff --git a/doc/user/project/merge_requests/img/btn_new_issue_for_all_discussions.png b/doc/user/discussions/img/btn_new_issue_for_all_discussions.png
index b15447ec290..b15447ec290 100644
--- a/doc/user/project/merge_requests/img/btn_new_issue_for_all_discussions.png
+++ b/doc/user/discussions/img/btn_new_issue_for_all_discussions.png
Binary files differ
diff --git a/doc/user/discussions/img/comment_type_toggle.gif b/doc/user/discussions/img/comment_type_toggle.gif
new file mode 100644
index 00000000000..b73c197b97f
--- /dev/null
+++ b/doc/user/discussions/img/comment_type_toggle.gif
Binary files differ
diff --git a/doc/user/discussions/img/discussion_comment.png b/doc/user/discussions/img/discussion_comment.png
new file mode 100644
index 00000000000..8f66d138922
--- /dev/null
+++ b/doc/user/discussions/img/discussion_comment.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/discussion_view.png b/doc/user/discussions/img/discussion_view.png
index 2ee1db2eab3..2ee1db2eab3 100644
--- a/doc/user/project/merge_requests/img/discussion_view.png
+++ b/doc/user/discussions/img/discussion_view.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/discussions_resolved.png b/doc/user/discussions/img/discussions_resolved.png
index 3fd496f6da5..3fd496f6da5 100644
--- a/doc/user/project/merge_requests/img/discussions_resolved.png
+++ b/doc/user/discussions/img/discussions_resolved.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/new_issue_for_discussion.png b/doc/user/discussions/img/new_issue_for_discussion.png
index 93c9dad8921..93c9dad8921 100644
--- a/doc/user/project/merge_requests/img/new_issue_for_discussion.png
+++ b/doc/user/discussions/img/new_issue_for_discussion.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved.png b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved.png
index 928c7d33898..928c7d33898 100644
--- a/doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved.png
+++ b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved_msg.png b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png
index bcdc0250d7c..bcdc0250d7c 100644
--- a/doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved_msg.png
+++ b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/preview_issue_for_discussion.png b/doc/user/discussions/img/preview_issue_for_discussion.png
index 2ee0653b2ba..2ee0653b2ba 100644
--- a/doc/user/project/merge_requests/img/preview_issue_for_discussion.png
+++ b/doc/user/discussions/img/preview_issue_for_discussion.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/preview_issue_for_discussions.png b/doc/user/discussions/img/preview_issue_for_discussions.png
index 3fe0a666678..3fe0a666678 100644
--- a/doc/user/project/merge_requests/img/preview_issue_for_discussions.png
+++ b/doc/user/discussions/img/preview_issue_for_discussions.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/resolve_comment_button.png b/doc/user/discussions/img/resolve_comment_button.png
index 70340108874..70340108874 100644
--- a/doc/user/project/merge_requests/img/resolve_comment_button.png
+++ b/doc/user/discussions/img/resolve_comment_button.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/resolve_discussion_button.png b/doc/user/discussions/img/resolve_discussion_button.png
index ab454f661e0..ab454f661e0 100644
--- a/doc/user/project/merge_requests/img/resolve_discussion_button.png
+++ b/doc/user/discussions/img/resolve_discussion_button.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/resolve_discussion_issue_notice.png b/doc/user/discussions/img/resolve_discussion_issue_notice.png
index e0ee6a39ffd..e0ee6a39ffd 100644
--- a/doc/user/project/merge_requests/img/resolve_discussion_issue_notice.png
+++ b/doc/user/discussions/img/resolve_discussion_issue_notice.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/resolve_discussion_open_issue.png b/doc/user/discussions/img/resolve_discussion_open_issue.png
index 98d63278326..98d63278326 100644
--- a/doc/user/project/merge_requests/img/resolve_discussion_open_issue.png
+++ b/doc/user/discussions/img/resolve_discussion_open_issue.png
Binary files differ
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
new file mode 100644
index 00000000000..c5123c06ce0
--- /dev/null
+++ b/doc/user/discussions/index.md
@@ -0,0 +1,150 @@
+# Discussions
+
+The ability to contribute conversationally is offered throughout GitLab.
+
+You can leave a comment in the following places:
+
+- issues
+- merge requests
+- snippets
+- commits
+- commit diffs
+
+The comment area supports [Markdown] and [slash commands]. One can edit their
+own comment at any time, and anyone with [Master access level][permissions] or
+higher can also a comment made by someone else.
+
+Apart from the standard comments, you also have the option to create a comment
+in the form of a resolvable or threaded discussion.
+
+## Resolvable discussions
+
+>**Notes:**
+- The main feature was [introduced][ce-5022] in GitLab 8.11.
+- Resolvable discussions can be added only to merge request diffs.
+
+Discussion resolution helps keep track of progress during planning or code review.
+Resolving comments prevents you from forgetting to address feedback and lets you
+hide discussions that are no longer relevant.
+
+!["A discussion between two people on a piece of code"][discussion-view]
+
+Comments and discussions can be resolved by anyone with at least Developer
+access to the project or the author of the merge request.
+
+### Jumping between unresolved discussions
+
+When a merge request has a large number of comments it can be difficult to track
+what remains unresolved. You can jump between unresolved discussions with the
+Jump button next to the Reply field on a discussion.
+
+You can also jump to the first unresolved discussion from the button next to the
+resolved discussions tracker.
+
+!["3/4 discussions resolved"][discussions-resolved]
+
+### Marking a comment or discussion as resolved
+
+You can mark a discussion as resolved by clicking the **Resolve discussion**
+button at the bottom of the discussion.
+
+!["Resolve discussion" button][resolve-discussion-button]
+
+Alternatively, you can mark each comment as resolved individually.
+
+!["Resolve comment" button][resolve-comment-button]
+
+### Move all unresolved discussions in a merge request to an issue
+
+> [Introduced][ce-8266] in GitLab 9.1
+
+To continue all open discussions from a merge request in a new issue, click the
+**Resolve all discussions in new issue** button.
+
+![Open new issue for all unresolved discussions](img/btn_new_issue_for_all_discussions.png)
+
+Alternatively, when your project only accepts merge requests [when all discussions
+are resolved](#only-allow-merge-requests-to-be-merged-if-all-discussions-are-resolved),
+there will be an **open an issue to resolve them later** link in the merge
+request widget.
+
+![Link in merge request widget](img/resolve_discussion_open_issue.png)
+
+This will prepare an issue with its content referring to the merge request and
+the unresolved discussions.
+
+![Issue mentioning discussions in a merge request](img/preview_issue_for_discussions.png)
+
+Hitting **Submit issue** will cause all discussions to be marked as resolved and
+add a note referring to the newly created issue.
+
+![Mark discussions as resolved notice](img/resolve_discussion_issue_notice.png)
+
+You can now proceed to merge the merge request from the UI.
+
+### Moving a single discussion to a new issue
+
+> [Introduced][ce-8266] in GitLab 9.1
+
+To create a new issue for a single discussion, you can use the **Resolve this
+discussion in a new issue** button.
+
+![Create issue for discussion](img/new_issue_for_discussion.png)
+
+This will direct you to a new issue prefilled with the content of the
+discussion, similar to the issues created for delegating multiple
+discussions at once. Saving the issue will mark the discussion as resolved and
+add a note to the merge request discussion referencing the new issue.
+
+![New issue for a single discussion](img/preview_issue_for_discussion.png)
+
+### Only allow merge requests to be merged if all discussions are resolved
+
+> [Introduced][ce-7125] in GitLab 8.14.
+
+You can prevent merge requests from being merged until all discussions are
+resolved.
+
+Navigate to your project's settings page, select the
+**Only allow merge requests to be merged if all discussions are resolved** check
+box and hit **Save** for the changes to take effect.
+
+![Only allow merge if all the discussions are resolved settings](img/only_allow_merge_if_all_discussions_are_resolved.png)
+
+From now on, you will not be able to merge from the UI until all discussions
+are resolved.
+
+![Only allow merge if all the discussions are resolved message](img/only_allow_merge_if_all_discussions_are_resolved_msg.png)
+
+## Threaded discussions
+
+> [Introduced][ce-7527] in GitLab 9.1.
+
+While resolvable discussions are only available to merge request diffs,
+discussions can also be added without a diff. You can start a specific
+discussion which will look like a thread, on issues, commits, snippets, and
+merge requests.
+
+To start a threaded discussion, click on the **Comment** button toggle dropdown,
+select **Start discussion** and click **Start discussion** when you're ready to
+post the comment.
+
+![Comment type toggle](img/comment_type_toggle.gif)
+
+This will post a comment with a single thread to allow you to discuss specific
+comments in greater detail.
+
+![Discussion comment](img/discussion_comment.png)
+
+[ce-5022]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5022
+[ce-7125]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7125
+[ce-7527]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7527
+[ce-7180]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7180
+[ce-8266]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8266
+[resolve-discussion-button]: img/resolve_discussion_button.png
+[resolve-comment-button]: img/resolve_comment_button.png
+[discussion-view]: img/discussion_view.png
+[discussions-resolved]: img/discussions_resolved.png
+[markdown]: ../markdown.md
+[slash commands]: ../project/slash_commands.md
+[permissions]: ../permissions.md
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 3122e95fc0e..637967510f3 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -7,6 +7,9 @@ project itself, the highest permission level is used.
On public and internal projects the Guest role is not enforced. All users will
be able to create issues, leave comments, and pull or download the project code.
+When a member leaves the team the all assigned Issues and Merge Requests
+will be unassigned automatically.
+
GitLab administrators receive all permissions.
To add or import a user, you can follow the [project users and members
diff --git a/doc/user/project/integrations/kubernetes.md b/doc/user/project/integrations/kubernetes.md
index f7d5e3a8ab2..73fa83d72a8 100644
--- a/doc/user/project/integrations/kubernetes.md
+++ b/doc/user/project/integrations/kubernetes.md
@@ -48,8 +48,12 @@ GitLab CI build environment:
- `KUBE_URL` - equal to the API URL
- `KUBE_TOKEN`
-- `KUBE_NAMESPACE`
-- `KUBE_CA_PEM_FILE` - only present if a custom CA bundle was specified. Path to a file containing PEM data.
+- `KUBE_NAMESPACE` - The Kubernetes namespace is auto-generated if not specified.
+ The default value is `<project_name>-<project_id>`. You can overwrite it to
+ use different one if needed, otherwise the `KUBE_NAMESPACE` variable will
+ receive the default value.
+- `KUBE_CA_PEM_FILE` - only present if a custom CA bundle was specified. Path
+ to a file containing PEM data.
- `KUBE_CA_PEM` (deprecated)- only if a custom CA bundle was specified. Raw PEM data.
## Web terminals
diff --git a/doc/user/project/integrations/microsoft_teams.md b/doc/user/project/integrations/microsoft_teams.md
index fbf9c1de443..eaad2d5138a 100644
--- a/doc/user/project/integrations/microsoft_teams.md
+++ b/doc/user/project/integrations/microsoft_teams.md
@@ -1,8 +1,8 @@
-# Microsoft Teams Service
+# Microsoft Teams service
## On Microsoft Teams
-To enable Microsoft Teams integration you must create an incoming webhook integration on Microsoft Teams by following the steps described in this [document](https://msdn.microsoft.com/en-us/microsoft-teams/connectors)
+To enable Microsoft Teams integration you must create an incoming webhook integration on Microsoft Teams by following the steps described in this [document](https://msdn.microsoft.com/en-us/microsoft-teams/connectors).
## On GitLab
@@ -30,4 +30,4 @@ At the end fill in your Microsoft Teams details:
After you are all done, click **Save changes** for the changes to take effect.
-![Microsoft Teams configuration](img/microsoft_teams_configuration.png) \ No newline at end of file
+![Microsoft Teams configuration](img/microsoft_teams_configuration.png)
diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md
index 25400633de5..96c91093d7d 100644
--- a/doc/user/project/integrations/project_services.md
+++ b/doc/user/project/integrations/project_services.md
@@ -47,6 +47,7 @@ Click on the service links to see further configuration instructions and details
| [Kubernetes](kubernetes.md) | A containerized deployment service |
| [Mattermost slash commands](mattermost_slash_commands.md) | Mattermost chat and ChatOps slash commands |
| [Mattermost Notifications](mattermost.md) | Receive event notifications in Mattermost |
+| [Microsoft teams](microsoft_teams.md) | Receive notifications for actions that happen on GitLab into a room on Microsoft Teams using Office 365 Connectors |
| Pipelines emails | Email the pipeline status to a list of recipients |
| [Slack Notifications](slack.md) | Receive event notifications in Slack |
| [Slack slash commands](slack_slash_commands.md) | Slack chat and ChatOps slash commands |
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index c759b7aaa4a..954454f7e7a 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -34,7 +34,7 @@ Keep track of the progress during a code review with resolving comments.
Resolving comments prevents you from forgetting to address feedback and lets
you hide discussions that are no longer relevant.
-[Read more about resolving discussion comments in merge requests reviews.](merge_request_discussion_resolution.md)
+[Read more about resolving discussion comments in merge requests reviews.](../../discussions/index.md)
## Resolve conflicts
diff --git a/doc/user/project/merge_requests/merge_request_discussion_resolution.md b/doc/user/project/merge_requests/merge_request_discussion_resolution.md
index 230e957f045..200965875a1 100644
--- a/doc/user/project/merge_requests/merge_request_discussion_resolution.md
+++ b/doc/user/project/merge_requests/merge_request_discussion_resolution.md
@@ -1,106 +1 @@
-# Merge Request discussion resolution
-
-> [Introduced][ce-5022] in GitLab 8.11.
-
-Discussion resolution helps keep track of progress during code review.
-Resolving comments prevents you from forgetting to address feedback and lets you
-hide discussions that are no longer relevant.
-
-!["A discussion between two people on a piece of code"][discussion-view]
-
-Comments and discussions can be resolved by anyone with at least Developer
-access to the project, as well as by the author of the merge request.
-
-## Marking a comment or discussion as resolved
-
-You can mark a discussion as resolved by clicking the "Resolve discussion"
-button at the bottom of the discussion.
-
-!["Resolve discussion" button][resolve-discussion-button]
-
-Alternatively, you can mark each comment as resolved individually.
-
-!["Resolve comment" button][resolve-comment-button]
-
-## Jumping between unresolved discussions
-
-When a merge request has a large number of comments it can be difficult to track
-what remains unresolved. You can jump between unresolved discussions with the
-Jump button next to the Reply field on a discussion.
-
-You can also jump to the first unresolved discussion from the button next to the
-resolved discussions tracker.
-
-!["3/4 discussions resolved"][discussions-resolved]
-
-## Only allow merge requests to be merged if all discussions are resolved
-
-> [Introduced][ce-7125] in GitLab 8.14.
-
-You can prevent merge requests from being merged until all discussions are
-resolved.
-
-Navigate to your project's settings page, select the
-**Only allow merge requests to be merged if all discussions are resolved** check
-box and hit **Save** for the changes to take effect.
-
-![Only allow merge if all the discussions are resolved settings](img/only_allow_merge_if_all_discussions_are_resolved.png)
-
-From now on, you will not be able to merge from the UI until all discussions
-are resolved.
-
-![Only allow merge if all the discussions are resolved message](img/only_allow_merge_if_all_discussions_are_resolved_msg.png)
-
-## Move all unresolved discussions in a merge request to an issue
-
-> [Introduced][ce-8266]
-
-To continue all open discussions in a merge request, click the button **Resolve
-all discussions in new issue**
-
-![Open new issue for all unresolved discussions](img/btn_new_issue_for_all_discussions.png)
-
-Alternatively, when your project only accepts merge requests when all discussions
-are resolved, there will be an **open an issue to resolve them later** link in
-the merge request-widget.
-
-![Link in merge request widget](img/resolve_discussion_open_issue.png)
-
-This will prepare an issue with content referring to the merge request and
-discussions.
-
-![Issue mentioning discussions in a merge request](img/preview_issue_for_discussions.png)
-
-Hitting **Submit issue** will cause all discussions to be marked as resolved and
-add a note referring to the newly created issue.
-
-![Mark discussions as resolved notice](img/resolve_discussion_issue_notice.png)
-
-You can now proceed to merge the merge request from the UI.
-
-## Moving a single discussion to a new issue
-
-> [Introduced][ce-8266]
-
-To create a new issue for a single discussion, you can use the **Resolve this
-discussion in a new issue** button.
-
-![Create issue for discussion](img/new_issue_for_discussion.png)
-
-This will direct you to a new issue prefilled with the content of the
-discussion, similar to the issues created for delegating multiple
-discussions at once.
-
-![New issue for a single discussion](img/preview_issue_for_discussion.png)
-
-Saving the issue will mark the discussion as resolved and add a note
-to the discussion referencing the new issue.
-
-[ce-5022]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5022
-[ce-7125]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7125
-[ce-7180]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7180
-[ce-8266]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8266
-[resolve-discussion-button]: img/resolve_discussion_button.png
-[resolve-comment-button]: img/resolve_comment_button.png
-[discussion-view]: img/discussion_view.png
-[discussions-resolved]: img/discussions_resolved.png
+This document was moved to [another location](../../discussions/index.md).
diff --git a/doc/user/project/milestones/img/milestone_create.png b/doc/user/project/milestones/img/milestone_create.png
new file mode 100644
index 00000000000..beb2caa897f
--- /dev/null
+++ b/doc/user/project/milestones/img/milestone_create.png
Binary files differ
diff --git a/doc/user/project/milestones/img/milestone_group_create.png b/doc/user/project/milestones/img/milestone_group_create.png
new file mode 100644
index 00000000000..7aaa7c56c15
--- /dev/null
+++ b/doc/user/project/milestones/img/milestone_group_create.png
Binary files differ
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
new file mode 100644
index 00000000000..a43a42a8fe8
--- /dev/null
+++ b/doc/user/project/milestones/index.md
@@ -0,0 +1,46 @@
+# Milestones
+
+Milestones allow you to organize issues and merge requests into a cohesive group,
+optionally setting a due date. A common use is keeping track of an upcoming
+software version. Milestones can be created per-project or per-group.
+
+## Creating a project milestone
+
+>**Note:**
+You need [Master permissions](../../permissions.md) in order to create a milestone.
+
+You can find the milestones page under your project's **Issues ➔ Milestones**.
+To create a new milestone, simply click the **New milestone** button when in the
+milestones page. A milestone can have a title, a description and start/due dates.
+Once you fill in all the details, hit the **Create milestone** button.
+
+![Creating a milestone](img/milestone_create.png)
+
+## Creating a group milestone
+
+>**Note:**
+You need [Master permissions](../../permissions.md) in order to create a milestone.
+
+You can create a milestone for several projects in the same group simultaneously.
+On the group's **Issues ➔ Milestones** page, you will be able to see the status
+of that milestone across all of the selected projects. To create a new milestone
+for selected projects in the group, click the **New milestone** button. The
+form is the same as when creating a milestone for a specific project with the
+addition of the selection of the projects you want to inherit this milestone.
+
+![Creating a group milestone](img/milestone_group_create.png)
+
+## Special milestone filters
+
+In addition to the milestones that exist in the project or group, there are some
+special options available when filtering by milestone:
+
+* **No Milestone** - only show issues or merge requests without a milestone.
+* **Upcoming** - show issues or merge request that belong to the next open
+ milestone with a due date, by project. (For example: if project A has
+ milestone v1 due in three days, and project B has milestone v2 due in a week,
+ then this will show issues or merge requests from milestone v1 in project A
+ and milestone v2 in project B.)
+* **Started** - show issues or merge requests from any milestone with a start
+ date less than today. Note that this can return results from several
+ milestones in the same project.
diff --git a/doc/user/search/img/search_history.gif b/doc/user/search/img/search_history.gif
new file mode 100644
index 00000000000..4cfa48ee0ab
--- /dev/null
+++ b/doc/user/search/img/search_history.gif
Binary files differ
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index 9d1ca1adcb2..45f443819ec 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -40,6 +40,12 @@ The same process is valid for merge requests. Navigate to your project's **Merge
and click **Search or filter results...**. Merge requests can be filtered by author, assignee,
milestone, and label.
+## Search History
+
+You can view recent searches by clicking on the little arrow-clock icon, which is to the left of the search input. Click the search entry to run that search again. This feature is available for issues and merge requests. Searches are stored locally in your browser.
+
+![search history](img/search_history.gif)
+
### Shortcut
You'll also find a shortcut on the search field on the top-right of the project's dashboard to
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index a1852650cfb..604c7d5cefb 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -27,12 +27,12 @@
- [Time tracking](time_tracking.md)
- [Web Editor](../user/project/repository/web_editor.md)
- [Releases](releases.md)
-- [Milestones](milestones.md)
+- [Milestones](../user/project/milestones/index.md)
- [Merge Requests](../user/project/merge_requests/index.md)
- [Authorization for merge requests](../user/project/merge_requests/authorization_for_merge_requests.md)
- [Cherry-pick changes](../user/project/merge_requests/cherry_pick_changes.md)
- [Merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md)
- - [Resolve discussion comments in merge requests reviews](../user/project/merge_requests/merge_request_discussion_resolution.md)
+ - [Resolve discussion comments in merge requests reviews](../user/discussions/index.md)
- [Resolve merge conflicts in the UI](../user/project/merge_requests/resolve_conflicts.md)
- [Revert changes in the UI](../user/project/merge_requests/revert_changes.md)
- [Merge requests versions](../user/project/merge_requests/versions.md)
diff --git a/doc/workflow/groups.md b/doc/workflow/groups.md
index 882747e14e9..1cb3c940f00 100644
--- a/doc/workflow/groups.md
+++ b/doc/workflow/groups.md
@@ -1,6 +1,6 @@
# GitLab Groups
-GitLab groups allow you to group projects into directories and give users to several projects at once.
+GitLab groups allow you to group projects into directories and give users access to several projects at once.
When you create a new project in GitLab, the default namespace for the project is the personal namespace associated with your GitLab user.
In this document we will see how to create groups, put projects in groups and manage who can access the projects in a group.
diff --git a/doc/workflow/milestones.md b/doc/workflow/milestones.md
index 37afe553e55..69eb6b286b0 100644
--- a/doc/workflow/milestones.md
+++ b/doc/workflow/milestones.md
@@ -1,28 +1 @@
-# Milestones
-
-Milestones allow you to organize issues and merge requests into a cohesive group, optionally setting a due date.
-A common use is keeping track of an upcoming software version. Milestones are created per-project.
-
-![milestone form](milestones/form.png)
-
-## Groups and milestones
-
-You can create a milestone for several projects in the same group simultaneously.
-On the group's milestones page, you will be able to see the status of that milestone across all of the selected projects.
-
-![group milestone form](milestones/group_form.png)
-
-## Special milestone filters
-
-In addition to the milestones that exist in the project or group, there are some
-special options available when filtering by milestone:
-
-* **No Milestone** - only show issues or merge requests without a milestone.
-* **Upcoming** - show issues or merge request that belong to the next open
- milestone with a due date, by project. (For example: if project A has
- milestone v1 due in three days, and project B has milestone v2 due in a week,
- then this will show issues or merge requests from milestone v1 in project A
- and milestone v2 in project B.)
-* **Started** - show issues or merge requests from any milestone with a start
- date less than today. Note that this can return results from several
- milestones in the same project.
+This document was moved to [another location](../user/project/milestones/index.md).
diff --git a/doc/workflow/milestones/form.png b/doc/workflow/milestones/form.png
deleted file mode 100644
index c4731d88543..00000000000
--- a/doc/workflow/milestones/form.png
+++ /dev/null
Binary files differ
diff --git a/doc/workflow/milestones/group_form.png b/doc/workflow/milestones/group_form.png
deleted file mode 100644
index dccdb019703..00000000000
--- a/doc/workflow/milestones/group_form.png
+++ /dev/null
Binary files differ
diff --git a/doc/workflow/shortcuts.md b/doc/workflow/shortcuts.md
index f94357abec9..c5b7488be69 100644
--- a/doc/workflow/shortcuts.md
+++ b/doc/workflow/shortcuts.md
@@ -75,3 +75,9 @@ You can see GitLab's keyboard shortcuts by using 'shift + ?'
| <kbd>r</kbd> | Reply (quoting selected text) |
| <kbd>e</kbd> | Edit issue/merge request |
| <kbd>l</kbd> | Change label |
+
+## Wiki pages
+
+| Keyboard Shortcut | Description |
+| ----------------- | ----------- |
+| <kbd>e</kbd> | Edit wiki page|