Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
15dbf53ff6
commit
2b0f233d35
|
|
@ -1013,6 +1013,11 @@ QA/SelectorUsage:
|
|||
Exclude:
|
||||
- 'spec/rubocop/**/*_spec.rb'
|
||||
|
||||
QA/FeatureFlags:
|
||||
Enabled: true
|
||||
Include:
|
||||
- 'qa/qa/specs/features/**/*.rb'
|
||||
|
||||
Performance/ActiveRecordSubtransactions:
|
||||
Exclude:
|
||||
- 'spec/**/*.rb'
|
||||
|
|
|
|||
|
|
@ -154,19 +154,6 @@ Layout/ArgumentAlignment:
|
|||
- 'ee/app/services/external_status_checks/create_service.rb'
|
||||
- 'ee/app/services/external_status_checks/destroy_service.rb'
|
||||
- 'ee/app/services/external_status_checks/update_service.rb'
|
||||
- 'lib/api/admin/plan_limits.rb'
|
||||
- 'lib/api/alert_management_alerts.rb'
|
||||
- 'lib/api/api.rb'
|
||||
- 'lib/api/applications.rb'
|
||||
- 'lib/api/branches.rb'
|
||||
- 'lib/api/bulk_imports.rb'
|
||||
- 'lib/api/ci/job_artifacts.rb'
|
||||
- 'lib/api/ci/jobs.rb'
|
||||
- 'lib/api/ci/pipeline_schedules.rb'
|
||||
- 'lib/api/ci/pipelines.rb'
|
||||
- 'lib/api/ci/resource_groups.rb'
|
||||
- 'lib/api/ci/runner.rb'
|
||||
- 'lib/api/ci/runners.rb'
|
||||
- 'lib/api/entities/npm_package.rb'
|
||||
- 'lib/api/entities/nuget/dependency_group.rb'
|
||||
- 'lib/api/entities/nuget/package_metadata.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
55197564f4f57d8049d351f5c4614bc9449c2a72
|
||||
fb36b2bea3817c3fd4f58804699e6e6830a0e578
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ export default {
|
|||
label-position="left"
|
||||
aria-describedby="board-labels-toggle-text"
|
||||
data-testid="show-labels-toggle"
|
||||
class="gl-flex-direction-row gl-justify-between gl-w-full"
|
||||
class="board-dropdown-toggle gl-flex-direction-row gl-justify-between gl-w-full"
|
||||
/>
|
||||
</template>
|
||||
</gl-disclosure-dropdown-item>
|
||||
|
|
|
|||
|
|
@ -7,8 +7,20 @@ import isShowingLabelsQuery from '~/graphql_shared/client/is_showing_labels.quer
|
|||
import getIssueStateQuery from '~/issues/show/queries/get_issue_state.query.graphql';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import typeDefs from '~/work_items/graphql/typedefs.graphql';
|
||||
import { WIDGET_TYPE_NOTES, WIDGET_TYPE_AWARD_EMOJI } from '~/work_items/constants';
|
||||
import { findWidget } from '~/issues/list/utils';
|
||||
import { newWorkItemFullPath } from '~/work_items/utils';
|
||||
import {
|
||||
WIDGET_TYPE_NOTES,
|
||||
WIDGET_TYPE_AWARD_EMOJI,
|
||||
NEW_WORK_ITEM_IID,
|
||||
WIDGET_TYPE_HEALTH_STATUS,
|
||||
WIDGET_TYPE_ASSIGNEES,
|
||||
WIDGET_TYPE_COLOR,
|
||||
WIDGET_TYPE_DESCRIPTION,
|
||||
} from '~/work_items/constants';
|
||||
import activeBoardItemQuery from 'ee_else_ce/boards/graphql/client/active_board_item.query.graphql';
|
||||
import groupWorkItemByIidQuery from '~/work_items//graphql/group_work_item_by_iid.query.graphql';
|
||||
import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
|
||||
|
||||
export const config = {
|
||||
typeDefs,
|
||||
|
|
@ -272,6 +284,85 @@ export const resolvers = {
|
|||
});
|
||||
return isShowingLabels;
|
||||
},
|
||||
updateNewWorkItem(_, { input }, { cache }) {
|
||||
const {
|
||||
healthStatus,
|
||||
isGroup,
|
||||
fullPath,
|
||||
assignees,
|
||||
color,
|
||||
title,
|
||||
description,
|
||||
confidential,
|
||||
} = input;
|
||||
const query = isGroup ? groupWorkItemByIidQuery : workItemByIidQuery;
|
||||
|
||||
const variables = {
|
||||
fullPath: newWorkItemFullPath(fullPath),
|
||||
iid: NEW_WORK_ITEM_IID,
|
||||
};
|
||||
cache.updateQuery({ query, variables }, (sourceData) =>
|
||||
produce(sourceData, (draftData) => {
|
||||
if (healthStatus) {
|
||||
const healthStatusWidget = findWidget(
|
||||
WIDGET_TYPE_HEALTH_STATUS,
|
||||
draftData?.workspace?.workItem,
|
||||
);
|
||||
|
||||
healthStatusWidget.healthStatus = healthStatus;
|
||||
|
||||
const healthStatusWidgetIndex = draftData.workspace.workItem.widgets.findIndex(
|
||||
(widget) => widget.type === WIDGET_TYPE_HEALTH_STATUS,
|
||||
);
|
||||
draftData.workspace.workItem.widgets[healthStatusWidgetIndex] = healthStatusWidget;
|
||||
}
|
||||
|
||||
if (assignees) {
|
||||
const assigneesWidget = findWidget(
|
||||
WIDGET_TYPE_ASSIGNEES,
|
||||
draftData?.workspace?.workItem,
|
||||
);
|
||||
assigneesWidget.assignees.nodes = assignees;
|
||||
|
||||
const assigneesWidgetIndex = draftData.workspace.workItem.widgets.findIndex(
|
||||
(widget) => widget.type === WIDGET_TYPE_ASSIGNEES,
|
||||
);
|
||||
draftData.workspace.workItem.widgets[assigneesWidgetIndex] = assigneesWidget;
|
||||
}
|
||||
|
||||
if (color) {
|
||||
const colorWidget = findWidget(WIDGET_TYPE_COLOR, draftData?.workspace?.workItem);
|
||||
colorWidget.color = color;
|
||||
|
||||
const colorWidgetIndex = draftData.workspace.workItem.widgets.findIndex(
|
||||
(widget) => widget.type === WIDGET_TYPE_COLOR,
|
||||
);
|
||||
draftData.workspace.workItem.widgets[colorWidgetIndex] = colorWidget;
|
||||
}
|
||||
|
||||
if (title) {
|
||||
draftData.workspace.workItem.title = title;
|
||||
}
|
||||
|
||||
if (description) {
|
||||
const descriptionWidget = findWidget(
|
||||
WIDGET_TYPE_DESCRIPTION,
|
||||
draftData?.workspace?.workItem,
|
||||
);
|
||||
descriptionWidget.description = description;
|
||||
|
||||
const descriptionWidgetIndex = draftData.workspace.workItem.widgets.findIndex(
|
||||
(widget) => widget.type === WIDGET_TYPE_DESCRIPTION,
|
||||
);
|
||||
draftData.workspace.workItem.widgets[descriptionWidgetIndex] = descriptionWidget;
|
||||
}
|
||||
|
||||
if (confidential !== undefined) {
|
||||
draftData.workspace.workItem.confidential = confidential;
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ const CrmOrganizationToken = () =>
|
|||
const DateToken = () => import('~/vue_shared/components/filtered_search_bar/tokens/date_token.vue');
|
||||
|
||||
export default {
|
||||
name: 'IssuesListAppCE',
|
||||
i18n,
|
||||
issuableListTabs,
|
||||
ISSUES_VIEW_TYPE_KEY,
|
||||
|
|
|
|||
|
|
@ -2,12 +2,24 @@ import Vue from 'vue';
|
|||
import VueApollo from 'vue-apollo';
|
||||
import VueRouter from 'vue-router';
|
||||
import IssuesListApp from 'ee_else_ce/issues/list/components/issues_list_app.vue';
|
||||
import { resolvers, config } from '~/graphql_shared/issuable_client';
|
||||
import createDefaultClient, { createApolloClientWithCaching } from '~/lib/graphql';
|
||||
import { addShortcutsExtension } from '~/behaviors/shortcuts';
|
||||
import ShortcutsWorkItems from '~/behaviors/shortcuts/shortcuts_work_items';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import JiraIssuesImportStatusApp from './components/jira_issues_import_status_app.vue';
|
||||
import { gqlClient } from './graphql';
|
||||
|
||||
let issuesClient;
|
||||
|
||||
export async function issuesListClient() {
|
||||
if (issuesClient) return issuesClient;
|
||||
issuesClient = gon.features?.frontendCaching
|
||||
? await createApolloClientWithCaching(resolvers, { localCacheKey: 'issues_list', ...config })
|
||||
: createDefaultClient(resolvers, config);
|
||||
return issuesClient;
|
||||
}
|
||||
|
||||
export async function mountJiraIssuesListApp() {
|
||||
const el = document.querySelector('.js-jira-issues-import-status-root');
|
||||
|
||||
|
|
@ -109,7 +121,7 @@ export async function mountIssuesListApp() {
|
|||
el,
|
||||
name: 'IssuesListRoot',
|
||||
apolloProvider: new VueApollo({
|
||||
defaultClient: await gqlClient(),
|
||||
defaultClient: await issuesListClient(),
|
||||
}),
|
||||
router: new VueRouter({
|
||||
base: window.location.pathname,
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ export const convertToSearchQuery = (filterTokens) =>
|
|||
.map((token) => token.value.data)
|
||||
.join(' ') || undefined;
|
||||
|
||||
function findWidget(type, workItem) {
|
||||
export function findWidget(type, workItem) {
|
||||
return workItem?.widgets?.find((widget) => widget.type === type);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export default {
|
|||
<template #list-item="{ item }">
|
||||
<div
|
||||
class="gl-line-clamp-2"
|
||||
:class="{ 'gl-font-weight-bold': item.memberRoleId }"
|
||||
:class="{ 'gl-font-bold': item.memberRoleId }"
|
||||
data-testid="role-name"
|
||||
>
|
||||
{{ item.text }}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export const GLOBAL_COMMANDS_GROUP_TITLE = s__('CommandPalette|Global Commands')
|
|||
export const USERS_GROUP_TITLE = s__('GlobalSearch|Users');
|
||||
export const PAGES_GROUP_TITLE = s__('CommandPalette|Pages');
|
||||
export const PROJECTS_GROUP_TITLE = s__('GlobalSearch|Projects');
|
||||
export const GROUPS_GROUP_TITLE = s__('GlobalSearch|Groups');
|
||||
export const ISSUES_GROUP_TITLE = s__('GlobalSearch|Issues');
|
||||
export const PATH_GROUP_TITLE = s__('CommandPalette|Project files');
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {
|
|||
PROJECTS_GROUP_TITLE,
|
||||
ISSUES_GROUP_TITLE,
|
||||
PAGES_GROUP_TITLE,
|
||||
GROUPS_GROUP_TITLE,
|
||||
} from '../command_palette/constants';
|
||||
import SearchResultHoverLayover from './global_search_hover_overlay.vue';
|
||||
import GlobalSearchNoResults from './global_search_no_results.vue';
|
||||
|
|
@ -38,6 +39,7 @@ export default {
|
|||
PROJECTS_GROUP_TITLE,
|
||||
ISSUES_GROUP_TITLE,
|
||||
PAGES_GROUP_TITLE,
|
||||
GROUPS_GROUP_TITLE,
|
||||
},
|
||||
components: {
|
||||
GlAvatar,
|
||||
|
|
@ -103,13 +105,18 @@ export default {
|
|||
},
|
||||
trackingTypes({ category }) {
|
||||
switch (category) {
|
||||
case this.$options.i18n.GROUPS_GROUP_TITLE: {
|
||||
this.trackEvent('click_group_result_in_command_palette');
|
||||
break;
|
||||
}
|
||||
|
||||
case this.$options.i18n.PROJECTS_GROUP_TITLE: {
|
||||
this.trackEvent('click_project_result_in_command_palette');
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
this.trackEvent('click_user_result_in_command_palette');
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export default {
|
|||
editStatus: s__('SetStatusModal|Edit status'),
|
||||
editProfile: s__('CurrentUser|Edit profile'),
|
||||
preferences: s__('CurrentUser|Preferences'),
|
||||
buyPipelineMinutes: s__('CurrentUser|Buy Pipeline minutes'),
|
||||
buyPipelineMinutes: s__('CurrentUser|Buy compute minutes'),
|
||||
oneOfGroupsRunningOutOfPipelineMinutes: s__('CurrentUser|One of your groups is running out'),
|
||||
gitlabNext: s__('CurrentUser|Switch to GitLab Next'),
|
||||
startTrial: s__('CurrentUser|Start an Ultimate trial'),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import Vue from 'vue';
|
|||
import { GlBreadcrumb, GlToast } from '@gitlab/ui';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import { apolloProvider } from '~/graphql_shared/issuable_client';
|
||||
import { staticBreadcrumbs } from '~/lib/utils/breadcrumbs';
|
||||
import { JS_TOGGLE_EXPAND_CLASS, CONTEXT_NAMESPACE_GROUPS } from './constants';
|
||||
import createStore from './components/global_search/store';
|
||||
|
|
@ -16,10 +16,6 @@ import SuperSidebarToggle from './components/super_sidebar_toggle.vue';
|
|||
Vue.use(GlToast);
|
||||
Vue.use(VueApollo);
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(),
|
||||
});
|
||||
|
||||
const getTrialStatusWidgetData = (sidebarData) => {
|
||||
if (sidebarData.trial_status_widget_data_attrs && sidebarData.trial_status_popover_data_attrs) {
|
||||
const {
|
||||
|
|
@ -135,6 +131,7 @@ export const initSuperSidebar = () => {
|
|||
projectsPath,
|
||||
groupsPath,
|
||||
fullPath: sidebarData.work_items?.full_path,
|
||||
hasIssuableHealthStatusFeature: sidebarData.work_items?.has_issuable_health_status_feature,
|
||||
isGroup,
|
||||
},
|
||||
store: createStore({
|
||||
|
|
|
|||
|
|
@ -7,24 +7,39 @@ import {
|
|||
GlFormGroup,
|
||||
GlFormSelect,
|
||||
} from '@gitlab/ui';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { TYPENAME_PROJECT } from '~/graphql_shared/constants';
|
||||
import { getPreferredLocales, s__ } from '~/locale';
|
||||
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
|
||||
import { fetchPolicies } from '~/lib/graphql';
|
||||
import { setNewWorkItemCache } from '~/work_items/graphql/cache_utils';
|
||||
import { findWidget } from '~/issues/list/utils';
|
||||
import { newWorkItemFullPath } from '~/work_items/utils';
|
||||
import {
|
||||
I18N_WORK_ITEM_CREATE_BUTTON_LABEL,
|
||||
I18N_WORK_ITEM_ERROR_CREATING,
|
||||
I18N_WORK_ITEM_ERROR_FETCHING_TYPES,
|
||||
sprintfWorkItem,
|
||||
i18n,
|
||||
WIDGET_TYPE_ASSIGNEES,
|
||||
WIDGET_TYPE_COLOR,
|
||||
NEW_WORK_ITEM_IID,
|
||||
WIDGET_TYPE_HEALTH_STATUS,
|
||||
WIDGET_TYPE_PARTICIPANTS,
|
||||
WIDGET_TYPE_DESCRIPTION,
|
||||
NEW_WORK_ITEM_GID,
|
||||
} from '../constants';
|
||||
import createWorkItemMutation from '../graphql/create_work_item.mutation.graphql';
|
||||
import groupWorkItemTypesQuery from '../graphql/group_work_item_types.query.graphql';
|
||||
import projectWorkItemTypesQuery from '../graphql/project_work_item_types.query.graphql';
|
||||
import groupWorkItemByIidQuery from '../graphql/group_work_item_by_iid.query.graphql';
|
||||
import workItemByIidQuery from '../graphql/work_item_by_iid.query.graphql';
|
||||
import updateNewWorkItemMutation from '../graphql/update_new_work_item.mutation.graphql';
|
||||
|
||||
import WorkItemTitle from './work_item_title.vue';
|
||||
import WorkItemAttributesWrapper from './work_item_attributes_wrapper.vue';
|
||||
import WorkItemDescription from './work_item_description.vue';
|
||||
import WorkItemAssignees from './work_item_assignees.vue';
|
||||
import WorkItemLoading from './work_item_loading.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -34,17 +49,16 @@ export default {
|
|||
GlFormGroup,
|
||||
GlFormCheckbox,
|
||||
GlFormSelect,
|
||||
WorkItemAttributesWrapper,
|
||||
WorkItemDescription,
|
||||
WorkItemTitle,
|
||||
WorkItemAssignees,
|
||||
WorkItemLoading,
|
||||
WorkItemHealthStatus: () =>
|
||||
import('ee_component/work_items/components/work_item_health_status.vue'),
|
||||
WorkItemColor: () => import('ee_component/work_items/components/work_item_color.vue'),
|
||||
},
|
||||
inject: ['fullPath', 'isGroup'],
|
||||
props: {
|
||||
initialTitle: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
workItemTypeName: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
|
@ -58,10 +72,6 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
draft: {
|
||||
title: this.initialTitle,
|
||||
description: '',
|
||||
},
|
||||
isTitleValid: true,
|
||||
isConfidential: false,
|
||||
error: null,
|
||||
|
|
@ -69,13 +79,37 @@ export default {
|
|||
selectedWorkItemTypeId: null,
|
||||
loading: false,
|
||||
showWorkItemTypeSelect: false,
|
||||
newWorkItemPath: newWorkItemFullPath(this.fullPath),
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
workItem: {
|
||||
query() {
|
||||
return this.isGroup ? groupWorkItemByIidQuery : workItemByIidQuery;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.newWorkItemPath,
|
||||
iid: NEW_WORK_ITEM_IID,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return !this.fullPath;
|
||||
},
|
||||
update(data) {
|
||||
return data?.workspace?.workItem ?? {};
|
||||
},
|
||||
error() {
|
||||
this.error = i18n.fetchError;
|
||||
},
|
||||
},
|
||||
workItemTypes: {
|
||||
query() {
|
||||
return this.isGroup ? groupWorkItemTypesQuery : projectWorkItemTypesQuery;
|
||||
},
|
||||
fetchPolicy() {
|
||||
return this.workItemTypeName ? fetchPolicies.CACHE_ONLY : fetchPolicies.CACHE_FIRST;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.fullPath,
|
||||
|
|
@ -86,7 +120,10 @@ export default {
|
|||
return data.workspace?.workItemTypes?.nodes;
|
||||
},
|
||||
result() {
|
||||
if (this.workItemTypes.length === 1) {
|
||||
if (!this.workItemTypes?.length) {
|
||||
return;
|
||||
}
|
||||
if (this.workItemTypes?.length === 1) {
|
||||
this.selectedWorkItemTypeId = this.workItemTypes[0].id;
|
||||
} else {
|
||||
this.showWorkItemTypeSelect = true;
|
||||
|
|
@ -98,17 +135,31 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
isLoading() {
|
||||
return this.$apollo.queries.workItemTypes.loading || this.$apollo.queries.workItem.loading;
|
||||
},
|
||||
hasWidgets() {
|
||||
return this.draft.widgets?.length > 0;
|
||||
return this.workItem?.widgets?.length > 0;
|
||||
},
|
||||
workItemAssignees() {
|
||||
return findWidget(WIDGET_TYPE_ASSIGNEES, this.workItem);
|
||||
},
|
||||
workItemHealthStatus() {
|
||||
return findWidget(WIDGET_TYPE_HEALTH_STATUS, this.workItem);
|
||||
},
|
||||
workItemColor() {
|
||||
return findWidget(WIDGET_TYPE_COLOR, this.workItem);
|
||||
},
|
||||
workItemTypesForSelect() {
|
||||
return this.workItemTypes.map((node) => ({
|
||||
value: node.id,
|
||||
text: capitalizeFirstCharacter(node.name.toLocaleLowerCase(getPreferredLocales()[0])),
|
||||
}));
|
||||
return this.workItemTypes
|
||||
? this.workItemTypes.map((node) => ({
|
||||
value: node.id,
|
||||
text: capitalizeFirstCharacter(node.name.toLocaleLowerCase(getPreferredLocales()[0])),
|
||||
}))
|
||||
: [];
|
||||
},
|
||||
selectedWorkItemType() {
|
||||
return this.workItemTypes.find((item) => item.id === this.selectedWorkItemTypeId);
|
||||
return this.workItemTypes?.find((item) => item.id === this.selectedWorkItemTypeId);
|
||||
},
|
||||
formOptions() {
|
||||
return [{ value: null, text: s__('WorkItem|Select type') }, ...this.workItemTypesForSelect];
|
||||
|
|
@ -129,24 +180,84 @@ export default {
|
|||
this.selectedWorkItemType?.name,
|
||||
);
|
||||
},
|
||||
|
||||
titleText() {
|
||||
return sprintfWorkItem(s__('WorkItem|New %{workItemType}'), this.selectedWorkItemType?.name);
|
||||
},
|
||||
canUpdate() {
|
||||
return this.workItem?.userPermissions?.updateWorkItem;
|
||||
},
|
||||
workItemType() {
|
||||
return this.workItem?.workItemType?.name;
|
||||
},
|
||||
workItemParticipantNodes() {
|
||||
return this.workItemParticipants?.participants?.nodes ?? [];
|
||||
},
|
||||
workItemParticipants() {
|
||||
return findWidget(WIDGET_TYPE_PARTICIPANTS, this.workItem);
|
||||
},
|
||||
workItemAssigneeIds() {
|
||||
const assigneesWidget = findWidget(WIDGET_TYPE_ASSIGNEES, this.workItem);
|
||||
return assigneesWidget?.assignees?.nodes?.map((assignee) => assignee.id) || [];
|
||||
},
|
||||
workItemColorValue() {
|
||||
const colorWidget = findWidget(WIDGET_TYPE_COLOR, this.workItem);
|
||||
return colorWidget?.color || '';
|
||||
},
|
||||
workItemHealthStatusValue() {
|
||||
const healthStatusWidget = findWidget(WIDGET_TYPE_HEALTH_STATUS, this.workItem);
|
||||
return healthStatusWidget?.healthStatus || null;
|
||||
},
|
||||
workItemAuthor() {
|
||||
return this.workItem?.author;
|
||||
},
|
||||
workItemTitle() {
|
||||
return this.workItem?.title || '';
|
||||
},
|
||||
workItemDescription() {
|
||||
const descriptionWidget = findWidget(WIDGET_TYPE_DESCRIPTION, this.workItem);
|
||||
return descriptionWidget?.description;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
validate() {
|
||||
this.isTitleValid = Boolean(this.draft.title.trim());
|
||||
isWidgetSupported(widgetType) {
|
||||
const widgetDefinitions =
|
||||
this.selectedWorkItemType?.widgetDefinitions?.flatMap((i) => i.type) || [];
|
||||
return widgetDefinitions.indexOf(widgetType) !== -1;
|
||||
},
|
||||
updateDraftData(type, value) {
|
||||
this.draft = {
|
||||
...this.draft,
|
||||
[type]: value,
|
||||
};
|
||||
this.$emit(`updateDraft`, { type, value });
|
||||
|
||||
validate(newValue) {
|
||||
const title = newValue || this.workItemTitle;
|
||||
this.isTitleValid = Boolean(title.trim());
|
||||
},
|
||||
updateCache() {
|
||||
if (!this.selectedWorkItemTypeId) {
|
||||
return;
|
||||
}
|
||||
setNewWorkItemCache(
|
||||
this.isGroup,
|
||||
this.fullPath,
|
||||
this.selectedWorkItemType?.widgetDefinitions,
|
||||
this.workItemType,
|
||||
);
|
||||
},
|
||||
async updateDraftData(type, value) {
|
||||
if (type === 'title') {
|
||||
this.validate();
|
||||
this.validate(value);
|
||||
}
|
||||
|
||||
try {
|
||||
this.$apollo.mutate({
|
||||
mutation: updateNewWorkItemMutation,
|
||||
variables: {
|
||||
input: {
|
||||
isGroup: this.isGroup,
|
||||
fullPath: this.fullPath,
|
||||
[type]: value,
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
this.error = this.createErrorText;
|
||||
Sentry.captureException(this.error);
|
||||
}
|
||||
},
|
||||
async createWorkItem() {
|
||||
|
|
@ -158,18 +269,42 @@ export default {
|
|||
|
||||
this.loading = true;
|
||||
|
||||
const workItemCreateInput = {
|
||||
title: this.workItemTitle,
|
||||
workItemTypeId: this.selectedWorkItemTypeId,
|
||||
namespacePath: this.fullPath,
|
||||
confidential: this.workItem.confidential,
|
||||
descriptionWidget: {
|
||||
description: this.workItemDescription || '',
|
||||
},
|
||||
};
|
||||
|
||||
// TODO , we can move this to util, currently objectives with other widgets not being supported is causing issues
|
||||
|
||||
if (this.isWidgetSupported(WIDGET_TYPE_COLOR)) {
|
||||
workItemCreateInput.colorWidget = {
|
||||
color: this.workItemColorValue,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.isWidgetSupported(WIDGET_TYPE_ASSIGNEES)) {
|
||||
workItemCreateInput.assigneesWidget = {
|
||||
assigneeIds: this.workItemAssigneeIds,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.isWidgetSupported(WIDGET_TYPE_HEALTH_STATUS)) {
|
||||
workItemCreateInput.healthStatusWidget = {
|
||||
healthStatus: this.workItemHealthStatusValue,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.$apollo.mutate({
|
||||
mutation: createWorkItemMutation,
|
||||
variables: {
|
||||
input: {
|
||||
title: this.draft.title,
|
||||
workItemTypeId: this.selectedWorkItemTypeId,
|
||||
namespacePath: this.fullPath,
|
||||
confidential: this.draft.confidential,
|
||||
descriptionWidget: {
|
||||
description: this.draft.description,
|
||||
},
|
||||
...workItemCreateInput,
|
||||
},
|
||||
},
|
||||
update: (store, { data: { workItemCreate } }) => {
|
||||
|
|
@ -205,91 +340,127 @@ export default {
|
|||
this.$emit('cancel');
|
||||
},
|
||||
},
|
||||
NEW_WORK_ITEM_IID,
|
||||
NEW_WORK_ITEM_GID,
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form @submit.prevent="createWorkItem">
|
||||
<gl-alert v-if="error" variant="danger" @dismiss="error = null">{{ error }}</gl-alert>
|
||||
<h1 v-if="!hideFormTitle" class="page-title gl-text-xl gl-pb-5">{{ titleText }}</h1>
|
||||
<div class="gl-mb-5">
|
||||
<gl-loading-icon
|
||||
v-if="$apollo.queries.workItemTypes.loading"
|
||||
size="lg"
|
||||
data-testid="loading-types"
|
||||
/>
|
||||
<gl-form-group
|
||||
v-else-if="showWorkItemTypeSelect"
|
||||
:label="__('Type')"
|
||||
label-for="work-item-type"
|
||||
>
|
||||
<gl-form-select
|
||||
id="work-item-type"
|
||||
v-model="selectedWorkItemTypeId"
|
||||
:options="formOptions"
|
||||
class="gl-max-w-26"
|
||||
<work-item-loading v-if="isLoading" />
|
||||
<template v-else>
|
||||
<gl-alert v-if="error" variant="danger" @dismiss="error = null">{{ error }}</gl-alert>
|
||||
<h1 v-if="!hideFormTitle" class="page-title gl-text-xl gl-pb-5">{{ titleText }}</h1>
|
||||
<div class="gl-mb-5">
|
||||
<gl-loading-icon
|
||||
v-if="$apollo.queries.workItemTypes.loading"
|
||||
size="lg"
|
||||
data-testid="loading-types"
|
||||
/>
|
||||
</gl-form-group>
|
||||
</div>
|
||||
<work-item-title
|
||||
ref="title"
|
||||
data-testid="title-input"
|
||||
is-editing
|
||||
:is-valid="isTitleValid"
|
||||
:title="draft.title"
|
||||
@updateDraft="updateDraftData('title', $event)"
|
||||
@updateWorkItem="createWorkItem"
|
||||
/>
|
||||
<div data-testid="work-item-overview" class="work-item-overview">
|
||||
<section>
|
||||
<work-item-description
|
||||
edit-mode
|
||||
disable-inline-editing
|
||||
:autofocus="false"
|
||||
:full-path="fullPath"
|
||||
:show-buttons-below-field="false"
|
||||
@error="updateError = $event"
|
||||
@updateDraft="updateDraftData('description', $event)"
|
||||
/>
|
||||
<gl-form-group :label="__('Confidentiality')" label-for="work-item-confidential">
|
||||
<gl-form-checkbox
|
||||
id="work-item-confidential"
|
||||
v-model="isConfidential"
|
||||
data-testid="confidential-checkbox"
|
||||
@change="updateDraftData('confidential', $event)"
|
||||
>
|
||||
{{ makeConfidentialText }}
|
||||
</gl-form-checkbox>
|
||||
</gl-form-group>
|
||||
</section>
|
||||
<aside
|
||||
v-if="hasWidgets"
|
||||
data-testid="work-item-overview-right-sidebar"
|
||||
class="work-item-overview-right-sidebar gl-block"
|
||||
:class="{ 'is-modal': true }"
|
||||
>
|
||||
<work-item-attributes-wrapper
|
||||
is-create-view
|
||||
:full-path="fullPath"
|
||||
:work-item="draft"
|
||||
@error="updateError = $event"
|
||||
@updateWorkItem="updateDraftData"
|
||||
@updateWorkItemAttribute="updateDraftData"
|
||||
/>
|
||||
</aside>
|
||||
<div class="gl-py-3 gl-flex gl-gap-3 gl-col-start-1">
|
||||
<gl-button
|
||||
variant="confirm"
|
||||
:loading="loading"
|
||||
data-testid="create-button"
|
||||
@click="createWorkItem"
|
||||
<gl-form-group
|
||||
v-else-if="showWorkItemTypeSelect"
|
||||
:label="__('Type')"
|
||||
label-for="work-item-type"
|
||||
>
|
||||
{{ createWorkItemText }}
|
||||
</gl-button>
|
||||
<gl-button type="button" data-testid="cancel-button" @click="handleCancelClick">
|
||||
{{ __('Cancel') }}
|
||||
</gl-button>
|
||||
<gl-form-select
|
||||
id="work-item-type"
|
||||
v-model="selectedWorkItemTypeId"
|
||||
:options="formOptions"
|
||||
class="gl-max-w-26"
|
||||
@change="updateCache"
|
||||
/>
|
||||
</gl-form-group>
|
||||
</div>
|
||||
</div>
|
||||
<work-item-title
|
||||
ref="title"
|
||||
data-testid="title-input"
|
||||
is-editing
|
||||
:is-valid="isTitleValid"
|
||||
:title="workItemTitle"
|
||||
@updateDraft="updateDraftData('title', $event)"
|
||||
@updateWorkItem="createWorkItem"
|
||||
/>
|
||||
<div data-testid="work-item-overview" class="work-item-overview">
|
||||
<section>
|
||||
<work-item-description
|
||||
edit-mode
|
||||
:autofocus="false"
|
||||
:full-path="fullPath"
|
||||
create-flow
|
||||
:show-buttons-below-field="false"
|
||||
:work-item-id="$options.NEW_WORK_ITEM_GID"
|
||||
:work-item-iid="$options.NEW_WORK_ITEM_IID"
|
||||
@error="updateError = $event"
|
||||
@updateDraft="updateDraftData('description', $event)"
|
||||
/>
|
||||
<gl-form-group :label="__('Confidentiality')" label-for="work-item-confidential">
|
||||
<gl-form-checkbox
|
||||
id="work-item-confidential"
|
||||
v-model="isConfidential"
|
||||
data-testid="confidential-checkbox"
|
||||
@change="updateDraftData('confidential', $event)"
|
||||
>
|
||||
{{ makeConfidentialText }}
|
||||
</gl-form-checkbox>
|
||||
</gl-form-group>
|
||||
</section>
|
||||
<aside
|
||||
v-if="hasWidgets"
|
||||
data-testid="work-item-overview-right-sidebar"
|
||||
class="work-item-overview-right-sidebar"
|
||||
:class="{ 'is-modal': true }"
|
||||
>
|
||||
<template v-if="workItemAssignees">
|
||||
<work-item-assignees
|
||||
class="gl-mb-5 js-assignee"
|
||||
:can-update="canUpdate"
|
||||
:full-path="fullPath"
|
||||
:work-item-id="workItem.id"
|
||||
:assignees="workItemAssignees.assignees.nodes"
|
||||
:participants="workItemParticipantNodes"
|
||||
:work-item-author="workItemAuthor"
|
||||
:allows-multiple-assignees="workItemAssignees.allowsMultipleAssignees"
|
||||
:work-item-type="workItemType"
|
||||
:can-invite-members="workItemAssignees.canInviteMembers"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="workItemHealthStatus">
|
||||
<work-item-health-status
|
||||
class="gl-mb-5"
|
||||
:health-status="workItemHealthStatus.healthStatus"
|
||||
:can-update="canUpdate"
|
||||
:work-item-id="workItem.id"
|
||||
:work-item-iid="workItem.iid"
|
||||
:work-item-type="workItemType"
|
||||
:full-path="fullPath"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="workItemColor">
|
||||
<work-item-color
|
||||
class="gl-mb-5"
|
||||
:work-item="workItem"
|
||||
:full-path="fullPath"
|
||||
:can-update="canUpdate"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
</template>
|
||||
</aside>
|
||||
<div class="gl-py-3 gl-flex gl-gap-3 gl-col-start-1">
|
||||
<gl-button
|
||||
variant="confirm"
|
||||
:loading="loading"
|
||||
data-testid="create-button"
|
||||
@click="createWorkItem"
|
||||
>
|
||||
{{ createWorkItemText }}
|
||||
</gl-button>
|
||||
<gl-button type="button" data-testid="cancel-button" @click="handleCancelClick">
|
||||
{{ __('Cancel') }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</form>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
import { GlButton, GlModal, GlDisclosureDropdownItem } from '@gitlab/ui';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import { setNewWorkItemCache } from '~/work_items/graphql/cache_utils';
|
||||
import {
|
||||
I18N_NEW_WORK_ITEM_BUTTON_LABEL,
|
||||
I18N_WORK_ITEM_CREATED,
|
||||
sprintfWorkItem,
|
||||
I18N_WORK_ITEM_ERROR_FETCHING_TYPES,
|
||||
} from '../constants';
|
||||
import projectWorkItemTypesQuery from '../graphql/project_work_item_types.query.graphql';
|
||||
import groupWorkItemTypesQuery from '../graphql/group_work_item_types.query.graphql';
|
||||
import CreateWorkItem from './create_work_item.vue';
|
||||
|
||||
export default {
|
||||
|
|
@ -16,6 +20,7 @@ export default {
|
|||
GlModal,
|
||||
GlDisclosureDropdownItem,
|
||||
},
|
||||
inject: ['fullPath', 'isGroup'],
|
||||
props: {
|
||||
workItemTypeName: {
|
||||
type: String,
|
||||
|
|
@ -31,8 +36,39 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
workItemTypes: [],
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
workItemTypes: {
|
||||
query() {
|
||||
return this.isGroup ? groupWorkItemTypesQuery : projectWorkItemTypesQuery;
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.fullPath,
|
||||
name: this.workItemTypeName,
|
||||
};
|
||||
},
|
||||
update(data) {
|
||||
return data.workspace?.workItemTypes?.nodes ?? [];
|
||||
},
|
||||
async result() {
|
||||
if (!this.workItemTypes || this.workItemTypes.length === 0) {
|
||||
return;
|
||||
}
|
||||
await setNewWorkItemCache(
|
||||
this.isGroup,
|
||||
this.fullPath,
|
||||
this.workItemTypes[0]?.widgetDefinitions,
|
||||
this.workItemTypeName,
|
||||
);
|
||||
},
|
||||
error() {
|
||||
this.error = I18N_WORK_ITEM_ERROR_FETCHING_TYPES;
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
newWorkItemText() {
|
||||
return sprintfWorkItem(I18N_NEW_WORK_ITEM_BUTTON_LABEL, this.workItemTypeName);
|
||||
|
|
@ -50,6 +86,14 @@ export default {
|
|||
methods: {
|
||||
hideModal() {
|
||||
this.visible = false;
|
||||
if (this.workItemTypes && this.workItemTypes[0]) {
|
||||
setNewWorkItemCache(
|
||||
this.isGroup,
|
||||
this.fullPath,
|
||||
this.workItemTypes[0]?.widgetDefinitions,
|
||||
this.workItemTypeName,
|
||||
);
|
||||
}
|
||||
},
|
||||
showModal() {
|
||||
this.visible = true;
|
||||
|
|
@ -79,8 +123,8 @@ export default {
|
|||
variant="confirm"
|
||||
data-testid="new-epic-button"
|
||||
@click="showModal"
|
||||
>{{ newWorkItemText }}</gl-button
|
||||
>
|
||||
>{{ newWorkItemText }}
|
||||
</gl-button>
|
||||
<gl-modal
|
||||
modal-id="create-work-item-modal"
|
||||
:visible="visible"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ import WorkItemSidebarDropdownWidget from '~/work_items/components/shared/work_i
|
|||
import { s__, sprintf, __ } from '~/locale';
|
||||
import Tracking from '~/tracking';
|
||||
import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql';
|
||||
import { i18n, TRACKING_CATEGORY_SHOW } from '../constants';
|
||||
import updateNewWorkItemMutation from '../graphql/update_new_work_item.mutation.graphql';
|
||||
import { i18n, TRACKING_CATEGORY_SHOW, NEW_WORK_ITEM_GID } from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -235,6 +236,22 @@ export default {
|
|||
this.updateInProgress = true;
|
||||
const { localAssigneeIds } = this;
|
||||
|
||||
if (this.workItemId === NEW_WORK_ITEM_GID) {
|
||||
this.$apollo.mutate({
|
||||
mutation: updateNewWorkItemMutation,
|
||||
variables: {
|
||||
input: {
|
||||
isGroup: this.isGroup,
|
||||
fullPath: this.fullPath,
|
||||
assignees: this.localAssignees,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.updateInProgress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const {
|
||||
data: {
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ export default {
|
|||
:due-date="workItemDueDate.dueDate"
|
||||
:start-date="workItemDueDate.startDate"
|
||||
:work-item-type="workItemType"
|
||||
:full-path="fullPath"
|
||||
:work-item="workItem"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
|
|
@ -234,6 +235,7 @@ export default {
|
|||
:work-item-id="workItem.id"
|
||||
:work-item-iid="workItem.iid"
|
||||
:work-item-type="workItemType"
|
||||
:full-path="fullPath"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -241,6 +243,7 @@ export default {
|
|||
<work-item-color
|
||||
class="gl-mb-5"
|
||||
:work-item="workItem"
|
||||
:full-path="fullPath"
|
||||
:can-update="canUpdate"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ import { __, s__ } from '~/locale';
|
|||
import EditedAt from '~/issues/show/components/edited.vue';
|
||||
import Tracking from '~/tracking';
|
||||
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
|
||||
import { autocompleteDataSources, markdownPreviewPath } from '../utils';
|
||||
import {
|
||||
newWorkItemFullPath,
|
||||
autocompleteDataSources,
|
||||
markdownPreviewPath,
|
||||
} from '~/work_items/utils';
|
||||
import groupWorkItemByIidQuery from '../graphql/group_work_item_by_iid.query.graphql';
|
||||
import workItemByIidQuery from '../graphql/work_item_by_iid.query.graphql';
|
||||
import { i18n, TRACKING_CATEGORY_SHOW, WIDGET_TYPE_DESCRIPTION } from '../constants';
|
||||
|
|
@ -61,6 +65,11 @@ export default {
|
|||
required: false,
|
||||
default: true,
|
||||
},
|
||||
createFlow: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
markdownDocsPath: helpPagePath('user/markdown'),
|
||||
data() {
|
||||
|
|
@ -90,12 +99,12 @@ export default {
|
|||
},
|
||||
variables() {
|
||||
return {
|
||||
fullPath: this.fullPath,
|
||||
fullPath: this.createFlow ? newWorkItemFullPath(this.fullPath) : this.fullPath,
|
||||
iid: this.workItemIid,
|
||||
};
|
||||
},
|
||||
update(data) {
|
||||
return data.workspace.workItem || {};
|
||||
return data?.workspace?.workItem || {};
|
||||
},
|
||||
result() {
|
||||
if (this.isEditing) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import {
|
|||
} from '../constants';
|
||||
|
||||
export default {
|
||||
name: 'WorkItemParent',
|
||||
inputId: 'work-item-parent-listbox-value',
|
||||
noWorkItemId: 'no-work-item-id',
|
||||
i18n: {
|
||||
|
|
|
|||
|
|
@ -354,3 +354,7 @@ export const MAX_FREQUENT_PROJECTS = 3;
|
|||
export const CREATE_NEW_WORK_ITEM_MODAL = 'create_new_work_item_modal';
|
||||
|
||||
export const WORK_ITEM_REFERENCE_CHAR = '#';
|
||||
|
||||
export const NEW_WORK_ITEM_IID = 'new-work-item-iid';
|
||||
|
||||
export const NEW_WORK_ITEM_GID = 'gid://gitlab/WorkItem/new';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,29 @@
|
|||
import { produce } from 'immer';
|
||||
import { findHierarchyWidgetChildren, isNotesWidget } from '../utils';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { apolloProvider } from '~/graphql_shared/issuable_client';
|
||||
import { issuesListClient } from '~/issues/list';
|
||||
import { TYPENAME_USER } from '~/graphql_shared/constants';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import { getBaseURL } from '~/lib/utils/url_utility';
|
||||
import { findHierarchyWidgetChildren, isNotesWidget, newWorkItemFullPath } from '../utils';
|
||||
import {
|
||||
WIDGET_TYPE_ASSIGNEES,
|
||||
WIDGET_TYPE_COLOR,
|
||||
WIDGET_TYPE_HIERARCHY,
|
||||
WIDGET_TYPE_PARTICIPANTS,
|
||||
WIDGET_TYPE_PROGRESS,
|
||||
WIDGET_TYPE_ROLLEDUP_DATES,
|
||||
WIDGET_TYPE_START_AND_DUE_DATE,
|
||||
WIDGET_TYPE_TIME_TRACKING,
|
||||
WIDGET_TYPE_LABELS,
|
||||
WIDGET_TYPE_WEIGHT,
|
||||
WIDGET_TYPE_MILESTONE,
|
||||
WIDGET_TYPE_ITERATION,
|
||||
WIDGET_TYPE_HEALTH_STATUS,
|
||||
WIDGET_TYPE_DESCRIPTION,
|
||||
NEW_WORK_ITEM_IID,
|
||||
NEW_WORK_ITEM_GID,
|
||||
} from '../constants';
|
||||
import groupWorkItemByIidQuery from './group_work_item_by_iid.query.graphql';
|
||||
import workItemByIidQuery from './work_item_by_iid.query.graphql';
|
||||
|
||||
|
|
@ -169,3 +193,261 @@ export const removeHierarchyChild = ({ cache, fullPath, iid, isGroup, workItem }
|
|||
}),
|
||||
});
|
||||
};
|
||||
|
||||
export const setNewWorkItemCache = async (isGroup, fullPath, widgetDefinitions, workItemType) => {
|
||||
const workItemAttributesWrapperOrder = [
|
||||
WIDGET_TYPE_ASSIGNEES,
|
||||
WIDGET_TYPE_LABELS,
|
||||
WIDGET_TYPE_WEIGHT,
|
||||
WIDGET_TYPE_ROLLEDUP_DATES,
|
||||
WIDGET_TYPE_MILESTONE,
|
||||
WIDGET_TYPE_ITERATION,
|
||||
WIDGET_TYPE_START_AND_DUE_DATE,
|
||||
WIDGET_TYPE_PROGRESS,
|
||||
WIDGET_TYPE_HEALTH_STATUS,
|
||||
WIDGET_TYPE_COLOR,
|
||||
WIDGET_TYPE_HIERARCHY,
|
||||
WIDGET_TYPE_TIME_TRACKING,
|
||||
WIDGET_TYPE_PARTICIPANTS,
|
||||
];
|
||||
|
||||
if (!widgetDefinitions) {
|
||||
return;
|
||||
}
|
||||
|
||||
const availableWidgets = widgetDefinitions?.flatMap((i) => i.type);
|
||||
const currentUserId = convertToGraphQLId(TYPENAME_USER, gon?.current_user_id);
|
||||
const baseURL = getBaseURL();
|
||||
|
||||
const widgets = [];
|
||||
|
||||
widgets.push({
|
||||
type: WIDGET_TYPE_DESCRIPTION,
|
||||
description: null,
|
||||
descriptionHtml: '',
|
||||
lastEditedAt: null,
|
||||
lastEditedBy: null,
|
||||
__typename: 'WorkItemWidgetDescription',
|
||||
});
|
||||
|
||||
widgets.push({
|
||||
type: WIDGET_TYPE_PARTICIPANTS,
|
||||
participants: {
|
||||
nodes: [
|
||||
{
|
||||
id: currentUserId,
|
||||
avatarUrl: gon?.current_user_avatar_url,
|
||||
username: gon?.current_username,
|
||||
name: gon?.current_user_fullname,
|
||||
webUrl: `${baseURL}/${gon?.current_username}`,
|
||||
webPath: `/${gon?.current_username}`,
|
||||
__typename: 'UserCore',
|
||||
},
|
||||
],
|
||||
__typename: 'UserCoreConnection',
|
||||
},
|
||||
__typename: 'WorkItemWidgetParticipants',
|
||||
});
|
||||
|
||||
workItemAttributesWrapperOrder.forEach((widgetName) => {
|
||||
if (availableWidgets.includes(widgetName)) {
|
||||
if (widgetName === WIDGET_TYPE_ASSIGNEES) {
|
||||
const assigneesWidgetData = widgetDefinitions.find(
|
||||
(definition) => definition.type === WIDGET_TYPE_ASSIGNEES,
|
||||
);
|
||||
widgets.push({
|
||||
type: 'ASSIGNEES',
|
||||
allowsMultipleAssignees: assigneesWidgetData.allowsMultipleAssignees,
|
||||
canInviteMembers: assigneesWidgetData.canInviteMembers,
|
||||
assignees: {
|
||||
nodes: [],
|
||||
__typename: 'UserCoreConnection',
|
||||
},
|
||||
__typename: 'WorkItemWidgetAssignees',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_LABELS) {
|
||||
const labelsWidgetData = widgetDefinitions.find(
|
||||
(definition) => definition.type === WIDGET_TYPE_LABELS,
|
||||
);
|
||||
widgets.push({
|
||||
type: 'LABELS',
|
||||
allowsScopedLabels: labelsWidgetData.allowsScopedLabels,
|
||||
labels: {
|
||||
nodes: [],
|
||||
__typename: 'LabelConnection',
|
||||
},
|
||||
__typename: 'WorkItemWidgetLabels',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_WEIGHT) {
|
||||
widgets.push({
|
||||
type: 'WEIGHT',
|
||||
weight: null,
|
||||
__typename: 'WorkItemWidgetWeight',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_ROLLEDUP_DATES) {
|
||||
widgets.push({
|
||||
type: 'ROLLEDUP_DATES',
|
||||
dueDate: null,
|
||||
dueDateFixed: null,
|
||||
dueDateIsFixed: null,
|
||||
startDate: null,
|
||||
startDateFixed: null,
|
||||
startDateIsFixed: null,
|
||||
__typename: 'WorkItemWidgetRolledupDates',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_MILESTONE) {
|
||||
widgets.push({
|
||||
type: 'MILESTONE',
|
||||
milestone: null,
|
||||
__typename: 'WorkItemWidgetMilestone',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_ITERATION) {
|
||||
widgets.push({
|
||||
iteration: null,
|
||||
type: 'ITERATION',
|
||||
__typename: 'WorkItemWidgetIteration',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_START_AND_DUE_DATE) {
|
||||
widgets.push({
|
||||
type: 'START_AND_DUE_DATE',
|
||||
dueDate: null,
|
||||
startDate: null,
|
||||
__typename: 'WorkItemWidgetStartAndDueDate',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_PROGRESS) {
|
||||
widgets.push({
|
||||
type: 'PROGRESS',
|
||||
progress: null,
|
||||
updatedAt: null,
|
||||
__typename: 'WorkItemWidgetProgress',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_HEALTH_STATUS) {
|
||||
widgets.push({
|
||||
type: 'HEALTH_STATUS',
|
||||
healthStatus: null,
|
||||
__typename: 'WorkItemWidgetHealthStatus',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_COLOR) {
|
||||
widgets.push({
|
||||
type: 'COLOR',
|
||||
color: '#1068bf',
|
||||
textColor: '#FFFFFF',
|
||||
__typename: 'WorkItemWidgetColor',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_HIERARCHY) {
|
||||
widgets.push({
|
||||
type: 'HIERARCHY',
|
||||
hasChildren: false,
|
||||
parent: null,
|
||||
children: {
|
||||
nodes: [],
|
||||
__typename: 'WorkItemConnection',
|
||||
},
|
||||
__typename: 'WorkItemWidgetHierarchy',
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetName === WIDGET_TYPE_TIME_TRACKING) {
|
||||
widgets.push({
|
||||
type: 'TIME_TRACKING',
|
||||
timeEstimate: 0,
|
||||
timelogs: {
|
||||
nodes: [],
|
||||
__typename: 'WorkItemTimelogConnection',
|
||||
},
|
||||
totalTimeSpent: 0,
|
||||
__typename: 'WorkItemWidgetTimeTracking',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const issuesListApolloProvider = new VueApollo({
|
||||
defaultClient: await issuesListClient(),
|
||||
});
|
||||
|
||||
const cacheProvider = document.querySelector('.js-issues-list-app')
|
||||
? issuesListApolloProvider
|
||||
: apolloProvider;
|
||||
|
||||
cacheProvider.clients.defaultClient.cache.writeQuery({
|
||||
query: isGroup ? groupWorkItemByIidQuery : workItemByIidQuery,
|
||||
variables: {
|
||||
fullPath: newWorkItemFullPath(fullPath),
|
||||
iid: NEW_WORK_ITEM_IID,
|
||||
},
|
||||
data: {
|
||||
workspace: {
|
||||
id: newWorkItemFullPath(fullPath),
|
||||
workItem: {
|
||||
id: NEW_WORK_ITEM_GID,
|
||||
iid: NEW_WORK_ITEM_IID,
|
||||
archived: false,
|
||||
title: '',
|
||||
state: 'OPEN',
|
||||
description: null,
|
||||
confidential: false,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
closedAt: null,
|
||||
webUrl: `${baseURL}/groups/gitlab-org/-/work_items/new`,
|
||||
reference: '',
|
||||
createNoteEmail: null,
|
||||
namespace: {
|
||||
id: newWorkItemFullPath(fullPath),
|
||||
fullPath,
|
||||
name: newWorkItemFullPath(fullPath),
|
||||
__typename: 'Namespace', // eslint-disable-line @gitlab/require-i18n-strings
|
||||
},
|
||||
author: {
|
||||
id: currentUserId,
|
||||
avatarUrl: gon?.current_user_avatar_url,
|
||||
username: gon?.current_username,
|
||||
name: gon?.current_user_fullname,
|
||||
webUrl: `${baseURL}/${gon?.current_username}`,
|
||||
webPath: `/${gon?.current_username}`,
|
||||
__typename: 'UserCore',
|
||||
},
|
||||
workItemType: {
|
||||
id: 'mock-work-item-type-id',
|
||||
name: workItemType,
|
||||
iconName: 'issue-type-epic',
|
||||
__typename: 'WorkItemType',
|
||||
},
|
||||
userPermissions: {
|
||||
deleteWorkItem: true,
|
||||
updateWorkItem: true,
|
||||
adminParentLink: true,
|
||||
setWorkItemMetadata: true,
|
||||
createNote: true,
|
||||
adminWorkItemLink: true,
|
||||
__typename: 'WorkItemPermissions',
|
||||
},
|
||||
widgets,
|
||||
__typename: 'WorkItem',
|
||||
},
|
||||
__typename: 'Namespace', // eslint-disable-line @gitlab/require-i18n-strings
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,3 +36,18 @@ type LocalWorkItemPayload {
|
|||
extend type Mutation {
|
||||
localUpdateWorkItem(input: LocalUpdateWorkItemInput!): LocalWorkItemPayload
|
||||
}
|
||||
|
||||
input LocalUpdateNewWorkItemInput {
|
||||
fullPath: String!
|
||||
isGroup: Boolean!
|
||||
healthStatus: String
|
||||
assignees: [LocalUserInput]
|
||||
color: String
|
||||
title: String
|
||||
description: String
|
||||
confidential: Boolean
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
updateNewWorkItem(input: LocalUpdateNewWorkItemInput!): LocalWorkItemPayload
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
mutation updateNewWorkItem($input: LocalUpdateNewWorkItemInput) {
|
||||
updateNewWorkItem(input: $input) @client
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import WorkItemsListApp from 'ee_else_ce/work_items/list/components/work_items_list_app.vue';
|
||||
import { apolloProvider } from '~/graphql_shared/issuable_client';
|
||||
|
||||
export const mountWorkItemsListApp = () => {
|
||||
const el = document.querySelector('.js-work-items-list-root');
|
||||
|
|
@ -22,14 +22,13 @@ export const mountWorkItemsListApp = () => {
|
|||
isSignedIn,
|
||||
showNewIssueLink,
|
||||
workItemType,
|
||||
canCreateEpic,
|
||||
} = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
name: 'WorkItemsListRoot',
|
||||
apolloProvider: new VueApollo({
|
||||
defaultClient: createDefaultClient(),
|
||||
}),
|
||||
apolloProvider,
|
||||
provide: {
|
||||
fullPath,
|
||||
hasEpicsFeature: parseBoolean(hasEpicsFeature),
|
||||
|
|
@ -40,6 +39,7 @@ export const mountWorkItemsListApp = () => {
|
|||
isGroup: true,
|
||||
showNewIssueLink: parseBoolean(showNewIssueLink),
|
||||
workItemType,
|
||||
canCreateEpic: parseBoolean(canCreateEpic),
|
||||
},
|
||||
render: (createComponent) => createComponent(WorkItemsListApp),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -106,3 +106,8 @@ export const workItemRoadmapPath = (fullPath, iid) => {
|
|||
const domain = gon.relative_url_root || '';
|
||||
return `${domain}/groups/${fullPath}/-/roadmap?epic_iid=${iid}`;
|
||||
};
|
||||
|
||||
export const newWorkItemFullPath = (fullPath) => {
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
return `${fullPath}-id`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
|
|||
# TODO https://gitlab.com/gitlab-org/gitlab/-/issues/388541
|
||||
# type_id is a misnomer. QuickActions::TargetService actually requires an iid.
|
||||
QuickActions::TargetService
|
||||
.new(container: project, current_user: current_user)
|
||||
.new(container: project, current_user: current_user, params: params)
|
||||
.execute(target_type, params[:type_id])
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MergeRequests
|
||||
class DiscussionsResolvedEvent < Gitlab::EventStore::Event
|
||||
def schema
|
||||
{
|
||||
'type' => 'object',
|
||||
'required' => %w[
|
||||
current_user_id
|
||||
merge_request_id
|
||||
],
|
||||
'properties' => {
|
||||
'current_user_id' => { 'type' => 'integer' },
|
||||
'merge_request_id' => { 'type' => 'integer' }
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -120,7 +120,12 @@ module SidebarsHelper
|
|||
end
|
||||
|
||||
def work_items_modal_data(group)
|
||||
{ full_path: group.full_path } if group
|
||||
return unless group
|
||||
|
||||
{
|
||||
full_path: group.full_path,
|
||||
has_issuable_health_status_feature: group.licensed_feature_available?(:issuable_health_status).to_s
|
||||
}
|
||||
end
|
||||
|
||||
def super_sidebar_nav_panel(
|
||||
|
|
|
|||
|
|
@ -74,36 +74,28 @@ module WikiHelper
|
|||
def wiki_empty_state_messages(wiki)
|
||||
case wiki.container
|
||||
when Project
|
||||
writable_body = s_("WikiEmpty|A wiki is where you can store all the details about your project. This can include why you've created it, its principles, how to use it, and so on.")
|
||||
writable_body = s_("WikiEmpty|Use GitLab Wiki to collaborate on documentation in a project or group. You can store wiki pages written in markup formats like Markdown or AsciiDoc in a separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.")
|
||||
writable_body += s_("WikiEmpty| Have a Confluence wiki already? Use that instead.") if show_enable_confluence_integration?(wiki.container)
|
||||
|
||||
{
|
||||
writable: {
|
||||
title: s_('WikiEmpty|The wiki lets you write documentation for your project'),
|
||||
title: s_('WikiEmpty|Get started with wikis'),
|
||||
body: writable_body
|
||||
},
|
||||
issuable: {
|
||||
title: s_('WikiEmpty|This project has no wiki pages'),
|
||||
body: s_('WikiEmptyIssueMessage|You must be a project member in order to add wiki pages. If you have suggestions for how to improve the wiki for this project, consider opening an issue in the %{issues_link}.')
|
||||
},
|
||||
readonly: {
|
||||
title: s_('WikiEmpty|This project has no wiki pages'),
|
||||
body: s_('WikiEmpty|You must be a project member in order to add wiki pages.')
|
||||
title: s_('WikiEmpty|This wiki doesn\'t have any content yet'),
|
||||
body: s_('WikiEmpty|You can use GitLab Wiki to collaborate on documentation in a project or group. You can store wiki pages written in markup formats like Markdown or AsciiDoc in a separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.')
|
||||
}
|
||||
}
|
||||
when Group
|
||||
{
|
||||
writable: {
|
||||
title: s_('WikiEmpty|The wiki lets you write documentation for your group'),
|
||||
body: s_("WikiEmpty|A wiki is where you can store all the details about your group. This can include why you've created it, its principles, how to use it, and so on.")
|
||||
},
|
||||
issuable: {
|
||||
title: s_('WikiEmpty|This group has no wiki pages'),
|
||||
body: s_('WikiEmptyIssueMessage|You must be a group member in order to add wiki pages. If you have suggestions for how to improve the wiki for this group, consider opening an issue in the %{issues_link}.')
|
||||
title: s_('WikiEmpty|Get started with wikis'),
|
||||
body: s_("WikiEmpty|Use GitLab Wiki to collaborate on documentation in a project or group. You can store wiki pages written in markup formats like Markdown or AsciiDoc in a separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.")
|
||||
},
|
||||
readonly: {
|
||||
title: s_('WikiEmpty|This group has no wiki pages'),
|
||||
body: s_('WikiEmpty|You must be a group member in order to add wiki pages.')
|
||||
title: s_('WikiEmpty|This wiki doesn\'t have any content yet'),
|
||||
body: s_('WikiEmpty|You can use GitLab Wiki to collaborate on documentation in a project or group. You can store wiki pages written in markup formats like Markdown or AsciiDoc in a separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.')
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
|
|||
reached_max_pipeline_hierarchy_size: 'The downstream pipeline tree is too large',
|
||||
project_deleted: 'The job belongs to a deleted project',
|
||||
user_blocked: 'The user who created this job is blocked',
|
||||
ci_quota_exceeded: 'No more CI minutes available',
|
||||
ci_quota_exceeded: 'No more compute minutes available',
|
||||
no_matching_runner: 'No matching runner available',
|
||||
trace_size_exceeded: 'The job log size limit was reached',
|
||||
builds_disabled: 'The CI/CD is disabled for this project',
|
||||
|
|
|
|||
|
|
@ -83,7 +83,15 @@ module Discussions
|
|||
def process_auto_merge
|
||||
return unless discussions_ready_to_merge?
|
||||
|
||||
AutoMergeProcessWorker.perform_async(merge_request.id)
|
||||
if Feature.enabled?(:merge_when_checks_pass, merge_request.project)
|
||||
Gitlab::EventStore.publish(
|
||||
MergeRequests::DiscussionsResolvedEvent.new(
|
||||
data: { current_user_id: current_user.id, merge_request_id: merge_request.id }
|
||||
)
|
||||
)
|
||||
else
|
||||
AutoMergeProcessWorker.perform_async(merge_request.id)
|
||||
end
|
||||
end
|
||||
|
||||
def discussions_ready_to_merge?
|
||||
|
|
|
|||
|
|
@ -19,6 +19,14 @@ module QuickActions
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def work_item(type_iid)
|
||||
if type_iid.blank?
|
||||
parent = group_container? ? { namespace: group } : { project: project, namespace: project.project_namespace }
|
||||
return WorkItem.new(
|
||||
work_item_type_id: params[:work_item_type_id] || WorkItems::Type.default_issue_type.id,
|
||||
**parent
|
||||
)
|
||||
end
|
||||
|
||||
WorkItems::WorkItemsFinder.new(current_user, **parent_params).find_by(iid: type_iid)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
|
|
|||
|
|
@ -46,5 +46,5 @@
|
|||
= f.fields_for :credit_card_validation do |ff|
|
||||
= ff.gitlab_ui_checkbox_component :credit_card_validated_at,
|
||||
s_('AdminUsers|Validate user account'),
|
||||
help_text: s_('AdminUsers|A user can validate themselves by inputting a credit/debit card, or an admin can manually validate a user. Validated users can use free CI minutes on instance runners.'),
|
||||
help_text: s_('AdminUsers|A user can validate themselves by inputting a credit/debit card, or an admin can manually validate a user. Validated users can use free compute minutes on instance runners.'),
|
||||
checkbox_options: { checked: @user.credit_card_validated_at.present? }
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
- if Feature.disabled?(:page_specific_styles, current_user)
|
||||
- add_page_specific_style('page_bundles/commit_description')
|
||||
|
||||
- add_page_specific_style('page_bundles/work_items')
|
||||
|
||||
%head{ omit_og ? { } : { prefix: "og: http://ogp.me/ns#" } }
|
||||
%meta{ charset: "utf-8" }
|
||||
%meta{ 'http-equiv' => 'X-UA-Compatible', content: 'IE=edge' }
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
%p
|
||||
- link = link_to('', help_page_path('user/project/working_with_projects', anchor: 'rename-a-repository'), target: '_blank', rel: 'noopener noreferrer')
|
||||
= safe_format(_("A project’s repository name defines its URL (the one you use to access the project via a browser) and its place on the file disk where GitLab is installed. %{link_start}Learn more.%{link_end}"), tag_pair(link, :link_start, :link_end))
|
||||
%p= _('When you transfer your project to a group, you can easily manage multiple projects, view usage quotas for storage, pipeline minutes, and users, and start a trial or upgrade to a paid tier.')
|
||||
%p= _('When you transfer your project to a group, you can easily manage multiple projects, view usage quotas for storage, compute minutes, and users, and start a trial or upgrade to a paid tier.')
|
||||
%p
|
||||
= _("Don't have a group?")
|
||||
= link_to _('Create one'), new_group_path, target: '_blank'
|
||||
|
|
|
|||
|
|
@ -19,14 +19,6 @@
|
|||
- secondary_button_text = s_('WikiEmpty|Enable the Confluence Wiki integration')
|
||||
- secondary_button_link = edit_project_settings_integration_path(@project, :confluence)
|
||||
|
||||
- elsif @project && can?(current_user, :read_issue, @project)
|
||||
- title = messages.dig(:issuable, :title)
|
||||
- issues_link = link_to s_('WikiEmptyIssueMessage|issue tracker'), project_issues_path(@project)
|
||||
- description = messages.dig(:issuable, :body).html_safe % { issues_link: issues_link }
|
||||
- if show_new_issue_link?(@project)
|
||||
- primary_button_text = s_('WikiEmpty|Suggest wiki improvement')
|
||||
- primary_button_link = new_project_issue_path(@project)
|
||||
|
||||
= render Pajamas::EmptyStateComponent.new(svg_path: illustration,
|
||||
title: title,
|
||||
primary_button_text: primary_button_text,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
description: User clicks a group result in the command palette
|
||||
internal_events: true
|
||||
action: click_group_result_in_command_palette
|
||||
identifiers:
|
||||
- namespace
|
||||
- user
|
||||
product_section: core_platform
|
||||
product_stage: data_stores
|
||||
product_group: global_search
|
||||
milestone: '17.1'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151657
|
||||
distributions:
|
||||
- ce
|
||||
- ee
|
||||
tiers:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: counts_monthly.deployments
|
||||
description: Total deployments count for recent 28 days
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.clusters_applications_cert_managers
|
||||
description: Count user ids from GitLab Managed clusters with Cert Manager enabled
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.clusters_applications_helm
|
||||
description: Count user ids from GitLab Managed clusters with Helm enabled
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.clusters_applications_ingress
|
||||
description: Count user ids from GitLab Managed clusters with Ingress enabled
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.clusters_applications_knative
|
||||
description: Count user ids from GitLab Managed clusters with Knative enabled
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ data_category: optional
|
|||
key_path: usage_activity_by_stage_monthly.configure.clusters_management_project
|
||||
description: Number of Kubernetes clusters with clusters management project being
|
||||
set
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.clusters_disabled
|
||||
description: Number of user ids from GitLab Managed disabled clusters
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.clusters_enabled
|
||||
description: Number of distict user ids from GitLab Managed clusters currently enabled
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.clusters_platforms_gke
|
||||
description: Number of user ids from GitLab Managed clusters provisioned with GitLab on GCE GKE
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.clusters_platforms_eks
|
||||
description: Number of user ids from GitLab Managed clusters provisioned with GitLab on AWS EKS
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.clusters_platforms_user
|
||||
description: Number of user ids from GitLab Managed clusters that are user provisioned
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.instance_clusters_disabled
|
||||
description: Number of users from GitLab Managed disabled clusters attached to the instance
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.instance_clusters_enabled
|
||||
description: Number of user ids from GitLab Managed enabled clusters attached to the instance
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.group_clusters_disabled
|
||||
description: Number of user ids GitLab Managed disabled clusters attached to groups
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.group_clusters_enabled
|
||||
description: Count disctinct user ids from GitLab Managed enabled clusters attached to groups
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: usage_activity_by_stage_monthly.configure.project_clusters_disabled
|
||||
description: Number of user ids from GitLab Managed disabled clusters attached to projects
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: usage_activity_by_stage_monthly.configure.project_clusters_enabled
|
||||
description: Number of user ids from GitLab Managed enabled clusters attached to projects
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: usage_activity_by_stage_monthly.verify.ci_pipeline_config_auto_devops
|
||||
description: Distinct users that ran an auto DevOps pipeline without a .gitlab-ci.yml file.
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.quickactions.i_quickactions_rebase_monthly
|
||||
description: Count of MAU using the `/rebase` quick action on a Merge Request
|
||||
product_section: dev
|
||||
product_stage: source_code
|
||||
product_group: source_code
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: counts_monthly.successful_deployments
|
||||
description: Total successful deployments
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: counts_monthly.failed_deployments
|
||||
description: Total failed deployments
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: usage_activity_by_stage_monthly.release.deployments
|
||||
description: Unique users triggering deployments
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: usage_activity_by_stage_monthly.release.failed_deployments
|
||||
description: Disinct users who initiated a failed deployment.
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: usage_activity_by_stage_monthly.release.releases
|
||||
description: Unique users creating release tags
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: usage_activity_by_stage_monthly.release.successful_deployments
|
||||
description: Disinct users who initiated a successful deployment.
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: redis_hll_counters.terraform.p_terraform_state_api_unique_users_monthly
|
||||
description: Monthly active users of GitLab Managed Terraform states
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_auto_devops_monthly
|
||||
description: Count of pipelines with implicit Auto DevOps runs
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_auto_devops_build_monthly
|
||||
description: Count of pipelines with implicit Auto Build runs
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: removed
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_auto_devops_deploy_monthly
|
||||
description: Count of pipelines with implicit Auto Deploy runs
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: removed
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_5_min_production_app_monthly
|
||||
description: Number of projects using 5 min production app CI template in last 7 days.
|
||||
product_section: seg
|
||||
product_stage: deploy
|
||||
product_group: 5-min-app
|
||||
value_type: number
|
||||
status: removed
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_auto_devops_monthly
|
||||
description: Count of pipelines using the Auto DevOps template
|
||||
product_section: ops
|
||||
product_stage: configure
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ data_category: optional
|
|||
key_path: redis_hll_counters.ci_templates.p_ci_templates_aws_cf_deploy_ec2_monthly
|
||||
description: Count of projects using `AWS/CF-Provision-and-Deploy-EC2.gitlab-ci.yml`
|
||||
template in last 28 days.
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: removed
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ data_category: optional
|
|||
key_path: redis_hll_counters.ci_templates.p_ci_templates_aws_deploy_ecs_monthly
|
||||
description: Count of projects using `AWS/Deploy-ECS.gitlab-ci.yml` template in last
|
||||
28 days.
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_auto_devops_build_monthly
|
||||
description: Count of pipelines using the Auto Build template
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: removed
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_auto_devops_deploy_monthly
|
||||
description: Count of pipelines using the stable Auto Deploy template
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: removed
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_auto_devops_deploy_latest_monthly
|
||||
description: Count of pipelines using the latest Auto Deploy template
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: removed
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: optional
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_terraform_base_latest_monthly
|
||||
description: Count of pipelines that include the terraform base template from GitLab
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
data_category: operational
|
||||
key_path: redis_hll_counters.ci_templates.ci_templates_total_unique_counts_monthly
|
||||
description: Total count of pipelines runs
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: removed
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
key_path: usage_activity_by_stage_monthly.release.releases_with_milestones
|
||||
description: Unique users creating releases with milestones associated
|
||||
performance_indicator_type: []
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_users.ci_users_executing_deployment_job_monthly
|
||||
description: Monthly counts of times users have executed deployment jobs
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_users.ci_users_executing_verify_environment_job_monthly
|
||||
description: Monthly counts of times users have executed verify jobs
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.kubernetes_agent.agent_users_using_ci_tunnel_monthly
|
||||
description: MAU of the Agent for Kubernetes CI/CD Tunnel
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
product_category: deployment_management
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.environments.users_visiting_environments_pages_monthly
|
||||
description: Monthly count of unique users visiting environments pages
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.work_items.users_updating_work_item_iteration_monthly
|
||||
description: Unique users updating a work item's iteration
|
||||
product_section: team planning
|
||||
product_stage: dev
|
||||
product_group: project_management
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_terraform_module_monthly
|
||||
description: Count of pipelines using the Terraform Module template
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_terraform_module_base_monthly
|
||||
description: Count of pipelines using the Terraform Module Base template
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_agents_via_ci_access_monthly
|
||||
description: MAU of the unique Agents using the CI/CD Tunnel via Ci Access
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_agents_via_user_access_monthly
|
||||
description: MAU of the unique Agents using the CI/CD Tunnel via User Access
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_users_via_ci_access_monthly
|
||||
description: MAU of the unique Users using the CI/CD Tunnel via Ci Access
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_users_via_user_access_monthly
|
||||
description: MAU of the unique Users using the CI/CD Tunnel via User Access
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.kubernetes_agent.flux_git_push_notified_unique_projects_monthly
|
||||
description: MAU of the unique projects which were notified by agentk about new Git push events in order to reconcile their Flux workloads
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_agents_via_pat_access_monthly
|
||||
description: MAU of the unique Agents using the KAS Kubernetes API proxy via Personal Access Token Access
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_users_via_pat_access_monthly
|
||||
description: MAU of the unique Users using the KAS Kubernetes API proxy via Personal Access Token Access
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_diffblue_cover_monthly
|
||||
description: Count of pipelines using the Diffblue Cover template
|
||||
product_section: ci
|
||||
product_stage: pipeline_authoring
|
||||
product_group: pipeline_authoring
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_opentofu_base_latest_monthly
|
||||
description: Count of pipelines that include the OpenTofu job template from GitLab
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.ci_templates.p_ci_templates_opentofu_latest_monthly
|
||||
description: Count of pipelines that include the OpenTofu pipeline template from GitLab
|
||||
product_section: ops
|
||||
product_stage: deploy
|
||||
product_group: environments
|
||||
value_type: number
|
||||
status: active
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
key_path: redis_hll_counters.count_distinct_user_id_from_click_group_result_in_command_palette_monthly
|
||||
description: Monthly count of unique users User clicks a group result in the command palette
|
||||
product_section: core_platform
|
||||
product_stage: data_stores
|
||||
product_group: global_search
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.1'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151657
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: click_group_result_in_command_palette
|
||||
unique: user.id
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.count_distinct_user_id_from_click_project_result_in_command_palette_monthly
|
||||
description: Monthly count of unique users User clicks a project result in the command palette
|
||||
product_section: core_platform
|
||||
product_stage: data_stores
|
||||
product_group: global_search
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.count_distinct_user_id_from_click_regex_button_in_search_page_input_monthly
|
||||
description: Monthly count of unique users who click regular expression button in search bar
|
||||
product_section: core_platform
|
||||
product_stage: data_stores
|
||||
product_group: global_search
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.count_distinct_user_id_from_click_search_button_to_activate_command_palette_monthly
|
||||
description: Monthly count of unique users User activates the command palette with the search button
|
||||
product_section: core_platform
|
||||
product_stage: data_stores
|
||||
product_group: global_search
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: redis_hll_counters.count_distinct_user_id_from_click_user_result_in_command_palette_monthly
|
||||
description: Monthly count of unique users User clicks a user result in the command palette
|
||||
product_section: core_platform
|
||||
product_stage: data_stores
|
||||
product_group: global_search
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: count_distinct_user_id_from_i_quickactions_remove_email_multiple_28d
|
||||
description: Unique users using the /remove_email quick action to remove multiple email participants from an issue within 28 days
|
||||
product_section: seg
|
||||
product_stage: service
|
||||
product_group: respond
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
---
|
||||
key_path: count_distinct_user_id_from_i_quickactions_remove_email_single_28d
|
||||
description: Unique users using the /remove_email quick action to remove a single email participant from an issue within 28 days
|
||||
product_section: seg
|
||||
product_stage: service
|
||||
product_group: respond
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue