Commit d9df18a3 authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '347547-request-deployment-target-info-from-users-on-new-projects' into 'master'

Request deployment target info from users on new projects

See merge request gitlab-org/gitlab!79873
parents ea91c704 83f1d280
import { initNewProjectCreation, initNewProjectUrlSelect } from '~/projects/new';
import {
initNewProjectCreation,
initNewProjectUrlSelect,
initDeploymentTargetSelect,
} from '~/projects/new';
import initProjectVisibilitySelector from '~/projects/project_visibility';
import initProjectNew from '~/projects/project_new';
......@@ -6,3 +10,4 @@ initProjectVisibilitySelector();
initProjectNew.bindEvents();
initNewProjectCreation();
initNewProjectUrlSelect();
initDeploymentTargetSelect();
<script>
import { GlFormGroup, GlFormSelect } from '@gitlab/ui';
import { s__ } from '~/locale';
import Tracking from '~/tracking';
import {
DEPLOYMENT_TARGET_SELECTIONS,
DEPLOYMENT_TARGET_LABEL,
DEPLOYMENT_TARGET_EVENT,
NEW_PROJECT_FORM,
} from '../constants';
const trackingMixin = Tracking.mixin({ label: DEPLOYMENT_TARGET_LABEL });
export default {
i18n: {
deploymentTargetLabel: s__('Deployment Target|Project deployment target (optional)'),
defaultOption: s__('Deployment Target|Select the deployment target'),
},
deploymentTargets: DEPLOYMENT_TARGET_SELECTIONS,
selectId: 'deployment-target-select',
components: {
GlFormGroup,
GlFormSelect,
},
mixins: [trackingMixin],
data() {
return {
selectedTarget: null,
formSubmitted: false,
};
},
mounted() {
const form = document.getElementById(NEW_PROJECT_FORM);
form.addEventListener('submit', () => {
this.formSubmitted = true;
this.trackSelection();
});
},
methods: {
trackSelection() {
if (this.formSubmitted && this.selectedTarget) {
this.track(DEPLOYMENT_TARGET_EVENT, { property: this.selectedTarget });
}
},
},
};
</script>
<template>
<gl-form-group :label="$options.i18n.deploymentTargetLabel" :label-for="$options.selectId">
<gl-form-select
:id="$options.selectId"
v-model="selectedTarget"
:options="$options.deploymentTargets"
>
<template #first>
<option :value="null" disabled>{{ $options.i18n.defaultOption }}</option>
</template>
</gl-form-select>
</gl-form-group>
</template>
import { s__ } from '~/locale';
export const DEPLOYMENT_TARGET_SELECTIONS = [
s__('DeploymentTarget|Kubernetes (GKE, EKS, OpenShift, and so on)'),
s__('DeploymentTarget|Managed container runtime (Fargate, Cloud Run, DigitalOcean App)'),
s__('DeploymentTarget|Self-managed container runtime (Podman, Docker Swarm, Docker Compose)'),
s__('DeploymentTarget|Heroku'),
s__('DeploymentTarget|Virtual machine (for example, EC2)'),
s__('DeploymentTarget|Mobile app store'),
s__('DeploymentTarget|Registry (package or container)'),
s__('DeploymentTarget|Infrastructure provider (Terraform, Cloudformation, and so on)'),
s__('DeploymentTarget|Serverless backend (Lambda, Cloud functions)'),
s__('DeploymentTarget|GitLab Pages'),
s__('DeploymentTarget|Other hosting service'),
s__('DeploymentTarget|None'),
];
export const NEW_PROJECT_FORM = 'new_project';
export const DEPLOYMENT_TARGET_LABEL = 'new_project_deployment_target';
export const DEPLOYMENT_TARGET_EVENT = 'select_deployment_target';
......@@ -4,6 +4,7 @@ import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils';
import NewProjectCreationApp from './components/app.vue';
import NewProjectUrlSelect from './components/new_project_url_select.vue';
import DeploymentTargetSelect from './components/deployment_target_select.vue';
export function initNewProjectCreation() {
const el = document.querySelector('.js-new-project-creation');
......@@ -64,3 +65,16 @@ export function initNewProjectUrlSelect() {
}),
);
}
export function initDeploymentTargetSelect() {
const el = document.querySelector('.js-deployment-target-select');
if (!el) {
return null;
}
return new Vue({
el,
render: (createElement) => createElement(DeploymentTargetSelect),
});
}
......@@ -46,6 +46,8 @@
= s_('ProjectsNew|Project description %{tag_start}(optional)%{tag_end}').html_safe % { tag_start: '<span>'.html_safe, tag_end: '</span>'.html_safe }
= f.text_area :description, placeholder: s_('ProjectsNew|Description format'), class: "form-control gl-form-input", rows: 3, maxlength: 250, data: { track_label: "#{track_label}", track_action: "activate_form_input", track_property: "project_description", track_value: "" }
.js-deployment-target-select
= f.label :visibility_level, class: 'label-bold' do
= s_('ProjectsNew|Visibility Level')
= link_to sprite_icon('question-o'), help_page_path('public_access/public_access'), aria: { label: 'Documentation for Visibility Level' }, target: '_blank', rel: 'noopener noreferrer'
......
---
description: Deployment target option selected from new project creation form
category: projects:new
action: select_deployment_target
label_description: new_project_deployment_target
property_description: selected option (string)
product_section: ops
product_stage: configure
product_group: group::configure
product_category:
milestone: "14.8"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79873
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate
......@@ -99,6 +99,8 @@ To create a blank project:
slug as the URL path to the project. To change the slug, first enter the project name,
then change the slug.
- In the **Project description (optional)** field, enter the description of your project's dashboard.
- In the **Project target (optional)** field, select your project's deployment target.
This information helps GitLab better understand its users and their deployment requirements.
- To modify the project's [viewing and access rights](../../public_access/public_access.md) for
users, change the **Visibility Level**.
- To create README file so that the Git repository is initialized, has a default branch, and
......
......@@ -12110,9 +12110,51 @@ msgstr ""
msgid "Deployment Frequency"
msgstr ""
msgid "Deployment Target|Project deployment target (optional)"
msgstr ""
msgid "Deployment Target|Select the deployment target"
msgstr ""
msgid "Deployment frequency"
msgstr ""
msgid "DeploymentTarget|GitLab Pages"
msgstr ""
msgid "DeploymentTarget|Heroku"
msgstr ""
msgid "DeploymentTarget|Infrastructure provider (Terraform, Cloudformation, and so on)"
msgstr ""
msgid "DeploymentTarget|Kubernetes (GKE, EKS, OpenShift, and so on)"
msgstr ""
msgid "DeploymentTarget|Managed container runtime (Fargate, Cloud Run, DigitalOcean App)"
msgstr ""
msgid "DeploymentTarget|Mobile app store"
msgstr ""
msgid "DeploymentTarget|None"
msgstr ""
msgid "DeploymentTarget|Other hosting service"
msgstr ""
msgid "DeploymentTarget|Registry (package or container)"
msgstr ""
msgid "DeploymentTarget|Self-managed container runtime (Podman, Docker Swarm, Docker Compose)"
msgstr ""
msgid "DeploymentTarget|Serverless backend (Lambda, Cloud functions)"
msgstr ""
msgid "DeploymentTarget|Virtual machine (for example, EC2)"
msgstr ""
msgid "Deployments"
msgstr ""
......
import { GlFormGroup, GlFormSelect } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { mockTracking } from 'helpers/tracking_helper';
import DeploymentTargetSelect from '~/projects/new/components/deployment_target_select.vue';
import {
DEPLOYMENT_TARGET_SELECTIONS,
DEPLOYMENT_TARGET_LABEL,
DEPLOYMENT_TARGET_EVENT,
NEW_PROJECT_FORM,
} from '~/projects/new/constants';
describe('Deployment target select', () => {
let wrapper;
let trackingSpy;
const findFormGroup = () => wrapper.findComponent(GlFormGroup);
const findSelect = () => wrapper.findComponent(GlFormSelect);
const createdWrapper = () => {
wrapper = shallowMount(DeploymentTargetSelect, {
stubs: {
GlFormSelect,
},
});
};
const createForm = () => {
setFixtures(`
<form id="${NEW_PROJECT_FORM}">
</form>
`);
};
beforeEach(() => {
createForm();
createdWrapper();
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
});
afterEach(() => {
wrapper.destroy();
});
it('renders the correct label', () => {
expect(findFormGroup().attributes('label')).toBe('Project deployment target (optional)');
});
it('renders a select with the disabled default option', () => {
expect(findSelect().find('option').text()).toBe('Select the deployment target');
expect(findSelect().find('option').attributes('disabled')).toBe('disabled');
});
describe.each`
selectedTarget | formSubmitted | eventSent
${null} | ${true} | ${false}
${DEPLOYMENT_TARGET_SELECTIONS[0]} | ${false} | ${false}
${DEPLOYMENT_TARGET_SELECTIONS[0]} | ${true} | ${true}
`('Snowplow tracking event', ({ selectedTarget, formSubmitted, eventSent }) => {
beforeEach(() => {
findSelect().vm.$emit('input', selectedTarget);
if (formSubmitted) {
const form = document.getElementById(NEW_PROJECT_FORM);
form.dispatchEvent(new Event('submit'));
}
});
if (eventSent) {
it(`is sent, when the the selectedTarget is ${selectedTarget} and the formSubmitted is ${formSubmitted} `, () => {
expect(trackingSpy).toHaveBeenCalledWith(undefined, DEPLOYMENT_TARGET_EVENT, {
label: DEPLOYMENT_TARGET_LABEL,
property: selectedTarget,
});
});
} else {
it(`is not sent, when the the selectedTarget is ${selectedTarget} and the formSubmitted is ${formSubmitted} `, () => {
expect(trackingSpy).toHaveBeenCalledTimes(0);
});
}
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment