summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/content_editor/components/content_editor.vue7
-rw-r--r--app/assets/javascripts/content_editor/components/toolbar_image_button.vue1
-rw-r--r--app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue3
-rw-r--r--app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue1
-rw-r--r--app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb2
-rw-r--r--config/metrics/counts_28d/20210216181158_epics.yml13
-rw-r--r--config/metrics/counts_all/20210216181134_epics.yml13
-rw-r--r--doc/api/index.md6
-rw-r--r--doc/api/oauth2.md44
-rw-r--r--doc/api/users.md2
-rw-r--r--doc/ci/lint.md4
-rw-r--r--doc/ci/pipelines/index.md16
-rw-r--r--doc/development/testing_guide/best_practices.md6
-rw-r--r--qa/qa.rb1
-rw-r--r--qa/qa/page/component/content_editor.rb54
-rw-r--r--qa/qa/page/component/wiki.rb12
-rw-r--r--qa/qa/page/component/wiki_page_form.rb7
-rw-r--r--qa/qa/page/project/wiki/edit.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/wiki/content_editor_spec.rb43
19 files changed, 206 insertions, 30 deletions
diff --git a/app/assets/javascripts/content_editor/components/content_editor.vue b/app/assets/javascripts/content_editor/components/content_editor.vue
index 965fcc6ce79..a372233e543 100644
--- a/app/assets/javascripts/content_editor/components/content_editor.vue
+++ b/app/assets/javascripts/content_editor/components/content_editor.vue
@@ -93,7 +93,12 @@ export default {
<div>
<editor-state-observer @docUpdate="notifyChange" @focus="focus" @blur="blur" />
<content-editor-error />
- <div data-testid="content-editor" class="md-area" :class="{ 'is-focused': focused }">
+ <div
+ data-testid="content-editor"
+ data-qa-selector="content_editor_container"
+ class="md-area"
+ :class="{ 'is-focused': focused }"
+ >
<top-toolbar ref="toolbar" class="gl-mb-4" />
<formatting-bubble-menu />
<div v-if="isLoadingContent" class="gl-w-full gl-display-flex gl-justify-content-center">
diff --git a/app/assets/javascripts/content_editor/components/toolbar_image_button.vue b/app/assets/javascripts/content_editor/components/toolbar_image_button.vue
index 6d970b27705..649e23c29aa 100644
--- a/app/assets/javascripts/content_editor/components/toolbar_image_button.vue
+++ b/app/assets/javascripts/content_editor/components/toolbar_image_button.vue
@@ -98,6 +98,7 @@ export default {
name="content_editor_image"
:accept="$options.acceptedMimes"
class="gl-display-none"
+ data-qa-selector="file_upload_field"
@change="onFileSelect"
/>
</gl-dropdown>
diff --git a/app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue b/app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue
index 1bcad5a4c6d..13728d4001d 100644
--- a/app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue
+++ b/app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue
@@ -61,6 +61,7 @@ export default {
<gl-dropdown
v-gl-tooltip="$options.i18n.placeholder"
size="small"
+ data-qa-selector="text_style_dropdown"
:disabled="!activeItem"
:text="activeItemLabel"
>
@@ -69,6 +70,8 @@ export default {
:key="index"
is-check-item
:is-checked="isActive(item)"
+ data-qa-selector="text_style_menu_item"
+ :data-qa-text-style="item.label"
@click="execute(item)"
>
{{ item.label }}
diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
index 68865281b27..a8ec731e105 100644
--- a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
+++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
@@ -397,6 +397,7 @@ export default {
v-if="showContentEditorAlert"
class="gl-mb-6"
variant="info"
+ data-qa-selector="try_new_editor_container"
:primary-button-text="$options.i18n.contentEditor.useNewEditor.primaryLabel"
:secondary-button-text="$options.i18n.contentEditor.useNewEditor.secondaryLabel"
:dismiss-label="$options.i18n.contentEditor.useNewEditor.secondaryLabel"
diff --git a/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb b/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb
index 9fa448a9abb..0bfea05abc7 100644
--- a/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb
+++ b/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb
@@ -18,7 +18,7 @@ module SpammableActions::CaptchaCheck::JsonFormatActionsSupport
def with_captcha_check_json_format(&block)
# NOTE: "409 - Conflict" seems to be the most appropriate HTTP status code for a response
# which requires a CAPTCHA to be solved in order for the request to be resubmitted.
- # See https://stackoverflow.com/q/26547466/25192
+ # https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10
captcha_render_lambda = -> { render json: spam_action_response_fields(spammable), status: :conflict }
with_captcha_check_common(captcha_render_lambda: captcha_render_lambda, &block)
end
diff --git a/config/metrics/counts_28d/20210216181158_epics.yml b/config/metrics/counts_28d/20210216181158_epics.yml
index db7e8870c6a..4a896092194 100644
--- a/config/metrics/counts_28d/20210216181158_epics.yml
+++ b/config/metrics/counts_28d/20210216181158_epics.yml
@@ -1,20 +1,19 @@
---
data_category: Optional
key_path: usage_activity_by_stage_monthly.plan.epics
-description:
+description: Count distinct author ids from epics
product_section: dev
-product_stage:
+product_stage: plan
product_group: group::plan
-product_category:
+product_category: epics
value_type: number
status: data_available
time_frame: 28d
-data_source:
+data_source: database
distribution:
-- ce
+- ee
tier:
-- free
-skip_validation: true
+- premium
performance_indicator_type:
- gmau
- paid_gmau
diff --git a/config/metrics/counts_all/20210216181134_epics.yml b/config/metrics/counts_all/20210216181134_epics.yml
index 8b87f64a4e1..ec43965b4fb 100644
--- a/config/metrics/counts_all/20210216181134_epics.yml
+++ b/config/metrics/counts_all/20210216181134_epics.yml
@@ -1,17 +1,16 @@
---
data_category: Operational
key_path: usage_activity_by_stage.plan.epics
-description:
+description: Count distinct author ids from epics
product_section: dev
-product_stage:
+product_stage: plan
product_group: group::plan
-product_category:
+product_category: epics
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
-- ce
+- ee
tier:
-- free
-skip_validation: true
+- premium
diff --git a/doc/api/index.md b/doc/api/index.md
index 4048a27b81f..12d01828803 100644
--- a/doc/api/index.md
+++ b/doc/api/index.md
@@ -167,7 +167,11 @@ curl --header "Authorization: Bearer OAUTH-TOKEN" "https://gitlab.example.com/ap
Read more about [GitLab as an OAuth2 provider](oauth2.md).
NOTE:
-We recommend that OAuth access tokens have an expiration. You can use a `refresh_token` to refresh tokens. Integrations may need to be updated to refresh tokens prior to expiration, which is based on the [expires_in](https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.14) property in the token endpoint response.
+We recommend OAuth access tokens have an expiration. You can use the `refresh_token` parameter
+to refresh tokens. Integrations may need to be updated to use refresh tokens prior to
+expiration, which is based on the [expires_in](https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.14)
+property in the token endpoint response. See [OAuth2 token](oauth2.md) documentation
+for examples requesting a new access token using a refresh token.
A default refresh setting of two hours is tracked in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/336598).
diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md
index f2efa8fb4c0..ce455c89d1a 100644
--- a/doc/api/oauth2.md
+++ b/doc/api/oauth2.md
@@ -123,6 +123,28 @@ Before starting the flow, generate the `STATE`, the `CODE_VERIFIER` and the `COD
"created_at": 1607635748
}
```
+
+1. To retrieve a new `access_token`, use the `refresh_token` parameter. Refresh tokens may
+ be used even after the `access_token` itself expires. This request:
+ - Invalidates the existing `access_token` and `refresh_token`.
+ - Sends new tokens in the response.
+
+ ```ruby
+ parameters = 'client_id=APP_ID&client_secret=APP_SECRET&refresh_token=REFRESH_TOKEN&grant_type=refresh_token&redirect_uri=REDIRECT_URI&code_verifier=CODE_VERIFIER'
+ RestClient.post 'https://gitlab.example.com/oauth/token', parameters
+ ```
+
+ Example response:
+
+ ```json
+ {
+ "access_token": "c97d1fe52119f38c7f67f0a14db68d60caa35ddc86fd12401718b649dcfa9c68",
+ "token_type": "bearer",
+ "expires_in": 7200,
+ "refresh_token": "803c1fd487fec35562c205dac93e9d8e08f9d3652a24079d704df3039df1158f",
+ "created_at": 1628711391
+ }
+ ```
NOTE:
The `redirect_uri` must match the `redirect_uri` used in the original
@@ -181,6 +203,28 @@ be used as a CSRF token.
"created_at": 1607635748
}
```
+
+1. To retrieve a new `access_token`, use the `refresh_token` parameter. Refresh tokens may
+ be used even after the `access_token` itself expires. This request:
+ - Invalidates the existing `access_token` and `refresh_token`.
+ - Sends new tokens in the response.
+
+ ```ruby
+ parameters = 'client_id=APP_ID&client_secret=APP_SECRET&refresh_token=REFRESH_TOKEN&grant_type=refresh_token&redirect_uri=REDIRECT_URI'
+ RestClient.post 'https://gitlab.example.com/oauth/token', parameters
+ ```
+
+ Example response:
+
+ ```json
+ {
+ "access_token": "c97d1fe52119f38c7f67f0a14db68d60caa35ddc86fd12401718b649dcfa9c68",
+ "token_type": "bearer",
+ "expires_in": 7200,
+ "refresh_token": "803c1fd487fec35562c205dac93e9d8e08f9d3652a24079d704df3039df1158f",
+ "created_at": 1628711391
+ }
+ ```
NOTE:
The `redirect_uri` must match the `redirect_uri` used in the original
diff --git a/doc/api/users.md b/doc/api/users.md
index e389759a9ba..6ba751bd292 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1546,7 +1546,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
Returns:
-- `201 OK` on success.
+- `201 Created` on success.
- `404 User Not Found` if user cannot be found.
- `403 Forbidden` if the user cannot be approved because they are blocked by an administrator or by LDAP synchronization.
diff --git a/doc/ci/lint.md b/doc/ci/lint.md
index 746638442a7..4e3ac8b9e93 100644
--- a/doc/ci/lint.md
+++ b/doc/ci/lint.md
@@ -39,8 +39,8 @@ more complicated issues.
To validate the configuration by running a pipeline simulation:
1. Paste the GitLab CI configuration to verify into the text box.
-1. Click the **Simulate pipeline creation for the default branch** checkbox.
-1. Click **Validate**.
+1. Select the **Simulate pipeline creation for the default branch** checkbox.
+1. Select **Validate**.
![Dry run](img/ci_lint_dry_run.png)
diff --git a/doc/ci/pipelines/index.md b/doc/ci/pipelines/index.md
index 2cf823e5746..f3d4cb72e62 100644
--- a/doc/ci/pipelines/index.md
+++ b/doc/ci/pipelines/index.md
@@ -135,13 +135,13 @@ operation of the pipeline.
To execute a pipeline manually:
-1. Navigate to your project's **CI/CD > Pipelines**.
-1. Select the **Run pipeline** button.
-1. On the **Run pipeline** page:
- 1. Select the branch or tag to run the pipeline for in the **Run for branch name or tag** field.
- 1. Enter any [environment variables](../variables/index.md) required for the pipeline run.
- You can set specific variables to have their [values prefilled in the form](#prefill-variables-in-manual-pipelines).
- 1. Click the **Run pipeline** button.
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **CI/CD > Pipelines**.
+1. Select **Run pipeline**.
+1. In the **Run for branch name or tag** field, select the branch or tag to run the pipeline for.
+1. Enter any [environment variables](../variables/index.md) required for the pipeline to run.
+ You can set specific variables to have their [values prefilled in the form](#prefill-variables-in-manual-pipelines).
+1. Select **Run pipeline**.
The pipeline now executes the jobs as configured.
@@ -413,7 +413,7 @@ Feature.disable(:pipeline_graph_layers_view)
Pipeline mini graphs take less space and can tell you at a
quick glance if all jobs passed or something failed. The pipeline mini graph can
-be found when you navigate to:
+be found when you go to:
- The pipelines index page.
- A single commit page.
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 6b6fbe3996e..b72d23d3f9b 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -911,14 +911,16 @@ describe '#show', :snowplow do
expect_snowplow_event(
category: 'Experiment',
action: 'start',
- standard_context: { namespace: group, project: project }
+ namespace: group,
+ project: project
)
expect_snowplow_event(
category: 'Experiment',
action: 'sent',
property: 'property',
label: 'label',
- standard_context: { namespace: group, project: project }
+ namespace: group,
+ project: project
)
end
end
diff --git a/qa/qa.rb b/qa/qa.rb
index e17b2b86ceb..88d9ea13045 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -544,6 +544,7 @@ module QA
autoload :AccessTokens, 'qa/page/component/access_tokens'
autoload :CommitModal, 'qa/page/component/commit_modal'
autoload :VisibilitySetting, 'qa/page/component/visibility_setting'
+ autoload :ContentEditor, 'qa/page/component/content_editor'
module Import
autoload :Gitlab, 'qa/page/component/import/gitlab'
diff --git a/qa/qa/page/component/content_editor.rb b/qa/qa/page/component/content_editor.rb
new file mode 100644
index 00000000000..b3a42634fe7
--- /dev/null
+++ b/qa/qa/page/component/content_editor.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module ContentEditor
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/assets/javascripts/content_editor/components/content_editor.vue' do
+ element :content_editor_container
+ end
+
+ base.view 'app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue' do
+ element :text_style_dropdown
+ element :text_style_menu_item
+ end
+
+ base.view 'app/assets/javascripts/content_editor/components/toolbar_image_button.vue' do
+ element :file_upload_field
+ end
+ end
+
+ def add_heading(heading, text)
+ within_element(:content_editor_container) do
+ text_area.set(text)
+ # wait for text style option to become active after typing
+ has_active_element?(:text_style_dropdown, wait: 1)
+ click_element(:text_style_dropdown)
+ within_element(:text_style_dropdown) do
+ click_element(:text_style_menu_item, text_style: heading)
+ end
+ end
+ end
+
+ def upload_image(image_path)
+ within_element(:content_editor_container) do
+ # add image on a new line
+ text_area.send_keys(:return)
+ find_element(:file_upload_field, visible: false).send_keys(image_path)
+ end
+ end
+
+ private
+
+ def text_area
+ find('[contenteditable="true"]', visible: false)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/component/wiki.rb b/qa/qa/page/component/wiki.rb
index 92eb25af247..c3db1d6c885 100644
--- a/qa/qa/page/component/wiki.rb
+++ b/qa/qa/page/component/wiki.rb
@@ -68,6 +68,18 @@ module QA
def has_no_page?
has_element?(:create_first_page_link)
end
+
+ def has_heading?(heading_type, text)
+ within_element(:wiki_page_content) do
+ has_css?(heading_type, text: text)
+ end
+ end
+
+ def has_image?(image_file_name)
+ within_element(:wiki_page_content) do
+ has_css?("img[src$='#{image_file_name}']")
+ end
+ end
end
end
end
diff --git a/qa/qa/page/component/wiki_page_form.rb b/qa/qa/page/component/wiki_page_form.rb
index bb22b7da003..6b7452b0e0f 100644
--- a/qa/qa/page/component/wiki_page_form.rb
+++ b/qa/qa/page/component/wiki_page_form.rb
@@ -14,6 +14,7 @@ module QA
element :wiki_content_textarea
element :wiki_message_textbox
element :wiki_submit_button
+ element :try_new_editor_container
end
base.view 'app/assets/javascripts/pages/shared/wikis/components/delete_wiki_modal.vue' do
@@ -41,6 +42,12 @@ module QA
click_element(:delete_button, Page::Modal::DeleteWiki)
Page::Modal::DeleteWiki.perform(&:confirm_deletion)
end
+
+ def use_new_editor
+ within_element(:try_new_editor_container) do
+ click_button('Use the new editor')
+ end
+ end
end
end
end
diff --git a/qa/qa/page/project/wiki/edit.rb b/qa/qa/page/project/wiki/edit.rb
index 70aa10cc43e..e782bbbb432 100644
--- a/qa/qa/page/project/wiki/edit.rb
+++ b/qa/qa/page/project/wiki/edit.rb
@@ -7,6 +7,7 @@ module QA
class Edit < Base
include Page::Component::WikiPageForm
include Page::Component::WikiSidebar
+ include Page::Component::ContentEditor
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/content_editor_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/content_editor_spec.rb
new file mode 100644
index 00000000000..2a46604f8ac
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/content_editor_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ context 'Content Editor' do
+ let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
+ let(:page_title) { 'Content Editor Page' }
+ let(:heading_text) { 'My New Heading' }
+ let(:image_file_name) { 'testfile.png' }
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ after do
+ initial_wiki.project.remove_via_api!
+ end
+
+ it 'creates a formatted Wiki page with an image uploaded', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1861' do
+ initial_wiki.visit!
+
+ Page::Project::Wiki::Show.perform(&:click_new_page)
+
+ Page::Project::Wiki::Edit.perform do |edit|
+ edit.set_title(page_title)
+ edit.use_new_editor
+ edit.add_heading('Heading 1', heading_text)
+ edit.upload_image(File.absolute_path(File.join('qa', 'fixtures', 'designs', image_file_name)))
+ end
+
+ Page::Project::Wiki::Edit.perform(&:click_submit)
+
+ Page::Project::Wiki::Show.perform do |wiki|
+ aggregate_failures 'page shows expected content' do
+ expect(wiki).to have_title(page_title)
+ expect(wiki).to have_heading('h1', heading_text)
+ expect(wiki).to have_image(image_file_name)
+ end
+ end
+ end
+ end
+ end
+end