Commit 98e00e9a authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents ede5a0ff 0adf5c66
...@@ -8,6 +8,14 @@ export const getJwt = () => { ...@@ -8,6 +8,14 @@ export const getJwt = () => {
}); });
}; };
export const getLocation = () => {
return new Promise((resolve) => {
AP.getLocation((location) => {
resolve(location);
});
});
};
export const addSubscription = async (addPath, namespace) => { export const addSubscription = async (addPath, namespace) => {
const jwt = await getJwt(); const jwt = await getJwt();
......
...@@ -3,6 +3,8 @@ import { mapState } from 'vuex'; ...@@ -3,6 +3,8 @@ import { mapState } from 'vuex';
import { GlAlert, GlButton, GlModal, GlModalDirective } from '@gitlab/ui'; import { GlAlert, GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { getLocation } from '~/jira_connect/api';
import GroupsList from './groups_list.vue'; import GroupsList from './groups_list.vue';
export default { export default {
...@@ -17,17 +19,42 @@ export default { ...@@ -17,17 +19,42 @@ export default {
GlModalDirective, GlModalDirective,
}, },
mixins: [glFeatureFlagsMixin()], mixins: [glFeatureFlagsMixin()],
inject: {
usersPath: {
default: '',
},
},
data() {
return {
location: '',
};
},
computed: { computed: {
...mapState(['errorMessage']), ...mapState(['errorMessage']),
showNewUI() { showNewUI() {
return this.glFeatures.newJiraConnectUi; return this.glFeatures.newJiraConnectUi;
}, },
usersPathWithReturnTo() {
if (this.location) {
return `${this.usersPath}?return_to=${this.location}`;
}
return this.usersPath;
},
}, },
modal: { modal: {
cancelProps: { cancelProps: {
text: __('Cancel'), text: __('Cancel'),
}, },
}, },
created() {
this.setLocation();
},
methods: {
async setLocation() {
this.location = await getLocation();
},
},
}; };
</script> </script>
...@@ -37,27 +64,40 @@ export default { ...@@ -37,27 +64,40 @@ export default {
{{ errorMessage }} {{ errorMessage }}
</gl-alert> </gl-alert>
<h1>GitLab for Jira Configuration</h1> <h2>{{ s__('JiraService|GitLab for Jira Configuration') }}</h2>
<div <div
v-if="showNewUI" v-if="showNewUI"
class="gl-display-flex gl-justify-content-space-between gl-my-5 gl-pb-4 gl-border-b-solid gl-border-b-1 gl-border-b-gray-200" class="gl-display-flex gl-justify-content-space-between gl-my-7 gl-pb-4 gl-border-b-solid gl-border-b-1 gl-border-b-gray-200"
> >
<h3 data-testid="new-jira-connect-ui-heading">{{ s__('Integrations|Linked namespaces') }}</h3> <h5 class="gl-align-self-center gl-mb-0" data-testid="new-jira-connect-ui-heading">
{{ s__('Integrations|Linked namespaces') }}
</h5>
<gl-button <gl-button
v-gl-modal-directive="'add-namespace-modal'" v-if="usersPath"
category="primary" category="primary"
variant="info" variant="info"
class="gl-align-self-center" class="gl-align-self-center"
>{{ s__('Integrations|Add namespace') }}</gl-button :href="usersPathWithReturnTo"
> target="_blank"
<gl-modal >{{ s__('Integrations|Sign in to add namespaces') }}</gl-button
modal-id="add-namespace-modal"
:title="s__('Integrations|Link namespaces')"
:action-cancel="$options.modal.cancelProps"
> >
<groups-list /> <template v-else>
</gl-modal> <gl-button
v-gl-modal-directive="'add-namespace-modal'"
category="primary"
variant="info"
class="gl-align-self-center"
>{{ s__('Integrations|Add namespace') }}</gl-button
>
<gl-modal
modal-id="add-namespace-modal"
:title="s__('Integrations|Link namespaces')"
:action-cancel="$options.modal.cancelProps"
>
<groups-list />
</gl-modal>
</template>
</div> </div>
</div> </div>
</template> </template>
...@@ -70,7 +70,7 @@ function initJiraConnect() { ...@@ -70,7 +70,7 @@ function initJiraConnect() {
Vue.use(Translate); Vue.use(Translate);
Vue.use(GlFeatureFlagsPlugin); Vue.use(GlFeatureFlagsPlugin);
const { groupsPath, subscriptionsPath } = el.dataset; const { groupsPath, subscriptionsPath, usersPath } = el.dataset;
return new Vue({ return new Vue({
el, el,
...@@ -78,6 +78,7 @@ function initJiraConnect() { ...@@ -78,6 +78,7 @@ function initJiraConnect() {
provide: { provide: {
groupsPath, groupsPath,
subscriptionsPath, subscriptionsPath,
usersPath,
}, },
render(createElement) { render(createElement) {
return createElement(JiraConnectApp); return createElement(JiraConnectApp);
......
<script>
export default {
props: {
hasUnsavedChanges: {
type: Boolean,
required: true,
},
},
created() {
window.addEventListener('beforeunload', this.confirmChanges);
},
destroyed() {
window.removeEventListener('beforeunload', this.confirmChanges);
},
methods: {
confirmChanges(e = {}) {
if (this.hasUnsavedChanges) {
e.preventDefault();
// eslint-disable-next-line no-param-reassign
e.returnValue = ''; // Chrome requires returnValue to be set
}
},
},
render: () => null,
};
</script>
...@@ -8,6 +8,7 @@ import httpStatusCodes from '~/lib/utils/http_status'; ...@@ -8,6 +8,7 @@ import httpStatusCodes from '~/lib/utils/http_status';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue'; import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import CiLint from './components/lint/ci_lint.vue'; import CiLint from './components/lint/ci_lint.vue';
import CommitForm from './components/commit/commit_form.vue'; import CommitForm from './components/commit/commit_form.vue';
import ConfirmUnsavedChangesDialog from './components/ui/confirm_unsaved_changes_dialog.vue';
import EditorTab from './components/ui/editor_tab.vue'; import EditorTab from './components/ui/editor_tab.vue';
import TextEditor from './components/text_editor.vue'; import TextEditor from './components/text_editor.vue';
import ValidationSegment from './components/info/validation_segment.vue'; import ValidationSegment from './components/info/validation_segment.vue';
...@@ -30,6 +31,7 @@ export default { ...@@ -30,6 +31,7 @@ export default {
components: { components: {
CiLint, CiLint,
CommitForm, CommitForm,
ConfirmUnsavedChangesDialog,
EditorTab, EditorTab,
GlAlert, GlAlert,
GlLoadingIcon, GlLoadingIcon,
...@@ -66,6 +68,7 @@ export default { ...@@ -66,6 +68,7 @@ export default {
ciConfigData: {}, ciConfigData: {},
content: '', content: '',
contentModel: '', contentModel: '',
lastCommittedContent: '',
lastCommitSha: this.commitSha, lastCommitSha: this.commitSha,
isSaving: false, isSaving: false,
...@@ -88,7 +91,9 @@ export default { ...@@ -88,7 +91,9 @@ export default {
}; };
}, },
update(data) { update(data) {
return data?.blobContent?.rawData; const content = data?.blobContent?.rawData;
this.lastCommittedContent = content;
return content;
}, },
result({ data }) { result({ data }) {
this.contentModel = data?.blobContent?.rawData ?? ''; this.contentModel = data?.blobContent?.rawData ?? '';
...@@ -122,6 +127,9 @@ export default { ...@@ -122,6 +127,9 @@ export default {
}, },
}, },
computed: { computed: {
hasUnsavedChanges() {
return this.lastCommittedContent !== this.contentModel;
},
isBlobContentLoading() { isBlobContentLoading() {
return this.$apollo.queries.content.loading; return this.$apollo.queries.content.loading;
}, },
...@@ -264,6 +272,7 @@ export default { ...@@ -264,6 +272,7 @@ export default {
// Update latest commit // Update latest commit
this.lastCommitSha = commit.sha; this.lastCommitSha = commit.sha;
this.lastCommittedContent = this.contentModel;
} }
} catch (error) { } catch (error) {
this.reportFailure(COMMIT_FAILURE, [error?.message]); this.reportFailure(COMMIT_FAILURE, [error?.message]);
...@@ -342,5 +351,6 @@ export default { ...@@ -342,5 +351,6 @@ export default {
@submit="onCommitSubmit" @submit="onCommitSubmit"
/> />
</div> </div>
<confirm-unsaved-changes-dialog :has-unsaved-changes="hasUnsavedChanges" />
</div> </div>
</template> </template>
...@@ -79,12 +79,6 @@ $header-height: 40px; ...@@ -79,12 +79,6 @@ $header-height: 40px;
margin-top: 16px; margin-top: 16px;
} }
.heading-with-border {
border-bottom: 1px solid $gray-100;
display: inline-block;
padding-bottom: 16px;
}
svg { svg {
fill: currentColor; fill: currentColor;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module ExternalLinkHelper module ExternalLinkHelper
def external_link(body, url, options = {}) def external_link(body, url, options = {})
link_to url, { target: '_blank', rel: 'noopener noreferrer' }.merge(options) do link_to url, { target: '_blank', rel: 'noopener noreferrer' }.merge(options) do
"#{body} #{sprite_icon('external-link')}".html_safe "#{body}#{sprite_icon('external-link', css_class: 'gl-ml-1')}".html_safe
end end
end end
end end
...@@ -12,7 +12,8 @@ module JiraConnectHelper ...@@ -12,7 +12,8 @@ module JiraConnectHelper
{ {
groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: skip_groups }), groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: skip_groups }),
subscriptions_path: jira_connect_subscriptions_path subscriptions_path: jira_connect_subscriptions_path,
users_path: current_user ? nil : jira_connect_users_path
} }
end end
end end
...@@ -1008,7 +1008,7 @@ module Ci ...@@ -1008,7 +1008,7 @@ module Ci
end end
def can_generate_codequality_reports? def can_generate_codequality_reports?
return false unless Feature.enabled?(:codequality_mr_diff, project) return false unless ::Gitlab::Ci::Features.display_quality_on_mr_diff?(project)
has_reports?(Ci::JobArtifact.codequality_reports) has_reports?(Ci::JobArtifact.codequality_reports)
end end
......
...@@ -1485,7 +1485,7 @@ class MergeRequest < ApplicationRecord ...@@ -1485,7 +1485,7 @@ class MergeRequest < ApplicationRecord
end end
def has_codequality_reports? def has_codequality_reports?
return false unless Feature.enabled?(:codequality_mr_diff, project) return false unless ::Gitlab::Ci::Features.display_quality_on_mr_diff?(project)
actual_head_pipeline&.has_reports?(Ci::JobArtifact.codequality_reports) actual_head_pipeline&.has_reports?(Ci::JobArtifact.codequality_reports)
end end
......
...@@ -5,12 +5,12 @@ ...@@ -5,12 +5,12 @@
.col-sm-2.col-form-label .col-sm-2.col-form-label
= f.label :title = f.label :title
.col-sm-10 .col-sm-10
= f.text_field :title, class: "form-control", required: true = f.text_field :title, class: "form-control gl-form-input", required: true
.form-group.row .form-group.row
.col-sm-2.col-form-label .col-sm-2.col-form-label
= f.label :description = f.label :description
.col-sm-10 .col-sm-10
= f.text_field :description, class: "form-control js-quick-submit" = f.text_field :description, class: "form-control gl-form-input js-quick-submit"
.form-group.row .form-group.row
.col-sm-2.col-form-label .col-sm-2.col-form-label
= f.label :color, _("Background color") = f.label :color, _("Background color")
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
.input-group .input-group
.input-group-prepend .input-group-prepend
.input-group-text.label-color-preview &nbsp; .input-group-text.label-color-preview &nbsp;
= f.text_field :color, class: "form-control" = f.text_field :color, class: "form-control gl-form-input"
.form-text.text-muted .form-text.text-muted
= _('Choose any color.') = _('Choose any color.')
%br %br
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
.form-group .form-group
= f.label :name, class: 'label-bold' = f.label :name, class: 'label-bold'
= f.text_field :name, class: 'form-control', required: true = f.text_field :name, class: 'form-control gl-form-input', required: true
.form-group .form-group
= f.label :redirect_uri, class: 'label-bold' = f.label :redirect_uri, class: 'label-bold'
= f.text_area :redirect_uri, class: 'form-control', required: true = f.text_area :redirect_uri, class: 'form-control gl-form-input gl-form-textarea', required: true
%span.form-text.text-muted %span.form-text.text-muted
= _('Use one line per URI') = _('Use one line per URI')
......
...@@ -3,21 +3,21 @@ ...@@ -3,21 +3,21 @@
.jira-connect-user .jira-connect-user
- if current_user - if current_user
- user_link = link_to(current_user.to_reference, user_path(current_user), target: '_blank', rel: 'noopener noreferrer') - user_link = link_to(current_user.to_reference, jira_connect_users_path, target: '_blank', rel: 'noopener noreferrer', class: 'js-jira-connect-sign-in')
= _('Signed in to GitLab as %{user_link}').html_safe % { user_link: user_link } = _('Signed in to GitLab as %{user_link}').html_safe % { user_link: user_link }
- elsif @subscriptions.present? - elsif @subscriptions.present?
= link_to _('Sign in to GitLab'), jira_connect_users_path, target: '_blank', rel: 'noopener noreferrer', class: 'js-jira-connect-sign-in' = link_to _('Sign in to GitLab'), jira_connect_users_path, target: '_blank', rel: 'noopener noreferrer', class: 'js-jira-connect-sign-in'
.jira-connect-app .jira-connect-app
- if current_user.blank? && @subscriptions.empty? - if current_user.blank? && @subscriptions.empty?
%h1 %h2= s_('JiraService|GitLab for Jira Configuration')
GitLab for Jira Configuration %p= s_('JiraService|Sign in to GitLab.com to get started.')
%h2.heading-with-border Sign in to GitLab.com to get started.
.gl-mt-5 .gl-mt-7
= external_link _('Sign in to GitLab'), jira_connect_users_path, class: 'ak-button ak-button__appearance-primary js-jira-connect-sign-in' - sign_in_button_class = new_jira_connect_ui? ? 'btn gl-button btn-confirm' : 'ak-button ak-button__appearance-primary'
= external_link _('Sign in to GitLab'), jira_connect_users_path, class: "#{sign_in_button_class} js-jira-connect-sign-in"
.gl-mt-5 .gl-mt-7
%p Note: this integration only works with accounts on GitLab.com (SaaS). %p Note: this integration only works with accounts on GitLab.com (SaaS).
- else - else
.js-jira-connect-app{ data: jira_connect_app_data(@subscriptions) } .js-jira-connect-app{ data: jira_connect_app_data(@subscriptions) }
...@@ -55,10 +55,8 @@ ...@@ -55,10 +55,8 @@
%strong Browser limitations: %strong Browser limitations:
Adding a namespace currently works only in browsers that allow cross‑site cookies. Please make sure to use Adding a namespace currently works only in browsers that allow cross‑site cookies. Please make sure to use
%a{ href: 'https://www.mozilla.org/en-US/firefox/', target: '_blank', rel: 'noopener noreferrer' } Firefox %a{ href: 'https://www.mozilla.org/en-US/firefox/', target: '_blank', rel: 'noopener noreferrer' } Firefox
or
%a{ href: 'https://www.google.com/chrome/index.html', target: '_blank', rel: 'noopener noreferrer' } Google Chrome
or enable cross‑site cookies in your browser when adding a namespace. or enable cross‑site cookies in your browser when adding a namespace.
%a{ href: 'https://gitlab.com/gitlab-org/gitlab/-/issues/263509', target: '_blank', rel: 'noopener noreferrer' } Learn more = link_to _('Learn more'), 'https://gitlab.com/gitlab-org/gitlab/-/issues/284211', target: '_blank', rel: 'noopener noreferrer'
= webpack_bundle_tag 'performance_bar' if performance_bar_enabled? = webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
= webpack_bundle_tag 'jira_connect_app' = webpack_bundle_tag 'jira_connect_app'
......
---
title: Apply new GitLab UI for input field in user applications
merge_request: 52425
author: Yogi (@yo)
type: other
---
title: Show confirmation dialog when exiting pipeline editor
merge_request: 52458
author:
type: added
---
title: Apply new GitLab UI for input field in admin/labels
merge_request: 52413
author: Yogi (@yo)
type: other
...@@ -76,7 +76,7 @@ Example response: ...@@ -76,7 +76,7 @@ Example response:
] ]
``` ```
Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) see Users on GitLab [Premium or higher](https://about.gitlab.com/pricing/) see
different parameters, due to the ability to have multiple group boards. different parameters, due to the ability to have multiple group boards.
Example response: Example response:
...@@ -192,7 +192,7 @@ Example response: ...@@ -192,7 +192,7 @@ Example response:
} }
``` ```
Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) see Users on GitLab [Premium or higher](https://about.gitlab.com/pricing/) see
different parameters, due to the ability to have multiple group issue boards. different parameters, due to the ability to have multiple group issue boards.
Example response: Example response:
......
...@@ -685,7 +685,7 @@ Additional response parameters: ...@@ -685,7 +685,7 @@ Additional response parameters:
} }
``` ```
Users on GitLab [Silver, Premium, or higher](https://about.gitlab.com/pricing/) also see Users on GitLab [Premium or higher](https://about.gitlab.com/pricing/) also see
the `marked_for_deletion_on` attribute: the `marked_for_deletion_on` attribute:
```json ```json
...@@ -961,7 +961,7 @@ Only available to group owners and administrators. ...@@ -961,7 +961,7 @@ Only available to group owners and administrators.
This endpoint either: This endpoint either:
- Removes group, and queues a background job to delete all projects in the group as well. - Removes group, and queues a background job to delete all projects in the group as well.
- Since [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/issues/33257), on [Premium or Silver](https://about.gitlab.com/pricing/) or higher tiers, marks a group for deletion. The deletion happens 7 days later by default, but this can be changed in the [instance settings](../user/admin_area/settings/visibility_and_access_controls.md#default-deletion-delay). - Since [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/issues/33257), on [Premium](https://about.gitlab.com/pricing/) or higher tiers, marks a group for deletion. The deletion happens 7 days later by default, but this can be changed in the [instance settings](../user/admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
```plaintext ```plaintext
DELETE /groups/:id DELETE /groups/:id
...@@ -1319,7 +1319,7 @@ GET /groups/:id/push_rule ...@@ -1319,7 +1319,7 @@ GET /groups/:id/push_rule
} }
``` ```
Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) also see Users on GitLab [Premium or higher](https://about.gitlab.com/pricing/) also see
the `commit_committer_check` and `reject_unsigned_commits` parameters: the `commit_committer_check` and `reject_unsigned_commits` parameters:
```json ```json
......
...@@ -298,7 +298,7 @@ When the user is authenticated and `simple` is not set this returns something li ...@@ -298,7 +298,7 @@ When the user is authenticated and `simple` is not set this returns something li
``` ```
NOTE: NOTE:
For users of GitLab [Silver, Premium, or higher](https://about.gitlab.com/pricing/), For users of GitLab [Premium or higher](https://about.gitlab.com/pricing/),
the `marked_for_deletion_at` attribute has been deprecated, and is removed the `marked_for_deletion_at` attribute has been deprecated, and is removed
in API v5 in favor of the `marked_for_deletion_on` attribute. in API v5 in favor of the `marked_for_deletion_on` attribute.
...@@ -1877,7 +1877,7 @@ This endpoint: ...@@ -1877,7 +1877,7 @@ This endpoint:
- Deletes a project including all associated resources (including issues and - Deletes a project including all associated resources (including issues and
merge requests). merge requests).
- From [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) on - From [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) on
[Premium or Silver](https://about.gitlab.com/pricing/) or higher tiers, group [Premium](https://about.gitlab.com/pricing/) or higher tiers, group
admins can [configure](../user/group/index.md#enabling-delayed-project-removal) admins can [configure](../user/group/index.md#enabling-delayed-project-removal)
projects within a group to be deleted after a delayed period. When enabled, projects within a group to be deleted after a delayed period. When enabled,
actual deletion happens after the number of days specified in the actual deletion happens after the number of days specified in the
...@@ -2231,7 +2231,7 @@ GET /projects/:id/push_rule ...@@ -2231,7 +2231,7 @@ GET /projects/:id/push_rule
} }
``` ```
Users of GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) Users of GitLab [Premium or higher](https://about.gitlab.com/pricing/)
can also see the `commit_committer_check` and `reject_unsigned_commits` can also see the `commit_committer_check` and `reject_unsigned_commits`
parameters: parameters:
......
...@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w ...@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# SCIM API (SYSTEM ONLY) **(PREMIUM SAAS)** # SCIM API (SYSTEM ONLY) **(PREMIUM SAAS)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9388) in [GitLab.com Silver](https://about.gitlab.com/pricing/) 11.10. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9388) in GitLab Premium 11.10.
The SCIM API implements the [RFC7644 protocol](https://tools.ietf.org/html/rfc7644). As this API is for The SCIM API implements the [RFC7644 protocol](https://tools.ietf.org/html/rfc7644). As this API is for
**system** use for SCIM provider integration, it is subject to change without notice. **system** use for SCIM provider integration, it is subject to change without notice.
......
...@@ -186,7 +186,7 @@ Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) ...@@ -186,7 +186,7 @@ Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/)
] ]
``` ```
Users on GitLab [Silver or higher](https://about.gitlab.com/pricing/) also see Users on GitLab [Premium or higher](https://about.gitlab.com/pricing/) also see
the `group_saml` provider option: the `group_saml` provider option:
```json ```json
...@@ -350,7 +350,7 @@ the `shared_runners_minutes_limit`, and `extra_shared_runners_minutes_limit` par ...@@ -350,7 +350,7 @@ the `shared_runners_minutes_limit`, and `extra_shared_runners_minutes_limit` par
} }
``` ```
Users on GitLab.com [Silver, or higher](https://about.gitlab.com/pricing/) also Users on GitLab.com [Premium or higher](https://about.gitlab.com/pricing/) also
see the `group_saml` option: see the `group_saml` option:
```json ```json
......
...@@ -483,12 +483,16 @@ For GitLab.com, we're setting up a [QA and Testing environment](https://gitlab.c ...@@ -483,12 +483,16 @@ For GitLab.com, we're setting up a [QA and Testing environment](https://gitlab.c
### `gitlab_standard` ### `gitlab_standard`
The [`gitlab_standard` schema](https://gitlab.com/gitlab-org/iglu/-/blob/master/public/schemas/com.gitlab/gitlab_standard/jsonschema/1-0-0) is available. We are currently working towards including the [`gitlab_standard` schema](https://gitlab.com/gitlab-org/iglu/-/blob/master/public/schemas/com.gitlab/gitlab_standard/jsonschema/) with every event. See [Standardize Snowplow Schema](https://gitlab.com/groups/gitlab-org/-/epics/5218) for details.
| Field Name | Required | Type | Description | The [`StandardContext`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/tracking/standard_context.rb) class represents this schema in the application.
|--------------|---------------------|---------|--------------------------------|
| project_id | **{dotted-circle}** | integer | ID of the associated project | | Field Name | Required | Type | Description |
| namespace_id | **{dotted-circle}** | integer | ID of the associated namespace | |----------------|---------------------|-----------------------|---------------------------------------------------------------------------------------------|
| `project_id` | **{dotted-circle}** | integer | |
| `namespace_id` | **{dotted-circle}** | integer | |
| `environment` | **{check-circle}** | string (max 32 chars) | Name of the source environment, such as `production` or `staging` |
| `source` | **{check-circle}** | string (max 32 chars) | Name of the source application, such as `gitlab-rails` or `gitlab-javascript` |
### Default Schema ### Default Schema
......
...@@ -4,15 +4,7 @@ module PolicyHelper ...@@ -4,15 +4,7 @@ module PolicyHelper
def policy_details(project, policy = nil, environment = nil) def policy_details(project, policy = nil, environment = nil)
return unless project return unless project
details = { details = details(project)
network_policies_endpoint: project_security_network_policies_path(project),
configure_agent_help_path: help_page_url('user/clusters/agent/repository.html'),
create_agent_help_path: help_page_url('user/clusters/agent/index.md', anchor: 'create-an-agent-record-in-gitlab'),
environments_endpoint: project_environments_path(project),
project_path: project.full_path,
threat_monitoring_path: project_threat_monitoring_path(project)
}
return details unless policy && environment return details unless policy && environment
edit_details = { edit_details = {
...@@ -21,4 +13,17 @@ module PolicyHelper ...@@ -21,4 +13,17 @@ module PolicyHelper
} }
details.merge(edit_details) details.merge(edit_details)
end end
private
def details(project)
{
network_policies_endpoint: project_security_network_policies_path(project),
configure_agent_help_path: help_page_url('user/clusters/agent/repository.html'),
create_agent_help_path: help_page_url('user/clusters/agent/index.md', anchor: 'create-an-agent-record-in-gitlab'),
environments_endpoint: project_environments_path(project),
project_path: project.full_path,
threat_monitoring_path: project_threat_monitoring_path(project)
}
end
end end
---
title: Abstract out details of policy_helper
merge_request: 52714
author:
type: other
...@@ -27,24 +27,52 @@ RSpec.describe "Admin views license" do ...@@ -27,24 +27,52 @@ RSpec.describe "Admin views license" do
context "when license is regular" do context "when license is regular" do
let_it_be(:license) { create(:license) } let_it_be(:license) { create(:license) }
let_it_be(:reference_date) { Date.parse('2020-01-22') }
before do context "when license is expired" do
visit(admin_license_path) let_it_be(:license) { build(:license, data: build(:gitlab_license, expires_at: reference_date - 1.day).export).save!(validate: false) }
end
context "when license expired" do it do
let_it_be(:license) { build(:license, data: build(:gitlab_license, expires_at: Date.yesterday).export).save!(validate: false) } travel_to(reference_date) do
visit(admin_license_path)
it { expect(page).to have_content("Your subscription expired!") } expect(page).to have_content("Your subscription expired!")
expect(page).to have_link 'Renew subscription', href: "#{EE::SUBSCRIPTIONS_URL}/subscriptions"
end
end
context "when license blocks changes" do context "when license blocks changes" do
let_it_be(:license) { build(:license, data: build(:gitlab_license, expires_at: Date.yesterday, block_changes_at: Date.today).export).save!(validate: false) } let_it_be(:license) { build(:license, data: build(:gitlab_license, expires_at: reference_date - 1.week).export).save!(validate: false) }
it do
travel_to(reference_date) do
visit(admin_license_path)
it { expect(page).to have_content "You didn't renew your subscription so it was downgraded to the GitLab Core Plan" } expect(page).to have_content "You have 7 days to renew your subscription."
expect(page).to have_link 'Renew subscription', href: "#{EE::SUBSCRIPTIONS_URL}/subscriptions"
end
end
end
context "when license blocks changes" do
let_it_be(:license) { build(:license, data: build(:gitlab_license, expires_at: reference_date - 4.weeks, block_changes_at: reference_date - 1.day).export).save!(validate: false) }
it do
travel_to(reference_date) do
visit(admin_license_path)
expect(page).to have_content "You didn't renew your subscription so it was downgraded to the GitLab Core Plan"
expect(page).to have_link 'Upgrade your plan', href: "#{EE::SUBSCRIPTIONS_URL}/subscriptions"
end
end
end end
end end
context "when viewing license history", :aggregate_failures do context "when viewing license history", :aggregate_failures do
before do
visit(admin_license_path)
end
it "shows licensee" do it "shows licensee" do
license_history = page.find("#license_history") license_history = page.find("#license_history")
......
...@@ -4,6 +4,8 @@ require 'spec_helper' ...@@ -4,6 +4,8 @@ require 'spec_helper'
RSpec.describe PolicyHelper do RSpec.describe PolicyHelper do
let(:project) { create(:project, :repository, :public) } let(:project) { create(:project, :repository, :public) }
let(:environment) { create(:environment, project: project) }
let(:policy) do let(:policy) do
Gitlab::Kubernetes::CiliumNetworkPolicy.new( Gitlab::Kubernetes::CiliumNetworkPolicy.new(
name: 'policy', name: 'policy',
...@@ -13,21 +15,23 @@ RSpec.describe PolicyHelper do ...@@ -13,21 +15,23 @@ RSpec.describe PolicyHelper do
) )
end end
let(:environment) { create(:environment, project: project) } let(:base_data) do
{
network_policies_endpoint: kind_of(String),
configure_agent_help_path: kind_of(String),
create_agent_help_path: kind_of(String),
environments_endpoint: kind_of(String),
project_path: project.full_path,
threat_monitoring_path: kind_of(String)
}
end
describe '#policy_details' do describe '#policy_details' do
context 'when a new policy is being created' do context 'when a new policy is being created' do
subject { helper.policy_details(project) } subject { helper.policy_details(project) }
it 'returns expected policy data' do it 'returns expected policy data' do
expect(subject).to match( expect(subject).to match(base_data)
network_policies_endpoint: kind_of(String),
configure_agent_help_path: kind_of(String),
create_agent_help_path: kind_of(String),
environments_endpoint: kind_of(String),
project_path: project.full_path,
threat_monitoring_path: kind_of(String)
)
end end
end end
...@@ -36,16 +40,20 @@ RSpec.describe PolicyHelper do ...@@ -36,16 +40,20 @@ RSpec.describe PolicyHelper do
it 'returns expected policy data' do it 'returns expected policy data' do
expect(subject).to match( expect(subject).to match(
network_policies_endpoint: kind_of(String), base_data.merge(
configure_agent_help_path: kind_of(String), policy: policy.to_json,
create_agent_help_path: kind_of(String), environment_id: environment.id
environments_endpoint: kind_of(String), )
project_path: project.full_path,
threat_monitoring_path: kind_of(String),
policy: policy.to_json,
environment_id: environment.id
) )
end end
end end
context 'when no environment is passed in' do
subject { helper.policy_details(project, policy) }
it 'returns expected policy data' do
expect(subject).to match(base_data)
end
end
end end
end end
...@@ -14,31 +14,15 @@ RSpec.describe 'layouts/header/_ee_subscribable_banner' do ...@@ -14,31 +14,15 @@ RSpec.describe 'layouts/header/_ee_subscribable_banner' do
end end
shared_examples 'displays the correct link' do shared_examples 'displays the correct link' do
context "when license will soon expire" do context "when license has expired" do
let(:license) { build(:gitlab_license, expires_at: Date.current + 5.days) } let(:license) { build(:gitlab_license, expires_at: Date.current - 1.week) }
it 'shows the renew plan link' do it 'shows the renew plan link' do
expect(rendered).to have_link 'Renew subscription', href: view.renew_subscription_path expect(rendered).to have_link 'Renew subscription', href: view.renew_subscription_path
end end
context "when license blocks changes" do context "when license blocks changes" do
let(:license) { build(:gitlab_license, expires_at: Date.current + 5.days, block_changes_at: Date.today) } let(:license) { build(:gitlab_license, expires_at: Date.current - 3.weeks) }
it 'shows the upgrade plan link' do
expect(rendered).to have_link 'Upgrade your plan', href: view.upgrade_subscription_path
end
end
end
context "when license expired" do
let(:license) { build(:gitlab_license, expires_at: Date.yesterday) }
it 'shows the renew plan link' do
expect(rendered).to have_link 'Renew subscription', href: view.renew_subscription_path
end
context "when license blocks changes" do
let(:license) { build(:gitlab_license, expires_at: Date.yesterday, block_changes_at: Date.today) }
it 'shows the upgrade plan link' do it 'shows the upgrade plan link' do
expect(rendered).to have_link 'Upgrade your plan', href: view.upgrade_subscription_path expect(rendered).to have_link 'Upgrade your plan', href: view.upgrade_subscription_path
......
...@@ -71,6 +71,10 @@ module Gitlab ...@@ -71,6 +71,10 @@ module Gitlab
::Feature.enabled?(:ci_validate_build_dependencies, default_enabled: :yaml) && ::Feature.enabled?(:ci_validate_build_dependencies, default_enabled: :yaml) &&
::Feature.disabled?(:ci_validate_build_dependencies_override, project) ::Feature.disabled?(:ci_validate_build_dependencies_override, project)
end end
def self.display_quality_on_mr_diff?(project)
::Feature.enabled?(:codequality_mr_diff, project, default_enabled: false)
end
end end
end end
end end
...@@ -4,6 +4,7 @@ module Gitlab ...@@ -4,6 +4,7 @@ module Gitlab
module Tracking module Tracking
class StandardContext class StandardContext
GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-0-2'.freeze GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-0-2'.freeze
GITLAB_RAILS_SOURCE = 'gitlab-rails'.freeze
def initialize(namespace: nil, project: nil, user: nil, **data) def initialize(namespace: nil, project: nil, user: nil, **data)
@data = data @data = data
...@@ -21,6 +22,10 @@ module Gitlab ...@@ -21,6 +22,10 @@ module Gitlab
'development' 'development'
end end
def source
GITLAB_RAILS_SOURCE
end
private private
def to_h def to_h
......
...@@ -15482,6 +15482,9 @@ msgstr "" ...@@ -15482,6 +15482,9 @@ msgstr ""
msgid "Integrations|Search Jira issues" msgid "Integrations|Search Jira issues"
msgstr "" msgstr ""
msgid "Integrations|Sign in to add namespaces"
msgstr ""
msgid "Integrations|Standard" msgid "Integrations|Standard"
msgstr "" msgstr ""
...@@ -16148,6 +16151,9 @@ msgstr "" ...@@ -16148,6 +16151,9 @@ msgstr ""
msgid "JiraService|For example, 12, 24" msgid "JiraService|For example, 12, 24"
msgstr "" msgstr ""
msgid "JiraService|GitLab for Jira Configuration"
msgstr ""
msgid "JiraService|If different from Web URL" msgid "JiraService|If different from Web URL"
msgstr "" msgstr ""
...@@ -16199,6 +16205,9 @@ msgstr "" ...@@ -16199,6 +16205,9 @@ msgstr ""
msgid "JiraService|Set transition IDs for Jira workflow transitions. %{link_start}Learn more%{link_end}" msgid "JiraService|Set transition IDs for Jira workflow transitions. %{link_start}Learn more%{link_end}"
msgstr "" msgstr ""
msgid "JiraService|Sign in to GitLab.com to get started."
msgstr ""
msgid "JiraService|This feature requires a Premium plan." msgid "JiraService|This feature requires a Premium plan."
msgstr "" msgstr ""
......
import Vue from 'vue';
import Vuex from 'vuex';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { GlAlert } from '@gitlab/ui'; import { GlAlert, GlButton, GlModal } from '@gitlab/ui';
import JiraConnectApp from '~/jira_connect/components/app.vue'; import JiraConnectApp from '~/jira_connect/components/app.vue';
import createStore from '~/jira_connect/store'; import createStore from '~/jira_connect/store';
import { SET_ERROR_MESSAGE } from '~/jira_connect/store/mutation_types'; import { SET_ERROR_MESSAGE } from '~/jira_connect/store/mutation_types';
Vue.use(Vuex); jest.mock('~/jira_connect/api');
describe('JiraConnectApp', () => { describe('JiraConnectApp', () => {
let wrapper; let wrapper;
let store; let store;
const findAlert = () => wrapper.findComponent(GlAlert); const findAlert = () => wrapper.findComponent(GlAlert);
const findGlButton = () => wrapper.findComponent(GlButton);
const findGlModal = () => wrapper.findComponent(GlModal);
const findHeader = () => wrapper.findByTestId('new-jira-connect-ui-heading'); const findHeader = () => wrapper.findByTestId('new-jira-connect-ui-heading');
const findHeaderText = () => findHeader().text(); const findHeaderText = () => findHeader().text();
...@@ -44,6 +45,33 @@ describe('JiraConnectApp', () => { ...@@ -44,6 +45,33 @@ describe('JiraConnectApp', () => {
expect(findHeaderText()).toBe('Linked namespaces'); expect(findHeaderText()).toBe('Linked namespaces');
}); });
describe('when user is not logged in', () => {
beforeEach(() => {
createComponent({
provide: {
glFeatures: { newJiraConnectUi: true },
usersPath: '/users',
},
});
});
it('renders "Sign in" button', () => {
expect(findGlButton().text()).toBe('Sign in to add namespaces');
expect(findGlModal().exists()).toBe(false);
});
});
describe('when user is logged in', () => {
beforeEach(() => {
createComponent();
});
it('renders "Add" button and modal', () => {
expect(findGlButton().text()).toBe('Add namespace');
expect(findGlModal().exists()).toBe(true);
});
});
describe('newJiraConnectUi is false', () => { describe('newJiraConnectUi is false', () => {
it('does not render new UI', () => { it('does not render new UI', () => {
createComponent({ createComponent({
......
import { shallowMount } from '@vue/test-utils';
import ConfirmDialog from '~/pipeline_editor/components/ui/confirm_unsaved_changes_dialog.vue';
describe('pipeline_editor/components/ui/confirm_unsaved_changes_dialog', () => {
let beforeUnloadEvent;
let setDialogContent;
let wrapper;
const createComponent = (propsData = {}) => {
wrapper = shallowMount(ConfirmDialog, {
propsData,
});
};
beforeEach(() => {
beforeUnloadEvent = new Event('beforeunload');
jest.spyOn(beforeUnloadEvent, 'preventDefault');
setDialogContent = jest.spyOn(beforeUnloadEvent, 'returnValue', 'set');
});
afterEach(() => {
beforeUnloadEvent.preventDefault.mockRestore();
setDialogContent.mockRestore();
wrapper.destroy();
});
it('shows confirmation dialog when there are unsaved changes', () => {
createComponent({ hasUnsavedChanges: true });
window.dispatchEvent(beforeUnloadEvent);
expect(beforeUnloadEvent.preventDefault).toHaveBeenCalled();
expect(setDialogContent).toHaveBeenCalledWith('');
});
it('does not show confirmation dialog when there are no unsaved changes', () => {
createComponent({ hasUnsavedChanges: false });
window.dispatchEvent(beforeUnloadEvent);
expect(beforeUnloadEvent.preventDefault).not.toHaveBeenCalled();
expect(setDialogContent).not.toHaveBeenCalled();
});
});
...@@ -5,20 +5,42 @@ require 'spec_helper' ...@@ -5,20 +5,42 @@ require 'spec_helper'
RSpec.describe JiraConnectHelper do RSpec.describe JiraConnectHelper do
describe '#jira_connect_app_data' do describe '#jira_connect_app_data' do
let_it_be(:subscription) { create(:jira_connect_subscription) } let_it_be(:subscription) { create(:jira_connect_subscription) }
let(:user) { create(:user) }
subject { helper.jira_connect_app_data([subscription]) } subject { helper.jira_connect_app_data([subscription]) }
it 'includes Jira Connect app attributes' do context 'user is not logged in' do
is_expected.to include( before do
:groups_path, allow(view).to receive(:current_user).and_return(nil)
:subscriptions_path end
)
it 'includes Jira Connect app attributes' do
is_expected.to include(
:groups_path,
:subscriptions_path,
:users_path
)
end
it 'assigns users_path with value' do
expect(subject[:users_path]).to eq(jira_connect_users_path)
end
it 'passes group as "skip_groups" param' do
skip_groups_param = CGI.escape('skip_groups[]')
expect(subject[:groups_path]).to include("#{skip_groups_param}=#{subscription.namespace.id}")
end
end end
it 'passes group as "skip_groups" param' do context 'user is logged in' do
skip_groups_param = CGI.escape('skip_groups[]') before do
allow(view).to receive(:current_user).and_return(user)
end
expect(subject[:groups_path]).to include("#{skip_groups_param}=#{subscription.namespace.id}") it 'assigns users_path to nil' do
expect(subject[:users_path]).to be_nil
end
end end
end end
end end
...@@ -9,7 +9,7 @@ RSpec.describe Gitlab::Tracking::StandardContext do ...@@ -9,7 +9,7 @@ RSpec.describe Gitlab::Tracking::StandardContext do
let(:snowplow_context) { subject.to_context } let(:snowplow_context) { subject.to_context }
describe '#to_context' do describe '#to_context' do
context 'with no arguments' do context 'default fields' do
context 'environment' do context 'environment' do
shared_examples 'contains environment' do |expected_environment| shared_examples 'contains environment' do |expected_environment|
it 'contains environment' do it 'contains environment' do
...@@ -37,6 +37,10 @@ RSpec.describe Gitlab::Tracking::StandardContext do ...@@ -37,6 +37,10 @@ RSpec.describe Gitlab::Tracking::StandardContext do
include_examples 'contains environment', 'production' include_examples 'contains environment', 'production'
end end
end end
it 'contains source' do
expect(snowplow_context.to_json.dig(:data, :source)).to eq(described_class::GITLAB_RAILS_SOURCE)
end
end end
context 'with extra data' do context 'with extra data' do
......
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