Commit f4b07b0a authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents b7ec0acc e3df0b6e
......@@ -47,7 +47,7 @@ export default {
},
deleteIssuableButtonText() {
return sprintf(__('Delete %{issuableType}'), {
issuableType: issuableTypes[this.issuableType],
issuableType: issuableTypes[this.issuableType].toLowerCase(),
});
},
},
......@@ -79,23 +79,23 @@ export default {
:loading="formState.updateLoading"
:disabled="formState.updateLoading || !isSubmitEnabled"
category="primary"
variant="success"
class="float-left qa-save-button"
variant="confirm"
class="float-left qa-save-button gl-mr-3"
type="submit"
@click.prevent="updateIssuable"
>
{{ __('Save changes') }}
</gl-button>
<gl-button class="float-right" @click="closeForm">
<gl-button @click="closeForm">
{{ __('Cancel') }}
</gl-button>
<gl-button
v-if="shouldShowDeleteButton"
:loading="deleteLoading"
:disabled="deleteLoading"
category="primary"
category="secondary"
variant="danger"
class="float-right gl-mr-3 qa-delete-button"
class="float-right qa-delete-button"
@click="deleteIssuable"
>
{{ deleteIssuableButtonText }}
......
......@@ -10,21 +10,21 @@ export const beautifyPath = (path) => (path ? path.split('/').join(' / ') : '');
export const getPackageTypeLabel = (packageType) => {
switch (packageType) {
case PackageType.CONAN:
return s__('PackageType|Conan');
return s__('PackageRegistry|Conan');
case PackageType.MAVEN:
return s__('PackageType|Maven');
return s__('PackageRegistry|Maven');
case PackageType.NPM:
return s__('PackageType|npm');
return s__('PackageRegistry|npm');
case PackageType.NUGET:
return s__('PackageType|NuGet');
return s__('PackageRegistry|NuGet');
case PackageType.PYPI:
return s__('PackageType|PyPI');
return s__('PackageRegistry|PyPI');
case PackageType.RUBYGEMS:
return s__('PackageType|RubyGems');
return s__('PackageRegistry|RubyGems');
case PackageType.COMPOSER:
return s__('PackageType|Composer');
return s__('PackageRegistry|Composer');
case PackageType.GENERIC:
return s__('PackageType|Generic');
return s__('PackageRegistry|Generic');
default:
return null;
}
......
......@@ -3,6 +3,8 @@
require 'asana'
class AsanaService < Service
include ActionView::Helpers::UrlHelper
prop_accessor :api_key, :restrict_to_branch
validates :api_key, presence: true, if: :activated?
......@@ -11,20 +13,12 @@ class AsanaService < Service
end
def description
s_('AsanaService|Asana - Teamwork without email')
s_('AsanaService|Add commit messages as comments to Asana tasks')
end
def help
'This service adds commit messages as comments to Asana tasks.
Once enabled, commit messages are checked for Asana task URLs
(for example, `https://app.asana.com/0/123456/987654`) or task IDs
starting with # (for example, `#987654`). Every task ID found will
get the commit comment added to it.
You can also close a task with a message containing: `fix #123456`.
You can create a Personal Access Token here:
https://app.asana.com/0/developer-console'
docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/asana'), target: '_blank', rel: 'noopener noreferrer'
s_('Add commit messages as comments to Asana tasks. %{docs_link}').html_safe % { docs_link: docs_link.html_safe }
end
def self.to_param
......@@ -36,14 +30,17 @@ https://app.asana.com/0/developer-console'
{
type: 'text',
name: 'api_key',
title: _('API key'),
placeholder: s_('AsanaService|User Personal Access Token. User must have access to task, all comments will be attributed to this user.'),
title: 'API key',
help: s_('AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user.'),
# Example Personal Access Token from Asana docs
placeholder: '0/68a9e79b868c6789e79a124c30b0',
required: true
},
{
type: 'text',
name: 'restrict_to_branch',
placeholder: s_('AsanaService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.')
title: 'Restrict to branch (optional)',
help: s_('AsanaService|Comma-separated list of branches to be automatically inspected. Leave blank to include all branches.')
}
]
end
......
......@@ -20,4 +20,4 @@
- if has_submit
.row-content-block.footer-block
= f.submit _("Submit %{humanized_resource_name}") % { humanized_resource_name: humanized_resource_name }, class: 'gl-button btn btn-confirm'
= f.submit _("Create %{humanized_resource_name}") % { humanized_resource_name: humanized_resource_name }, class: 'gl-button btn btn-confirm'
......@@ -62,25 +62,23 @@
- is_footer = !(issuable.is_a?(MergeRequest) && issuable.new_record?)
.row-content-block{ class: (is_footer ? "footer-block" : "middle-block") }
.float-right
- if !issuable.persisted? && !issuable.project.empty_repo? && (guide_url = issuable.project.present.contribution_guide_path)
.gl-mb-5
Please review the
%strong= link_to('contribution guidelines', guide_url)
for this project.
- if issuable.new_record?
= link_to _('Cancel'), polymorphic_path([@project, issuable.class]), class: 'gl-button btn btn-cancel'
= form.submit "Create #{issuable.class.model_name.human.downcase}", class: 'gl-button btn btn-confirm gl-mr-2', data: { qa_selector: 'issuable_create_button' }
- else
- if can?(current_user, :"destroy_#{issuable.to_ability_name}", @project)
= link_to 'Delete', polymorphic_path([@project, issuable], params: { destroy_confirm: true }), data: { confirm: "#{issuable.human_class_name} will be removed! Are you sure?" }, method: :delete, class: 'btn btn-danger btn-grouped'
= link_to _('Cancel'), polymorphic_path([@project, issuable]), class: 'gl-button btn btn-grouped btn-default btn-cancel'
= form.submit 'Save changes', class: 'gl-button btn btn-confirm gl-mr-2'
%span.gl-mr-3
- if issuable.new_record?
= form.submit "Submit #{issuable.class.model_name.human.downcase}", class: 'gl-button btn btn-confirm', data: { qa_selector: 'issuable_create_button' }
= link_to _('Cancel'), polymorphic_path([@project, issuable.class]), class: 'btn gl-button btn-default'
- else
= form.submit 'Save changes', class: 'gl-button btn btn-confirm'
- if !issuable.persisted? && !issuable.project.empty_repo? && (guide_url = issuable.project.present.contribution_guide_path)
.inline.gl-mt-3
Please review the
%strong= link_to('contribution guidelines', guide_url)
for this project.
= link_to _('Cancel'), polymorphic_path([@project, issuable]), class: 'gl-button btn btn-default'
- if can?(current_user, :"destroy_#{issuable.to_ability_name}", @project)
= link_to 'Delete', polymorphic_path([@project, issuable], params: { destroy_confirm: true }), data: { confirm: _('%{issuableType} will be removed! Are you sure?') % { issuableType: issuable.human_class_name } }, method: :delete, class: 'btn gl-button btn-danger btn-danger-secondary gl-float-right'
= render_if_exists 'shared/issuable/remove_approver'
......
---
title: Update issuable submit content order, button variants, and button alignment
merge_request: 57172
author:
type: other
---
title: Review and revise Integrations/Asana UI text
merge_request: 57362
author:
type: other
......@@ -68,14 +68,14 @@ Example response:
## Asana
Asana - Teamwork without email
Add commit messages as comments to Asana tasks.
See also the [Asana service documentation](../user/project/integrations/asana.md).
### Create/Edit Asana service
Set Asana service for a project.
> This service adds commit messages as comments to Asana tasks. Once enabled, commit messages are checked for Asana task URLs (for example, `https://app.asana.com/0/123456/987654`) or task IDs starting with # (for example, `#987654`). Every task ID found gets the commit comment added to it. You can also close a task with a message containing: `fix #123456`. You can find your API Keys here: <https://developers.asana.com/docs/#authentication-basics>.
```plaintext
PUT /projects/:id/services/asana
```
......@@ -84,8 +84,8 @@ Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `api_key` | string | true | User API token. User must have access to task, all comments are attributed to this user. |
| `restrict_to_branch` | string | false | Comma-separated list of branches which are automatically inspected. Leave blank to include all branches. |
| `api_key` | string | true | User API token. User must have access to task. All comments are attributed to this user. |
| `restrict_to_branch` | string | false | Comma-separated list of branches to be are automatically inspected. Leave blank to include all branches. |
| `push_events` | boolean | false | Enable notifications for push events |
### Delete Asana service
......
---
stage: Create
group: Ecosystem
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Asana service **(FREE)**
This service adds commit messages as comments to Asana tasks.
Once enabled, commit messages are checked for Asana task URLs (for example,
`https://app.asana.com/0/123456/987654`) or task IDs starting with `#`
(for example, `#987654`). Every task ID found gets the commit comment added to it.
You can also close a task with a message containing: `fix #123456`.
You can use either of these words:
- `fix`
- `fixed`
- `fixes`
- `fixing`
- `close`
- `closes`
- `closed`
- `closing`
See also the [Asana service API documentation](../../../api/services.md#asana).
## Setup
In Asana, create a Personal Access Token.
[Learn about Personal Access Tokens in Asana](https://developers.asana.com/docs/personal-access-token).
Complete these steps in GitLab:
1. Go to the project you want to configure.
1. Go to the [Integrations page](overview.md#accessing-integrations).
1. Select **Asana**.
1. Ensure that the **Active** toggle is enabled.
1. Paste the token you generated in Asana.
1. (Optional) To restrict this setting to specific branches, list them in the **Restrict to branch**
field, separated with commas.
1. Select **Save changes** or optionally select **Test settings**.
<!-- ## Troubleshooting -->
......@@ -25,8 +25,7 @@ want to configure.
Click on the service links to see further configuration instructions and details.
| Service | Description | Service Hooks |
| ------- | ----------- | ------------- |
| Asana | Asana - Teamwork without email | No |
| Asana | Add commit messages as comments to Asana tasks | No |
| Assembla | Project Management Software (Source Commits Endpoint) | No |
| [Atlassian Bamboo CI](bamboo.md) | A continuous integration and build server | Yes |
| Buildkite | Continuous integration and deployments | Yes |
......
......@@ -66,27 +66,29 @@ export default {
<div class="border-bottom">
<slot name="rules"></slot>
</div>
<div v-if="settings.canEdit && settings.allowMultiRule" class="border-bottom py-3 px-2">
<div v-if="settings.canEdit && settings.allowMultiRule" class="border-bottom py-3 px-3">
<div class="gl-display-flex">
<gl-button
v-if="targetBranch"
:disabled="isLoading"
data-testid="reset-to-defaults"
@click="resetToProjectDefaults"
>
{{ __('Reset to project defaults') }}
</gl-button>
<gl-button
:class="{ 'gl-ml-3': targetBranch, 'gl-ml-0': !targetBranch }"
:class="{ 'gl-mr-3': targetBranch, 'gl-mr-0': !targetBranch }"
:disabled="isLoading"
category="secondary"
variant="info"
size="small"
data-qa-selector="add_approvers_button"
data-testid="add-approval-rule"
@click="openCreateModal(null)"
>
{{ __('Add approval rule') }}
</gl-button>
<gl-button
v-if="targetBranch"
:disabled="isLoading"
size="small"
data-testid="reset-to-defaults"
@click="resetToProjectDefaults"
>
{{ __('Reset to project defaults') }}
</gl-button>
</div>
</div>
<slot name="footer"></slot>
......
......@@ -3,16 +3,20 @@ import { s__ } from '~/locale';
import GeoNodeCoreDetails from './geo_node_core_details.vue';
import GeoNodePrimaryOtherInfo from './primary_node/geo_node_primary_other_info.vue';
import GeoNodeVerificationInfo from './primary_node/geo_node_verification_info.vue';
import GeoNodeReplicationSummary from './secondary_node/geo_node_replication_summary.vue';
import GeoNodeSecondaryOtherInfo from './secondary_node/geo_node_secondary_other_info.vue';
export default {
name: 'GeoNodeDetails',
i18n: {
secondaryDetails: s__('Geo|Secondary Details'),
replicationDetails: s__('Geo|Replication Details'),
},
components: {
GeoNodeCoreDetails,
GeoNodePrimaryOtherInfo,
GeoNodeVerificationInfo,
GeoNodeReplicationSummary,
GeoNodeSecondaryOtherInfo,
},
props: {
node: {
......@@ -37,7 +41,16 @@ export default {
<geo-node-primary-other-info class="gl-flex-fill-1 gl-h-full gl-w-full" :node="node" />
</div>
<div v-else class="gl-display-flex gl-flex-direction-column gl-h-full gl-w-full">
<p data-testid="secondary-node-details">{{ $options.i18n.secondaryDetails }}</p>
<div
class="gl-display-flex gl-sm-flex-direction-column gl-align-items-flex-start gl-h-full gl-w-full gl-mb-5"
>
<geo-node-replication-summary
class="gl-flex-fill-1 gl-mb-5 gl-md-mb-0 gl-md-mr-5 gl-h-full gl-w-full"
:node="node"
/>
<geo-node-secondary-other-info class="gl-flex-fill-1 gl-h-full gl-w-full" :node="node" />
</div>
<p data-testid="secondary-replication-details">{{ $options.i18n.replicationDetails }}</p>
</div>
</div>
</template>
<script>
import { GlCard, GlButton } from '@gitlab/ui';
import { s__ } from '~/locale';
export default {
name: 'GeoNodeReplicationSummary',
i18n: {
replicationSummary: s__('Geo|Replication summary'),
replicationDetailsButton: s__('Geo|Replication details'),
replicationStatus: s__('Geo|Replication status'),
syncSettings: s__('Geo|Synchronization settings'),
replicationCounts: s__('Geo|Replication counts'),
},
components: {
GlCard,
GlButton,
},
props: {
node: {
type: Object,
required: true,
},
},
};
</script>
<template>
<gl-card header-class="gl-display-flex gl-align-items-center">
<template #header>
<h5 class="gl-my-0">{{ $options.i18n.replicationSummary }}</h5>
<gl-button
class="gl-ml-auto"
variant="confirm"
category="secondary"
:href="node.webGeoProjectsUrl"
target="_blank"
>{{ $options.i18n.replicationDetailsButton }}</gl-button
>
</template>
<div class="gl-display-flex gl-flex-direction-column gl-mb-5">
<span data-testid="replication-status">{{ $options.i18n.replicationStatus }}</span>
</div>
<div class="gl-display-flex gl-flex-direction-column gl-mb-5">
<span data-testid="sync-settings">{{ $options.i18n.syncSettings }}</span>
</div>
<span data-testid="replication-counts">{{ $options.i18n.replicationCounts }}</span>
</gl-card>
</template>
<script>
import { GlCard } from '@gitlab/ui';
import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
import { __, s__ } from '~/locale';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
export default {
name: 'GeoNodeSecondaryOtherInfo',
i18n: {
otherInfo: __('Other information'),
dbReplicationLag: s__('Geo|Data replication lag'),
lastEventId: s__('Geo|Last event ID from primary'),
lastCursorEventId: s__('Geo|Last event ID processed by cursor'),
storageConfig: s__('Geo|Storage config'),
shardsNotMatched: s__('Geo|Does not match the primary storage configuration'),
unknown: __('Unknown'),
ok: __('OK'),
},
components: {
GlCard,
TimeAgo,
},
props: {
node: {
type: Object,
required: true,
},
},
computed: {
storageShardsStatus() {
if (this.node.storageShardsMatch == null) {
return this.$options.i18n.unknown;
}
return this.node.storageShardsMatch
? this.$options.i18n.ok
: this.$options.i18n.shardsNotMatched;
},
dbReplicationLag() {
if (parseInt(this.node.dbReplicationLagSeconds, 10) >= 0) {
const parsedTime = parseSeconds(this.node.dbReplicationLagSeconds, {
hoursPerDay: 24,
daysPerWeek: 7,
});
return stringifyTime(parsedTime);
}
return this.$options.i18n.unknown;
},
lastEventTimestamp() {
const time = this.node.lastEventTimestamp * 1000;
return new Date(time).toString();
},
lastCursorEventTimestamp() {
const time = this.node.cursorLastEventTimestamp * 1000;
return new Date(time).toString();
},
},
};
</script>
<template>
<gl-card>
<template #header>
<h5 class="gl-my-3">{{ $options.i18n.otherInfo }}</h5>
</template>
<div class="gl-display-flex gl-flex-direction-column gl-mb-5">
<span>{{ $options.i18n.dbReplicationLag }}</span>
<span class="gl-font-weight-bold gl-mt-2" data-testid="replication-lag">{{
dbReplicationLag
}}</span>
</div>
<div class="gl-display-flex gl-flex-direction-column gl-mb-5">
<span>{{ $options.i18n.lastEventId }}</span>
<span class="gl-font-weight-bold gl-mt-2"
>{{ node.lastEventId || 0 }} (<time-ago
data-testid="last-event"
:time="lastEventTimestamp"
/>)</span
>
</div>
<div class="gl-display-flex gl-flex-direction-column gl-mb-5">
<span>{{ $options.i18n.lastCursorEventId }}</span>
<span class="gl-font-weight-bold gl-mt-2"
>{{ node.cursorLastEventId || 0 }} (<time-ago
data-testid="last-cursor-event"
:time="lastCursorEventTimestamp"
/>)</span
>
</div>
<div class="gl-display-flex gl-flex-direction-column gl-mb-5">
<span>{{ $options.i18n.storageConfig }}</span>
<span
:class="{ 'gl-text-red-500': !node.storageShardsMatch }"
class="gl-font-weight-bold gl-mt-2"
data-testid="storage-shards"
>{{ storageShardsStatus }}</span
>
</div>
</gl-card>
</template>
......@@ -32,7 +32,7 @@ RSpec.describe 'Delete Epic', :js do
it 'deletes the issue and redirect to epic list' do
page.accept_alert 'Delete this epic and all descendants?' do
find(:button, text: 'Delete Epic').click
find(:button, text: 'Delete epic').click
end
wait_for_requests
......
......@@ -156,7 +156,7 @@ RSpec.describe 'New/edit issue', :js do
fill_in 'issue_weight', with: '1'
click_button 'Submit issue'
click_button 'Create issue'
page.within '.issuable-sidebar' do
page.within '.assignee' do
......
......@@ -8,6 +8,7 @@ RSpec.describe 'Issues > User uses EE quick actions', :js do
describe 'issue-only commands' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
before do
......
......@@ -57,7 +57,7 @@ RSpec.describe "User creates a merge request", :js do
# end
fill_in("Title", with: title)
click_button("Submit merge request")
click_button("Create merge request")
page.within(".js-issuable-actions") do
click_link("Edit", match: :first)
......
......@@ -24,7 +24,7 @@ RSpec.describe 'User creates a merge request with blocking MRs', :js do
visit(project_new_merge_request_path(project, merge_request: mr_params))
fill_in 'Merge request dependencies', with: other_mr.to_reference(full: true)
click_button('Submit merge request')
click_button 'Create merge request'
expect(page).to have_content('Depends on 1 merge request')
end
......
......@@ -9,5 +9,5 @@ RSpec.describe 'Merge request > User creates MR with multiple assignees' do
stub_licensed_features(multiple_merge_request_assignees: true)
end
it_behaves_like 'multiple assignees merge request', 'creates', 'Submit merge request'
it_behaves_like 'multiple assignees merge request', 'creates', 'Create merge request'
end
......@@ -9,5 +9,5 @@ RSpec.describe 'Merge request > User creates MR with multiple reviewers' do
stub_licensed_features(multiple_merge_request_reviewers: true)
end
it_behaves_like 'multiple reviewers merge request', 'creates', 'Submit merge request'
it_behaves_like 'multiple reviewers merge request', 'creates', 'Create merge request'
end
......@@ -25,7 +25,7 @@ RSpec.describe 'Merge request > User selects branches for new MR', :js do
context 'saving the MR' do
it 'shows the saved MR' do
fill_in 'merge_request_title', with: 'Test'
click_button 'Submit merge request'
click_button 'Create merge request'
expect(page).to have_button('Close merge request')
end
......
......@@ -66,7 +66,7 @@ RSpec.describe 'Merge request > User sets approval rules', :js do
end
it "persists hidden groups that author has no access to when creating MR" do
click_on("Submit merge request")
click_on("Create merge request")
wait_for_requests
click_on("View eligible approvers")
......
......@@ -109,7 +109,7 @@ RSpec.describe 'Merge request > User sets approvers', :js do
click_button 'Add approval rule'
end
click_on("Submit merge request")
click_on("Create merge request")
wait_for_all_requests
expect(page).to have_content("Requires approval.")
......@@ -134,7 +134,7 @@ RSpec.describe 'Merge request > User sets approvers', :js do
end
click_button 'Update approval rule'
click_on("Submit merge request")
click_on("Create merge request")
wait_for_all_requests
click_on("View eligible approvers") if page.has_button?("View eligible approvers")
wait_for_requests
......
......@@ -7,6 +7,7 @@ RSpec.describe "User creates issue", :js do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project_empty_repo, :public, namespace: group) }
let_it_be(:epic) { create(:epic, group: group, title: 'Sample epic', author: user) }
let(:issue_title) { '500 error on profile' }
before_all do
......@@ -29,7 +30,7 @@ RSpec.describe "User creates issue", :js do
fill_in("Title", with: issue_title)
fill_in("issue_weight", with: weight)
click_button("Submit issue")
click_button 'Create issue'
page.within(".weight") do
expect(page).to have_content(weight)
......@@ -48,7 +49,7 @@ RSpec.describe "User creates issue", :js do
it 'creates an issue with no epic' do
click_button 'Select epic'
find('.gl-new-dropdown-item', text: 'No Epic').click
click_button('Submit issue')
click_button 'Create issue'
wait_for_all_requests
......@@ -62,7 +63,7 @@ RSpec.describe "User creates issue", :js do
it 'credates an issue with an epic' do
click_button 'Select epic'
find('.gl-new-dropdown-item', text: epic.title).click
click_button('Submit issue')
click_button 'Create issue'
wait_for_all_requests
......
......@@ -3,6 +3,8 @@ import GeoNodeCoreDetails from 'ee/geo_nodes_beta/components/details/geo_node_co
import GeoNodeDetails from 'ee/geo_nodes_beta/components/details/geo_node_details.vue';
import GeoNodePrimaryOtherInfo from 'ee/geo_nodes_beta/components/details/primary_node/geo_node_primary_other_info.vue';
import GeoNodeVerificationInfo from 'ee/geo_nodes_beta/components/details/primary_node/geo_node_verification_info.vue';
import GeoNodeReplicationSummary from 'ee/geo_nodes_beta/components/details/secondary_node/geo_node_replication_summary.vue';
import GeoNodeSecondaryOtherInfo from 'ee/geo_nodes_beta/components/details/secondary_node/geo_node_secondary_other_info.vue';
import { MOCK_NODES } from 'ee_jest/geo_nodes_beta/mock_data';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
......@@ -31,7 +33,11 @@ describe('GeoNodeDetails', () => {
const findGeoNodeCoreDetails = () => wrapper.findComponent(GeoNodeCoreDetails);
const findGeoNodePrimaryOtherInfo = () => wrapper.findComponent(GeoNodePrimaryOtherInfo);
const findGeoNodeVerificationInfo = () => wrapper.findComponent(GeoNodeVerificationInfo);
const findGeoNodeSecondaryDetails = () => wrapper.findByTestId('secondary-node-details');
const findGeoNodeSecondaryReplicationSummary = () =>
wrapper.findComponent(GeoNodeReplicationSummary);
const findGeoNodeSecondaryOtherInfo = () => wrapper.findComponent(GeoNodeSecondaryOtherInfo);
const findGeoNodeSecondaryReplicationDetails = () =>
wrapper.findByTestId('secondary-replication-details');
describe('template', () => {
describe('always', () => {
......@@ -45,32 +51,39 @@ describe('GeoNodeDetails', () => {
});
describe.each`
node | showPrimaryOtherInfo | showPrimaryVerificationInfo | showSecondaryDetails
${MOCK_NODES[0]} | ${true} | ${true} | ${false}
${MOCK_NODES[1]} | ${false} | ${false} | ${true}
`(
`conditionally`,
({ node, showPrimaryOtherInfo, showPrimaryVerificationInfo, showSecondaryDetails }) => {
node | showPrimaryComponent | showSecondaryComponent
${MOCK_NODES[0]} | ${true} | ${false}
${MOCK_NODES[1]} | ${false} | ${true}
`(`conditionally`, ({ node, showPrimaryComponent, showSecondaryComponent }) => {
beforeEach(() => {
createComponent({ node });
});
describe(`when primary is ${node.primary}`, () => {
it(`does ${showPrimaryOtherInfo ? '' : 'not '}render GeoNodePrimaryInfo`, () => {
expect(findGeoNodePrimaryOtherInfo().exists()).toBe(showPrimaryOtherInfo);
it(`does ${showPrimaryComponent ? '' : 'not '}render GeoNodePrimaryOtherInfo`, () => {
expect(findGeoNodePrimaryOtherInfo().exists()).toBe(showPrimaryComponent);
});
it(`does ${showPrimaryComponent ? '' : 'not '}render GeoNodeVerificationInfo`, () => {
expect(findGeoNodeVerificationInfo().exists()).toBe(showPrimaryComponent);
});
it(`does ${
showPrimaryVerificationInfo ? '' : 'not '
}render GeoNodeVerificationInfo`, () => {
expect(findGeoNodeVerificationInfo().exists()).toBe(showPrimaryVerificationInfo);
showSecondaryComponent ? '' : 'not '
}render GeoNodeSecondaryReplicationSummary`, () => {
expect(findGeoNodeSecondaryReplicationSummary().exists()).toBe(showSecondaryComponent);
});
it(`does ${showSecondaryComponent ? '' : 'not '}render GeoNodeSecondaryOtherInfo`, () => {
expect(findGeoNodeSecondaryOtherInfo().exists()).toBe(showSecondaryComponent);
});
it(`does ${showSecondaryDetails ? '' : 'not '}render GeoNodeSecondaryDetails`, () => {
expect(findGeoNodeSecondaryDetails().exists()).toBe(showSecondaryDetails);
it(`does ${
showSecondaryComponent ? '' : 'not '
}render GeoNodeSecondaryReplicationDetails`, () => {
expect(findGeoNodeSecondaryReplicationDetails().exists()).toBe(showSecondaryComponent);
});
});
});
},
);
});
});
import { GlButton } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import GeoNodeReplicationSummary from 'ee/geo_nodes_beta/components/details/secondary_node/geo_node_replication_summary.vue';
import { MOCK_NODES } from 'ee_jest/geo_nodes_beta/mock_data';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
describe('GeoNodeReplicationSummary', () => {
let wrapper;
const defaultProps = {
node: MOCK_NODES[1],
};
const createComponent = (initialState, props) => {
wrapper = extendedWrapper(
mount(GeoNodeReplicationSummary, {
propsData: {
...defaultProps,
...props,
},
}),
);
};
afterEach(() => {
wrapper.destroy();
});
const findGlButton = () => wrapper.findComponent(GlButton);
const findGeoNodeReplicationStatus = () => wrapper.findByTestId('replication-status');
const findGeoNodeReplicationCounts = () => wrapper.findByTestId('replication-counts');
const findGeoNodeSyncSettings = () => wrapper.findByTestId('sync-settings');
describe('template', () => {
beforeEach(() => {
createComponent();
});
it('renders the GlButton as a link', () => {
expect(findGlButton().exists()).toBe(true);
expect(findGlButton().attributes('href')).toBe(MOCK_NODES[1].webGeoProjectsUrl);
});
it('renders the geo node replication status', () => {
expect(findGeoNodeReplicationStatus().exists()).toBe(true);
});
it('renders the geo node replication counts', () => {
expect(findGeoNodeReplicationCounts().exists()).toBe(true);
});
it('renders the geo node sync settings', () => {
expect(findGeoNodeSyncSettings().exists()).toBe(true);
});
});
});
import { shallowMount } from '@vue/test-utils';
import GeoNodeSecondaryOtherInfo from 'ee/geo_nodes_beta/components/details/secondary_node/geo_node_secondary_other_info.vue';
import { MOCK_NODES } from 'ee_jest/geo_nodes_beta/mock_data';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
describe('GeoNodeSecondaryOtherInfo', () => {
let wrapper;
const defaultProps = {
node: MOCK_NODES[1],
};
const createComponent = (props) => {
wrapper = extendedWrapper(
shallowMount(GeoNodeSecondaryOtherInfo, {
propsData: {
...defaultProps,
...props,
},
}),
);
};
afterEach(() => {
wrapper.destroy();
});
const findDbReplicationLag = () => wrapper.findByTestId('replication-lag');
const findLastEvent = () => wrapper.findByTestId('last-event');
const findLastCursorEvent = () => wrapper.findByTestId('last-cursor-event');
const findStorageShards = () => wrapper.findByTestId('storage-shards');
describe('template', () => {
describe('always', () => {
beforeEach(() => {
createComponent();
});
it('renders the db replication lag', () => {
expect(findDbReplicationLag().exists()).toBe(true);
});
it('renders the last event correctly', () => {
expect(findLastEvent().exists()).toBe(true);
expect(findLastEvent().props('time')).toBe(
new Date(MOCK_NODES[1].lastEventTimestamp * 1000).toString(),
);
});
it('renders the last cursor event correctly', () => {
expect(findLastCursorEvent().exists()).toBe(true);
expect(findLastCursorEvent().props('time')).toBe(
new Date(MOCK_NODES[1].cursorLastEventTimestamp * 1000).toString(),
);
});
it('renders the storage shards', () => {
expect(findStorageShards().exists()).toBe(true);
});
});
describe('conditionally', () => {
describe.each`
dbReplicationLagSeconds | text
${60} | ${'1m'}
${null} | ${'Unknown'}
`(`db replication lag`, ({ dbReplicationLagSeconds, text }) => {
beforeEach(() => {
createComponent({ node: { dbReplicationLagSeconds } });
});
it(`renders correctly when dbReplicationLagSeconds is ${dbReplicationLagSeconds}`, () => {
expect(findDbReplicationLag().text()).toBe(text);
});
});
describe.each`
storageShardsMatch | text | hasErrorClass
${true} | ${'OK'} | ${false}
${false} | ${'Does not match the primary storage configuration'} | ${true}
`(`storage shards`, ({ storageShardsMatch, text, hasErrorClass }) => {
beforeEach(() => {
createComponent({ node: { storageShardsMatch } });
});
it(`renders correctly when storageShardsMatch is ${storageShardsMatch}`, () => {
expect(findStorageShards().text()).toBe(text);
expect(findStorageShards().classes('gl-text-red-500')).toBe(hasErrorClass);
});
});
});
});
});
......@@ -173,6 +173,7 @@ export const MOCK_NODES = [
version: '10.4.0-pre',
revision: 'b93c51849b',
storageShardsMatch: true,
webGeoProjectsUrl: 'http://127.0.0.1:3002/replication/projects',
},
];
......@@ -235,5 +236,6 @@ export const MOCK_NODE_STATUSES_RES = [
version: '10.4.0-pre',
revision: 'b93c51849b',
storage_shards_match: true,
web_geo_projects_url: 'http://127.0.0.1:3002/replication/projects',
},
];
......@@ -3,6 +3,7 @@
RSpec.shared_examples 'status page quick actions' do
describe '/publish' do
let_it_be(:status_page_setting) { create(:status_page_setting, :enabled, project: project) }
let(:user) { project.owner }
before do
......@@ -35,7 +36,7 @@ RSpec.shared_examples 'status page quick actions' do
fill_in('Title', with: 'Title')
fill_in('Description', with: "Published issue \n\n/publish")
click_button('Submit issue')
click_button('Create issue')
wait_for_requests
......
......@@ -1896,6 +1896,9 @@ msgstr ""
msgid "Add comment to design"
msgstr ""
msgid "Add commit messages as comments to Asana tasks. %{docs_link}"
msgstr ""
msgid "Add deploy freeze"
msgstr ""
......@@ -4176,13 +4179,13 @@ msgstr ""
msgid "AsanaService|%{user} pushed to branch %{branch} of %{project_name} ( %{commit_url} ):"
msgstr ""
msgid "AsanaService|Asana - Teamwork without email"
msgid "AsanaService|Add commit messages as comments to Asana tasks"
msgstr ""
msgid "AsanaService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches."
msgid "AsanaService|Comma-separated list of branches to be automatically inspected. Leave blank to include all branches."
msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to task, all comments will be attributed to this user."
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
msgid "Ascending"
......@@ -8771,6 +8774,9 @@ msgstr ""
msgid "Create %{environment}"
msgstr ""
msgid "Create %{humanized_resource_name}"
msgstr ""
msgid "Create %{type}"
msgstr ""
......@@ -13907,9 +13913,15 @@ msgstr ""
msgid "Geo|Could not remove tracking entry for an existing upload."
msgstr ""
msgid "Geo|Data replication lag"
msgstr ""
msgid "Geo|Discover GitLab Geo"
msgstr ""
msgid "Geo|Does not match the primary storage configuration"
msgstr ""
msgid "Geo|Failed"
msgstr ""
......@@ -13937,6 +13949,12 @@ msgstr ""
msgid "Geo|Internal URL"
msgstr ""
msgid "Geo|Last event ID from primary"
msgstr ""
msgid "Geo|Last event ID processed by cursor"
msgstr ""
msgid "Geo|Last repository check run"
msgstr ""
......@@ -14021,12 +14039,27 @@ msgstr ""
msgid "Geo|Replicated data is verified with the secondary node(s) using checksums."
msgstr ""
msgid "Geo|Replication Details"
msgstr ""
msgid "Geo|Replication counts"
msgstr ""
msgid "Geo|Replication details"
msgstr ""
msgid "Geo|Replication slot WAL"
msgstr ""
msgid "Geo|Replication slots"
msgstr ""
msgid "Geo|Replication status"
msgstr ""
msgid "Geo|Replication summary"
msgstr ""
msgid "Geo|Resync"
msgstr ""
......@@ -14045,9 +14078,6 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
msgid "Geo|Secondary Details"
msgstr ""
msgid "Geo|Secondary node"
msgstr ""
......@@ -14057,6 +14087,9 @@ msgstr ""
msgid "Geo|Status"
msgstr ""
msgid "Geo|Storage config"
msgstr ""
msgid "Geo|Synced"
msgstr ""
......@@ -14069,6 +14102,9 @@ msgstr ""
msgid "Geo|Synchronization of %{itemTitle} is disabled."
msgstr ""
msgid "Geo|Synchronization settings"
msgstr ""
msgid "Geo|The database is currently %{db_lag} behind the primary node."
msgstr ""
......@@ -22139,30 +22175,6 @@ msgstr ""
msgid "PackageRegistry|yarn command"
msgstr ""
msgid "PackageType|Composer"
msgstr ""
msgid "PackageType|Conan"
msgstr ""
msgid "PackageType|Generic"
msgstr ""
msgid "PackageType|Maven"
msgstr ""
msgid "PackageType|NuGet"
msgstr ""
msgid "PackageType|PyPI"
msgstr ""
msgid "PackageType|RubyGems"
msgstr ""
msgid "PackageType|npm"
msgstr ""
msgid "Packages"
msgstr ""
......@@ -29256,9 +29268,6 @@ msgstr ""
msgid "Submit"
msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
msgid "Submit a review"
msgstr ""
......
......@@ -27,7 +27,7 @@ RSpec.describe 'Ensure Boards do not show stale data on browser back', :js do
fill_in 'issue_title', with: 'issue should be shown'
click_button 'Submit issue'
click_button 'Create issue'
page.go_back
wait_for_requests
......
......@@ -156,7 +156,7 @@ RSpec.describe 'New/edit issue', :js do
expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
click_button 'Submit issue'
click_button 'Create issue'
page.within '.issuable-sidebar' do
page.within '.assignee' do
......
......@@ -43,7 +43,7 @@ RSpec.describe 'New issue', :js do
end
it 'rejects issue creation' do
click_button 'Submit issue'
click_button 'Create issue'
expect(page).to have_content('discarded')
expect(page).not_to have_content('potential spam')
......@@ -51,7 +51,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates a spam log record' do
expect { click_button 'Submit issue' }
expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
......@@ -63,14 +63,14 @@ RSpec.describe 'New issue', :js do
end
it 'allows issue creation' do
click_button 'Submit issue'
click_button 'Create issue'
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
it 'creates a spam log record' do
expect { click_button 'Submit issue' }
expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
......@@ -101,14 +101,14 @@ RSpec.describe 'New issue', :js do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
click_button 'Submit issue'
click_button 'Create issue'
# it is impossible to test reCAPTCHA automatically and there is no possibility to fill in recaptcha
# reCAPTCHA verification is skipped in test environment and it always returns true
expect(page).not_to have_content('issue title')
expect(page).to have_css('.recaptcha')
click_button 'Submit issue'
click_button 'Create issue'
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
......@@ -122,7 +122,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates an issue without a need to solve reCAPTCHA' do
click_button 'Submit issue'
click_button 'Create issue'
expect(page).not_to have_css('.recaptcha')
expect(page.find('.issue-details h2.title')).to have_content('issue title')
......@@ -130,7 +130,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates a spam log record' do
expect { click_button 'Submit issue' }
expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
......@@ -148,7 +148,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates an issue without a need to solve reCaptcha' do
click_button 'Submit issue'
click_button 'Create issue'
expect(page).not_to have_css('.recaptcha')
expect(page.find('.issue-details h2.title')).to have_content('issue title')
......@@ -156,7 +156,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates a spam log record' do
expect { click_button 'Submit issue' }
expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
......@@ -178,7 +178,7 @@ RSpec.describe 'New issue', :js do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
click_button 'Submit issue'
click_button 'Create issue'
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
......
......@@ -54,7 +54,7 @@ RSpec.describe "User creates issue" do
first('.js-md').click
first('.rspec-issuable-form-description').native.send_keys('Description')
click_button("Submit issue")
click_button("Create issue")
expect(page).to have_content(issue_title)
.and have_content(user.name)
......@@ -112,7 +112,7 @@ RSpec.describe "User creates issue" do
fill_in("Title", with: issue_title)
click_button("Label")
click_link(label_titles.first)
click_button("Submit issue")
click_button("Create issue")
expect(page).to have_content(issue_title)
.and have_content(user.name)
......@@ -135,7 +135,7 @@ RSpec.describe "User creates issue" do
expect(find('#issuable-due-date').value).to eq date.to_s
click_button 'Submit issue'
click_button 'Create issue'
page.within '.issuable-sidebar' do
expect(page).to have_content date.to_s(:medium)
......@@ -259,7 +259,7 @@ RSpec.describe "User creates issue" do
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
click_button 'Submit issue'
click_button 'Create issue'
end
end
end
......
......@@ -28,7 +28,7 @@ RSpec.describe 'create a merge request, allowing commits from members who can me
check 'Allow commits from members who can merge to the target branch'
click_button 'Submit merge request'
click_button 'Create merge request'
wait_for_requests
......
......@@ -31,7 +31,7 @@ RSpec.describe "User creates a merge request", :js do
end
fill_in("Title", with: title)
click_button("Submit merge request")
click_button("Create merge request")
page.within(".merge-request") do
expect(page).to have_content(title)
......@@ -103,7 +103,7 @@ RSpec.describe "User creates a merge request", :js do
end
find('.js-assignee-search').click
click_button("Submit merge request")
click_button("Create merge request")
expect(page).to have_content(title).and have_content("Request to merge #{user.namespace.path}:#{source_branch} into master")
end
......
......@@ -32,7 +32,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows widget status after creating new merge request' do
click_button 'Submit merge request'
click_button 'Create merge request'
wait_for_requests
......
......@@ -60,7 +60,7 @@ RSpec.describe 'Merge request > User selects branches for new MR', :js do
expect(page).to have_content "wm.png"
fill_in "merge_request_title", with: "Orphaned MR test"
click_button "Submit merge request"
click_button "Create merge request"
click_button "Check out branch"
......@@ -200,7 +200,7 @@ RSpec.describe 'Merge request > User selects branches for new MR', :js do
click_button "Compare branches"
expect(page).to have_button("Submit merge request")
expect(page).to have_button("Create merge request")
end
end
end
......@@ -92,7 +92,7 @@ RSpec.describe 'User squashes a merge request', :js do
before do
visit project_new_merge_request_path(project, merge_request: { target_branch: 'master', source_branch: source_branch })
check 'merge_request[squash]'
click_on 'Submit merge request'
click_on 'Create merge request'
wait_for_requests
end
......@@ -121,7 +121,7 @@ RSpec.describe 'User squashes a merge request', :js do
context 'when squash is not enabled on merge request creation', :sidekiq_might_not_need_inline do
before do
visit project_new_merge_request_path(project, merge_request: { target_branch: 'master', source_branch: source_branch })
click_on 'Submit merge request'
click_on 'Create merge request'
wait_for_requests
end
......
......@@ -48,7 +48,7 @@ describe('Edit Actions components', () => {
vm.formState.title = '';
Vue.nextTick(() => {
expect(vm.$el.querySelector('.btn-success').getAttribute('disabled')).toBe('disabled');
expect(vm.$el.querySelector('.btn-confirm').getAttribute('disabled')).toBe('disabled');
done();
});
......@@ -65,16 +65,16 @@ describe('Edit Actions components', () => {
describe('updateIssuable', () => {
it('sends update.issauble event when clicking save button', () => {
vm.$el.querySelector('.btn-success').click();
vm.$el.querySelector('.btn-confirm').click();
expect(eventHub.$emit).toHaveBeenCalledWith('update.issuable');
});
it('disabled button after clicking save button', (done) => {
vm.$el.querySelector('.btn-success').click();
vm.$el.querySelector('.btn-confirm').click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.btn-success').getAttribute('disabled')).toBe('disabled');
expect(vm.$el.querySelector('.btn-confirm').getAttribute('disabled')).toBe('disabled');
done();
});
......
......@@ -43,7 +43,7 @@ RSpec.shared_examples 'a creatable merge request' do
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
click_button 'Submit merge request'
click_button 'Create merge request'
page.within '.issuable-sidebar' do
page.within '.assignee' do
......
......@@ -14,11 +14,11 @@ RSpec.shared_examples 'creating an issue for a thread' do
end
it 'can create a new issue for the project' do
expect { click_button 'Submit issue' }.to change { project.issues.reload.size }.by(1)
expect { click_button 'Create issue' }.to change { project.issues.reload.size }.by(1)
end
it 'resolves the discussion in the merge request' do
click_button 'Submit issue'
click_button 'Create issue'
discussion.first_note.reload
......@@ -26,7 +26,7 @@ RSpec.shared_examples 'creating an issue for a thread' do
end
it 'shows a flash messaage after resolving a discussion' do
click_button 'Submit issue'
click_button 'Create issue'
page.within '.flash-notice' do
# Only check for the word 'Resolved' since the spec might have resolved
......
......@@ -23,7 +23,7 @@ RSpec.shared_examples 'close quick action' do |issuable_type|
it "creates the #{issuable_type} and interprets close quick action accordingly" do
fill_in "#{issuable_type}_title", with: 'bug 345'
fill_in "#{issuable_type}_description", with: "bug description\n/close"
click_button "Submit #{issuable_type}".humanize
click_button "Create #{issuable_type}".humanize
issuable = project.public_send(issuable_type.to_s.pluralize).first
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment