Skip to content
Snippets Groups Projects
Commit c6043933 authored by pshutsin's avatar pshutsin
Browse files

Pivot Devops adoption to groups

Changes DevopsAdoption to be structured
around groups instead of segments
parent d6d09424
No related branches found
No related tags found
No related merge requests found
Showing
with 144 additions and 406 deletions
---
title: Change DevopsAdoption feature to work with single group only
merge_request: 52871
author:
type: changed
# frozen_string_literal: true
class AddDevopsAdoptionGroupSegment < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column :analytics_devops_adoption_segments, :namespace_id, :integer, if_not_exists: true
add_concurrent_index :analytics_devops_adoption_segments, :namespace_id, unique: true
end
def down
remove_column :analytics_devops_adoption_segments, :namespace_id
end
end
# frozen_string_literal: true
class OptionalDevopsAdoptionSegmentName < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
INDEX_NAME = 'index_analytics_devops_adoption_segments_on_name'
def up
change_column_null :analytics_devops_adoption_segments, :name, true
remove_concurrent_index_by_name :analytics_devops_adoption_segments, INDEX_NAME
end
def down
transaction do
execute "DELETE FROM analytics_devops_adoption_segments WHERE name IS NULL"
change_column_null :analytics_devops_adoption_segments, :name, false
end
add_concurrent_index :analytics_devops_adoption_segments, :name, unique: true, name: INDEX_NAME
end
end
# frozen_string_literal: true
class AddDevopsAdoptionSegmentNamespaceFk < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key :analytics_devops_adoption_segments, :namespaces, column: :namespace_id
end
def down
remove_foreign_key_if_exists :analytics_devops_adoption_segments, :namespaces, column: :namespace_id
end
end
# frozen_string_literal: true
# Data migration to migrate multi-selection segments into separate segments.
# Both tables involved are pretty-low traffic and the number
# of records in DB cannot exceed 400
class MigrateExistingDevopsSegmentsToGroups < ActiveRecord::Migration[6.0]
DOWNTIME = false
def up
Gitlab::BackgroundMigration::MigrateDevopsSegmentsToGroups.new.perform
end
def down
end
end
12a5eba74f0bb5b63cddd32d32009ad073e638a9defb40eeee5c16f559ebe951
\ No newline at end of file
359231b3f18a2c1e56ffba4872a51d01fd4ca834ef722e1133a5a9f01e4271e9
\ No newline at end of file
0c80fa1c88f67ef34bbfab52b1b75eadc4a6f07557986f0fbe4ffd83e20df52a
\ No newline at end of file
1f05176d9f6a88e9d740000084b7c9f5c72c61a59dbe1f68f43b3b5606ecd9d8
\ No newline at end of file
Loading
Loading
@@ -8990,10 +8990,11 @@ ALTER SEQUENCE analytics_devops_adoption_segment_selections_id_seq OWNED BY anal
 
CREATE TABLE analytics_devops_adoption_segments (
id bigint NOT NULL,
name text NOT NULL,
name text,
last_recorded_at timestamp with time zone,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
namespace_id integer,
CONSTRAINT check_4be7a006fd CHECK ((char_length(name) <= 255))
);
 
Loading
Loading
@@ -21363,7 +21364,7 @@ CREATE INDEX index_analytics_ca_project_stages_on_start_event_label_id ON analyt
 
CREATE INDEX index_analytics_cycle_analytics_group_stages_custom_only ON analytics_cycle_analytics_group_stages USING btree (id) WHERE (custom = true);
 
CREATE UNIQUE INDEX index_analytics_devops_adoption_segments_on_name ON analytics_devops_adoption_segments USING btree (name);
CREATE UNIQUE INDEX index_analytics_devops_adoption_segments_on_namespace_id ON analytics_devops_adoption_segments USING btree (namespace_id);
 
CREATE INDEX index_application_settings_on_custom_project_templates_group_id ON application_settings USING btree (custom_project_templates_group_id);
 
Loading
Loading
@@ -24702,6 +24703,9 @@ ALTER TABLE ONLY ci_pipeline_variables
ALTER TABLE ONLY design_management_designs_versions
ADD CONSTRAINT fk_f4d25ba00c FOREIGN KEY (version_id) REFERENCES design_management_versions(id) ON DELETE CASCADE;
 
ALTER TABLE ONLY analytics_devops_adoption_segments
ADD CONSTRAINT fk_f5aa768998 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY protected_tag_create_access_levels
ADD CONSTRAINT fk_f7dfda8c51 FOREIGN KEY (protected_tag_id) REFERENCES protected_tags(id) ON DELETE CASCADE;
 
Loading
Loading
Loading
Loading
@@ -4982,14 +4982,9 @@ input CreateDevopsAdoptionSegmentInput {
clientMutationId: String
 
"""
The array of group IDs to set for the segment.
Namespace ID to set for the segment.
"""
groupIds: [GroupID!]
"""
Name of the segment.
"""
name: String!
namespaceId: NamespaceID!
}
 
"""
Loading
Loading
@@ -8102,11 +8097,6 @@ type DetailedStatus {
Segment
"""
type DevopsAdoptionSegment {
"""
Assigned groups.
"""
groups: [Group!]
"""
ID of the segment.
"""
Loading
Loading
@@ -8118,9 +8108,9 @@ type DevopsAdoptionSegment {
latestSnapshot: DevopsAdoptionSnapshot
 
"""
Name of the segment.
Segment namespace.
"""
name: String!
namespace: Namespace
}
 
"""
Loading
Loading
@@ -16837,7 +16827,6 @@ type Mutation {
updateBoardList(input: UpdateBoardListInput!): UpdateBoardListPayload
updateComplianceFramework(input: UpdateComplianceFrameworkInput!): UpdateComplianceFrameworkPayload
updateContainerExpirationPolicy(input: UpdateContainerExpirationPolicyInput!): UpdateContainerExpirationPolicyPayload
updateDevopsAdoptionSegment(input: UpdateDevopsAdoptionSegmentInput!): UpdateDevopsAdoptionSegmentPayload
updateEpic(input: UpdateEpicInput!): UpdateEpicPayload
 
"""
Loading
Loading
@@ -26544,51 +26533,6 @@ type UpdateContainerExpirationPolicyPayload {
errors: [String!]!
}
 
"""
Autogenerated input type of UpdateDevopsAdoptionSegment
"""
input UpdateDevopsAdoptionSegmentInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
The array of group IDs to set for the segment.
"""
groupIds: [GroupID!]
"""
ID of the segment.
"""
id: AnalyticsDevopsAdoptionSegmentID!
"""
Name of the segment.
"""
name: String!
}
"""
Autogenerated return type of UpdateDevopsAdoptionSegment
"""
type UpdateDevopsAdoptionSegmentPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Errors encountered during execution of the mutation.
"""
errors: [String!]!
"""
The segment after mutation.
"""
segment: DevopsAdoptionSegment
}
input UpdateDiffImagePositionInput {
"""
Total height of the image.
Loading
Loading
Loading
Loading
@@ -13497,37 +13497,19 @@
"fields": null,
"inputFields": [
{
"name": "name",
"description": "Name of the segment.",
"name": "namespaceId",
"description": "Namespace ID to set for the segment.",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"name": "NamespaceID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "groupIds",
"description": "The array of group IDs to set for the segment.",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "GroupID",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
Loading
Loading
@@ -22122,28 +22104,6 @@
"name": "DevopsAdoptionSegment",
"description": "Segment",
"fields": [
{
"name": "groups",
"description": "Assigned groups.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Group",
"ofType": null
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
"description": "ID of the segment.",
Loading
Loading
@@ -22177,19 +22137,15 @@
"deprecationReason": null
},
{
"name": "name",
"description": "Name of the segment.",
"name": "namespace",
"description": "Segment namespace.",
"args": [
 
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
"kind": "OBJECT",
"name": "Namespace",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
Loading
Loading
@@ -49283,33 +49239,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updateDevopsAdoptionSegment",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "UpdateDevopsAdoptionSegmentInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "UpdateDevopsAdoptionSegmentPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updateEpic",
"description": null,
Loading
Loading
@@ -76566,140 +76495,6 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "UpdateDevopsAdoptionSegmentInput",
"description": "Autogenerated input type of UpdateDevopsAdoptionSegment",
"fields": null,
"inputFields": [
{
"name": "name",
"description": "Name of the segment.",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "groupIds",
"description": "The array of group IDs to set for the segment.",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "GroupID",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "id",
"description": "ID of the segment.",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "AnalyticsDevopsAdoptionSegmentID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "UpdateDevopsAdoptionSegmentPayload",
"description": "Autogenerated return type of UpdateDevopsAdoptionSegment",
"fields": [
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "errors",
"description": "Errors encountered during execution of the mutation.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "segment",
"description": "The segment after mutation.",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "DevopsAdoptionSegment",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "UpdateDiffImagePositionInput",
Loading
Loading
@@ -1335,10 +1335,9 @@ Segment.
 
| Field | Type | Description |
| ----- | ---- | ----------- |
| `groups` | Group! => Array | Assigned groups. |
| `id` | ID! | ID of the segment. |
| `latestSnapshot` | DevopsAdoptionSnapshot | The latest adoption metrics for the segment. |
| `name` | String! | Name of the segment. |
| `namespace` | Namespace | Segment namespace. |
 
### DevopsAdoptionSnapshot
 
Loading
Loading
@@ -3956,16 +3955,6 @@ Autogenerated return type of UpdateContainerExpirationPolicy.
| `containerExpirationPolicy` | ContainerExpirationPolicy | The container expiration policy after mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
 
### UpdateDevopsAdoptionSegmentPayload
Autogenerated return type of UpdateDevopsAdoptionSegment.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `segment` | DevopsAdoptionSegment | The segment after mutation. |
### UpdateEpicPayload
 
Autogenerated return type of UpdateEpic.
Loading
Loading
Loading
Loading
@@ -40,7 +40,7 @@ collected before this feature is available.
 
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/247112) in GitLab 13.7 as a [Beta feature](https://about.gitlab.com/handbook/product/gitlab-the-product/#beta).
 
The DevOps Adoption tab shows you which segments of your organization are using the most essential features of GitLab:
The DevOps Adoption tab shows you which groups within your organization are using the most essential features of GitLab:
 
- Issues
- Merge Requests
Loading
Loading
@@ -50,9 +50,7 @@ The DevOps Adoption tab shows you which segments of your organization are using
- Deploys
- Scanning
 
Segments are arbitrary collections of GitLab groups that you define. You might define a segment to represent a small team, a large department, or a whole organization.
You are limited to creating a maximum of 20 segments, and each segment is limited to a maximum of 20 groups.
Buttons to manage your segments appear in the DevOps Adoption section of the page.
Buttons to manage your groups appear in the DevOps Adoption section of the page.
 
DevOps Adoption allows you to:
 
Loading
Loading
@@ -60,7 +58,7 @@ DevOps Adoption allows you to:
- Identify specific groups that are lagging in their adoption of GitLab so you can help them along in their DevOps journey.
- Find the groups that have adopted certain features and can provide guidance to other groups on how to use those features.
 
![DevOps Report](img/dev_ops_adoption_v13_7.png)
![DevOps Report](img/dev_ops_adoption_v13_9.png)
 
### Disable or enable DevOps Adoption
 
Loading
Loading
doc/user/admin_area/analytics/img/dev_ops_adoption_v13_7.png

48 KiB

doc/user/admin_area/analytics/img/dev_ops_adoption_v13_9.png

157 KiB

Loading
Loading
@@ -43,6 +43,9 @@ export default {
displayError() {
return this.errors[0];
},
displayName() {
return this.segment.namespace?.fullName;
},
},
methods: {
async deleteSegment() {
Loading
Loading
@@ -100,7 +103,7 @@ export default {
</gl-alert>
<gl-sprintf :message="$options.i18n.confirmationMessage">
<template #name
><strong>{{ segment.name }}</strong></template
><strong>{{ displayName }}</strong></template
>
</gl-sprintf>
</gl-modal>
Loading
Loading
<script>
import { GlFormGroup, GlFormInput, GlFormRadioGroup, GlModal, GlAlert, GlIcon } from '@gitlab/ui';
import { getIdFromGraphQLId, convertToGraphQLId, TYPE_GROUP } from '~/graphql_shared/utils';
import { convertToGraphQLId, TYPE_GROUP } from '~/graphql_shared/utils';
import * as Sentry from '~/sentry/wrapper';
import { DEVOPS_ADOPTION_STRINGS, DEVOPS_ADOPTION_SEGMENT_MODAL_ID } from '../constants';
import createDevopsAdoptionSegmentMutation from '../graphql/mutations/create_devops_adoption_segment.mutation.graphql';
import updateDevopsAdoptionSegmentMutation from '../graphql/mutations/update_devops_adoption_segment.mutation.graphql';
import { DEVOPS_ADOPTION_STRINGS, DEVOPS_ADOPTION_SEGMENT_MODAL_ID } from '../constants';
import { addSegmentToCache } from '../utils/cache_updates';
 
export default {
Loading
Loading
@@ -18,11 +17,6 @@ export default {
GlIcon,
},
props: {
segment: {
type: Object,
required: false,
default: null,
},
groups: {
type: Array,
required: true,
Loading
Loading
@@ -31,8 +25,7 @@ export default {
i18n: DEVOPS_ADOPTION_STRINGS.modal,
data() {
return {
name: this.segment?.name || '',
selectedGroupId: this.segment ? this.groupIdFromSegment() : null,
selectedGroupId: null,
filter: '',
loading: false,
errors: [],
Loading
Loading
@@ -54,7 +47,7 @@ export default {
primaryOptions() {
return {
button: {
text: this.segment ? this.$options.i18n.editingButton : this.$options.i18n.addingButton,
text: this.$options.i18n.addingButton,
attributes: [
{
variant: 'info',
Loading
Loading
@@ -63,17 +56,17 @@ export default {
},
],
},
callback: this.segment ? this.updateSegment : this.createSegment,
callback: this.createSegment,
};
},
canSubmit() {
return this.name.length && Boolean(this.selectedGroupId);
return Boolean(this.selectedGroupId);
},
displayError() {
return this.errors[0];
},
modalTitle() {
return this.segment ? this.$options.i18n.editingTitle : this.$options.i18n.addingTitle;
return this.$options.i18n.addingTitle;
},
filteredOptions() {
return this.filter
Loading
Loading
@@ -94,8 +87,7 @@ export default {
} = await this.$apollo.mutate({
mutation: createDevopsAdoptionSegmentMutation,
variables: {
name: this.name,
groupIds: convertToGraphQLId(TYPE_GROUP, this.selectedGroupId),
namespaceId: convertToGraphQLId(TYPE_GROUP, this.selectedGroupId),
},
update: (store, { data }) => {
const {
Loading
Loading
@@ -119,46 +111,14 @@ export default {
this.loading = false;
}
},
async updateSegment() {
try {
this.loading = true;
const {
data: {
updateDevopsAdoptionSegment: { errors },
},
} = await this.$apollo.mutate({
mutation: updateDevopsAdoptionSegmentMutation,
variables: {
id: this.segment.id,
name: this.name,
groupIds: convertToGraphQLId(TYPE_GROUP, this.selectedGroupId),
},
});
if (errors.length) {
this.errors = errors;
} else {
this.closeModal();
}
} catch (error) {
this.errors.push(this.$options.i18n.error);
Sentry.captureException(error);
} finally {
this.loading = false;
}
},
clearErrors() {
this.errors = [];
},
closeModal() {
this.$refs.modal.hide();
},
groupIdFromSegment() {
return this.segment.groups.map(({ id }) => getIdFromGraphQLId(id))[0];
},
resetForm() {
this.name = this.segment?.name || '';
this.selectedGroupId = this.segment ? this.groupIdFromSegment() : null;
this.selectedGroupId = null;
this.filter = '';
},
},
Loading
Loading
@@ -181,17 +141,6 @@ export default {
<gl-alert v-if="errors.length" variant="danger" class="gl-mb-3" @dismiss="clearErrors">
{{ displayError }}
</gl-alert>
<gl-form-group :label="$options.i18n.nameLabel" label-for="name">
<gl-form-input
id="name"
v-model="name"
data-testid="name"
type="text"
:placeholder="$options.i18n.namePlaceholder"
required
:disabled="loading"
/>
</gl-form-group>
<gl-form-group class="gl-mb-3" data-testid="filter">
<gl-icon name="search" :size="18" class="gl-text-gray-300 gl-absolute gl-mt-3 gl-ml-3" />
<gl-form-input
Loading
Loading
<script>
import {
GlTable,
GlButton,
GlPopover,
GlModalDirective,
GlTooltipDirective,
GlIcon,
} from '@gitlab/ui';
import { GlTable, GlButton, GlModalDirective, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import {
DEVOPS_ADOPTION_TABLE_TEST_IDS,
Loading
Loading
@@ -23,7 +16,7 @@ const NAME_HEADER = 'name';
 
const formatter = (value, key, item) => {
if (key === NAME_HEADER) {
return value;
return item.namespace?.fullName;
}
 
if (item.latestSnapshot && item.latestSnapshot[key] === false) {
Loading
Loading
@@ -62,7 +55,6 @@ export default {
GlTable,
DevopsAdoptionTableCellFlag,
GlButton,
GlPopover,
LocalStorageSync,
DevopsAdoptionDeleteModal,
GlIcon,
Loading
Loading
@@ -104,12 +96,6 @@ export default {
};
},
methods: {
popoverContainerId(name) {
return `popover_container_id_for_${name}`;
},
popoverId(name) {
return `popover_id_for_${name}`;
},
setSelectedSegment(segment) {
this.$emit('set-selected-segment', segment);
},
Loading
Loading
@@ -154,11 +140,18 @@ export default {
</div>
</template>
 
<template #cell(name)="{ item }">
<template
#cell(name)="{
item: {
namespace: { fullName },
latestSnapshot,
},
}"
>
<div :data-testid="$options.testids.SEGMENT">
<strong v-if="item.latestSnapshot">{{ item.name }}</strong>
<strong v-if="latestSnapshot">{{ fullName }}</strong>
<template v-else>
<span class="gl-text-gray-400">{{ item.name }}</span>
<span class="gl-text-gray-400">{{ fullName }}</span>
<gl-icon name="hourglass" class="gl-text-gray-400" />
</template>
</div>
Loading
Loading
@@ -222,32 +215,13 @@ export default {
 
<template #cell(actions)="{ item }">
<div :data-testid="$options.testids.ACTIONS">
<gl-button :id="popoverId(item.name)" category="tertiary" icon="ellipsis_h" />
<div :id="popoverContainerId(item.name)">
<gl-popover
:target="popoverId(item.name)"
:container="popoverContainerId(item.name)"
triggers="hover focus"
placement="left"
>
<div class="gl-display-inline-flex gl-flex-direction-column">
<gl-button
v-gl-modal="$options.devopsSegmentModalId"
category="tertiary"
class="gl-w-max-content"
@click="setSelectedSegment(item)"
>{{ $options.i18n.editButton }}</gl-button
>
<gl-button
v-gl-modal="$options.devopsSegmentDeleteModalId"
category="tertiary"
variant="danger"
@click="setSelectedSegment(item)"
>{{ $options.i18n.deleteButton }}</gl-button
>
</div>
</gl-popover>
</div>
<gl-button
v-gl-modal="$options.devopsSegmentDeleteModalId"
v-gl-tooltip.hover="$options.i18n.removeButton"
category="tertiary"
icon="remove"
@click="setSelectedSegment(item)"
/>
</div>
</template>
</gl-table>
Loading
Loading
Loading
Loading
@@ -42,21 +42,18 @@ export const DEVOPS_ADOPTION_STRINGS = {
},
modal: {
addingTitle: s__('DevopsAdoption|Add Group'),
editingTitle: s__('DevopsAdoption|Edit Group'),
addingButton: s__('DevopsAdoption|Add Group'),
editingButton: s__('DevopsAdoption|Save changes'),
cancel: __('Cancel'),
namePlaceholder: s__('DevopsAdoption|My group'),
filterPlaceholder: s__('DevopsAdoption|Filter by name'),
nameLabel: s__('DevopsAdoption|Name'),
selectedGroupsTextSingular: s__('DevopsAdoption|%{selectedCount} group selected'),
selectedGroupsTextPlural: s__('DevopsAdoption|%{selectedCount} groups selected'),
error: s__('DevopsAdoption|An error occured while saving the group. Please try again.'),
noResults: s__('DevopsAdoption|No filter results.'),
},
table: {
editButton: s__('DevopsAdoption|Edit Group'),
deleteButton: s__('DevopsAdoption|Delete Group'),
removeButton: s__('DevopsAdoption|Remove Group from the table'),
headers: {
name: {
label: __('Group'),
Loading
Loading
@@ -92,11 +89,13 @@ export const DEVOPS_ADOPTION_STRINGS = {
},
},
deleteModal: {
title: s__('DevopsAdoption|Confirm delete Group'),
confirmationMessage: s__('DevopsAdoption|Are you sure that you would like to delete %{name}?'),
title: s__('DevopsAdoption|Confirm remove Group'),
confirmationMessage: s__(
'DevopsAdoption|Are you sure that you would like to remove %{name} from the table?',
),
cancel: __('Cancel'),
confirm: s__('DevopsAdoption|Delete Group'),
error: s__('DevopsAdoption|An error occured while deleting the group. Please try again.'),
confirm: s__('DevopsAdoption|Remove Group'),
error: s__('DevopsAdoption|An error occured while removing the group. Please try again.'),
},
tableCell: {
trueText: s__('DevopsAdoption|Adopted'),
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment