Commit 55621154 authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '164-add-deprecation-notice-to-the-ui' into 'master'

Add deprecation notice to the Serverless UI

See merge request gitlab-org/gitlab!80233
parents 6aa8c3ae 127a4c15
import ServerlessBundle from '~/serverless/serverless_bundle'; import ServerlessBundle from '~/serverless/serverless_bundle';
import initServerlessSurveyBanner from '~/serverless/survey_banner';
initServerlessSurveyBanner();
new ServerlessBundle(); // eslint-disable-line no-new new ServerlessBundle(); // eslint-disable-line no-new
<script> <script>
import { GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui'; import { GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
import { mapState } from 'vuex'; import { mapState } from 'vuex';
import { s__ } from '~/locale';
import { DEPRECATION_POST_LINK } from '../constants';
export default { export default {
components: { components: {
...@@ -8,6 +10,13 @@ export default { ...@@ -8,6 +10,13 @@ export default {
GlLink, GlLink,
GlSprintf, GlSprintf,
}, },
i18n: {
title: s__('Serverless|Getting started with serverless'),
description: s__(
'Serverless|Serverless was %{postLinkStart}deprecated%{postLinkEnd}. But if you opt to use it, you must install Knative in your Kubernetes cluster first. %{linkStart}Learn more.%{linkEnd}',
),
},
deprecationPostLink: DEPRECATION_POST_LINK,
computed: { computed: {
...mapState(['emptyImagePath', 'helpPath']), ...mapState(['emptyImagePath', 'helpPath']),
}, },
...@@ -15,18 +24,12 @@ export default { ...@@ -15,18 +24,12 @@ export default {
</script> </script>
<template> <template>
<gl-empty-state <gl-empty-state :svg-path="emptyImagePath" :title="$options.i18n.title">
:svg-path="emptyImagePath"
:title="s__('Serverless|Getting started with serverless')"
>
<template #description> <template #description>
<gl-sprintf <gl-sprintf :message="$options.i18n.description">
:message=" <template #postLink="{ content }">
s__( <gl-link :href="$options.deprecationPostLink" target="_blank">{{ content }}</gl-link>
'Serverless|In order to start using functions as a service, you must first install Knative on your Kubernetes cluster. %{linkStart}More information%{linkEnd}', </template>
)
"
>
<template #link="{ content }"> <template #link="{ content }">
<gl-link :href="helpPath">{{ content }}</gl-link> <gl-link :href="helpPath">{{ content }}</gl-link>
</template> </template>
......
<script> <script>
import { GlLink, GlLoadingIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; import {
GlLink,
GlAlert,
GlSprintf,
GlLoadingIcon,
GlSafeHtmlDirective as SafeHtml,
} from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import { sprintf, s__ } from '~/locale'; import { sprintf, s__ } from '~/locale';
import { CHECKING_INSTALLED } from '../constants'; import { CHECKING_INSTALLED, DEPRECATION_POST_LINK } from '../constants';
import EmptyState from './empty_state.vue'; import EmptyState from './empty_state.vue';
import EnvironmentRow from './environment_row.vue'; import EnvironmentRow from './environment_row.vue';
...@@ -11,11 +17,14 @@ export default { ...@@ -11,11 +17,14 @@ export default {
EnvironmentRow, EnvironmentRow,
EmptyState, EmptyState,
GlLink, GlLink,
GlAlert,
GlSprintf,
GlLoadingIcon, GlLoadingIcon,
}, },
directives: { directives: {
SafeHtml, SafeHtml,
}, },
deprecationPostLink: DEPRECATION_POST_LINK,
computed: { computed: {
...mapState(['installed', 'isLoading', 'hasFunctionData', 'helpPath', 'statusPath']), ...mapState(['installed', 'isLoading', 'hasFunctionData', 'helpPath', 'statusPath']),
...mapGetters(['getFunctions']), ...mapGetters(['getFunctions']),
...@@ -65,6 +74,17 @@ export default { ...@@ -65,6 +74,17 @@ export default {
<template> <template>
<section id="serverless-functions" class="flex-grow"> <section id="serverless-functions" class="flex-grow">
<gl-alert class="gl-mt-6" variant="warning" :dismissible="false">
<gl-sprintf
:message="s__('Serverless|Serverless was %{linkStart}deprecated%{linkEnd} in GitLab 14.3.')"
><template #link="{ content }"
><gl-link :href="$options.deprecationPostLink" target="_blank">{{
content
}}</gl-link></template
></gl-sprintf
>
</gl-alert>
<gl-loading-icon v-if="checkingInstalled" size="lg" class="gl-mt-3 gl-mb-3" /> <gl-loading-icon v-if="checkingInstalled" size="lg" class="gl-mt-3 gl-mb-3" />
<div v-else-if="isInstalled"> <div v-else-if="isInstalled">
......
...@@ -5,3 +5,6 @@ export const X_INTERVAL = 5; // Reflects the number of verticle bars on the x-ax ...@@ -5,3 +5,6 @@ export const X_INTERVAL = 5; // Reflects the number of verticle bars on the x-ax
export const CHECKING_INSTALLED = 'checking'; // The backend is still determining whether or not Knative is installed export const CHECKING_INSTALLED = 'checking'; // The backend is still determining whether or not Knative is installed
export const TIMEOUT = 'timeout'; export const TIMEOUT = 'timeout';
export const DEPRECATION_POST_LINK =
'https://about.gitlab.com/releases/2021/09/22/gitlab-14-3-released/#gitlab-serverless';
import Vue from 'vue';
import { setUrlParams } from '~/lib/utils/url_utility';
import SurveyBanner from './survey_banner.vue';
let bannerInstance;
const SURVEY_URL_BASE = 'https://gitlab.fra1.qualtrics.com/jfe/form/SV_00PfofFfY9s8Shf';
export default function initServerlessSurveyBanner() {
const el = document.querySelector('.js-serverless-survey-banner');
if (el && !bannerInstance) {
const { userName, userEmail } = el.dataset;
// pre-populate survey fields
const surveyUrl = setUrlParams(
{
Q_PopulateResponse: JSON.stringify({
QID1: userEmail,
QID2: userName,
QID16: '1', // selects "yes" to "do you currently use GitLab?"
}),
},
SURVEY_URL_BASE,
);
bannerInstance = new Vue({
el,
render(createElement) {
return createElement(SurveyBanner, {
props: {
surveyUrl,
},
});
},
});
}
}
<script>
import { GlBanner } from '@gitlab/ui';
import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';
export default {
components: {
GlBanner,
},
props: {
surveyUrl: {
type: String,
required: true,
},
},
data() {
return {
visible: true,
};
},
created() {
if (parseBoolean(getCookie('hide_serverless_survey'))) {
this.visible = false;
}
},
methods: {
handleClose() {
setCookie('hide_serverless_survey', 'true', { expires: 365 * 10 });
this.visible = false;
},
},
};
</script>
<template>
<gl-banner
v-if="visible"
class="mt-4"
:title="s__('Serverless|Help shape the future of Serverless at GitLab')"
:button-text="s__('Serverless|Sign up for First Look')"
:button-link="surveyUrl"
@close="handleClose"
>
<p>
{{
s__(
'Serverless|We are continually striving to improve our Serverless functionality. As a Knative user, we would love to hear how we can make this experience better for you. Sign up for GitLab First Look today and we will be in touch shortly.',
)
}}
</p>
</gl-banner>
</template>
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
.js-cluster-application-notice .js-cluster-application-notice
.flash-container .flash-container
.js-serverless-survey-banner{ data: { user_name: current_user.name, user_email: current_user.email } }
%h4.gl-my-5.gl-display-flex.gl-align-items-center %h4.gl-my-5.gl-display-flex.gl-align-items-center
= @cluster.name = @cluster.name
= gl_badge_tag cluster_type_label(@cluster.cluster_type), { variant: :info }, { class: 'gl-ml-3' } = gl_badge_tag cluster_type_label(@cluster.cluster_type), { variant: :info }, { class: 'gl-ml-3' }
......
...@@ -10,8 +10,6 @@ ...@@ -10,8 +10,6 @@
help_path: help_page_path('user/project/clusters/serverless/index'), help_path: help_page_path('user/project/clusters/serverless/index'),
empty_image_path: image_path('illustrations/empty-state/empty-serverless-lg.svg') } } empty_image_path: image_path('illustrations/empty-state/empty-serverless-lg.svg') } }
.js-serverless-survey-banner{ data: { user_name: current_user.name, user_email: current_user.email } }
.js-serverless-functions-notice .js-serverless-functions-notice
.flash-container .flash-container
......
...@@ -32966,22 +32966,19 @@ msgstr "" ...@@ -32966,22 +32966,19 @@ msgstr ""
msgid "Serverless|Getting started with serverless" msgid "Serverless|Getting started with serverless"
msgstr "" msgstr ""
msgid "Serverless|Help shape the future of Serverless at GitLab"
msgstr ""
msgid "Serverless|If you believe none of these apply, please check back later as the function data may be in the process of becoming available." msgid "Serverless|If you believe none of these apply, please check back later as the function data may be in the process of becoming available."
msgstr "" msgstr ""
msgid "Serverless|In order to start using functions as a service, you must first install Knative on your Kubernetes cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
msgid "Serverless|Learn more about Serverless" msgid "Serverless|Learn more about Serverless"
msgstr "" msgstr ""
msgid "Serverless|No functions available" msgid "Serverless|No functions available"
msgstr "" msgstr ""
msgid "Serverless|Sign up for First Look" msgid "Serverless|Serverless was %{linkStart}deprecated%{linkEnd} in GitLab 14.3."
msgstr ""
msgid "Serverless|Serverless was %{postLinkStart}deprecated%{postLinkEnd}. But if you opt to use it, you must install Knative in your Kubernetes cluster first. %{linkStart}Learn more.%{linkEnd}"
msgstr "" msgstr ""
msgid "Serverless|The deploy job has not finished." msgid "Serverless|The deploy job has not finished."
...@@ -32993,9 +32990,6 @@ msgstr "" ...@@ -32993,9 +32990,6 @@ msgstr ""
msgid "Serverless|There is currently no function data available from Knative. This could be for a variety of reasons including:" msgid "Serverless|There is currently no function data available from Knative. This could be for a variety of reasons including:"
msgstr "" msgstr ""
msgid "Serverless|We are continually striving to improve our Serverless functionality. As a Knative user, we would love to hear how we can make this experience better for you. Sign up for GitLab First Look today and we will be in touch shortly."
msgstr ""
msgid "Serverless|Your %{startTag}.gitlab-ci.yml%{endTag} file is not properly configured." msgid "Serverless|Your %{startTag}.gitlab-ci.yml%{endTag} file is not properly configured."
msgstr "" msgstr ""
......
...@@ -10,7 +10,7 @@ exports[`EmptyStateComponent should render content 1`] = ` ...@@ -10,7 +10,7 @@ exports[`EmptyStateComponent should render content 1`] = `
<h1 class=\\"gl-font-size-h-display gl-line-height-36 h4\\"> <h1 class=\\"gl-font-size-h-display gl-line-height-36 h4\\">
Getting started with serverless Getting started with serverless
</h1> </h1>
<p class=\\"gl-mt-3\\">In order to start using functions as a service, you must first install Knative on your Kubernetes cluster. <gl-link-stub href=\\"/help\\">More information</gl-link-stub> <p class=\\"gl-mt-3\\">Serverless was <gl-link-stub target=\\"_blank\\" href=\\"https://about.gitlab.com/releases/2021/09/22/gitlab-14-3-released/#gitlab-serverless\\">deprecated</gl-link-stub>. But if you opt to use it, you must install Knative in your Kubernetes cluster first. <gl-link-stub href=\\"/help\\">Learn more.</gl-link-stub>
</p> </p>
<div class=\\"gl-display-flex gl-flex-wrap gl-justify-content-center\\"> <div class=\\"gl-display-flex gl-flex-wrap gl-justify-content-center\\">
<!----> <!---->
......
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon, GlAlert, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue'; import Vue, { nextTick } from 'vue';
import AxiosMockAdapter from 'axios-mock-adapter'; import AxiosMockAdapter from 'axios-mock-adapter';
...@@ -25,6 +25,7 @@ describe('functionsComponent', () => { ...@@ -25,6 +25,7 @@ describe('functionsComponent', () => {
Vue.use(Vuex); Vue.use(Vuex);
store = createStore({}); store = createStore({});
component = shallowMount(functionsComponent, { store, stubs: { GlSprintf } });
}); });
afterEach(() => { afterEach(() => {
...@@ -32,23 +33,26 @@ describe('functionsComponent', () => { ...@@ -32,23 +33,26 @@ describe('functionsComponent', () => {
axiosMock.restore(); axiosMock.restore();
}); });
it('should render empty state when Knative is not installed', () => { it('should render deprecation notice', () => {
store.dispatch('receiveFunctionsSuccess', { knative_installed: false }); expect(component.findComponent(GlAlert).text()).toBe(
component = shallowMount(functionsComponent, { store }); 'Serverless was deprecated in GitLab 14.3.',
);
});
it('should render empty state when Knative is not installed', async () => {
await store.dispatch('receiveFunctionsSuccess', { knative_installed: false });
expect(component.find(EmptyState).exists()).toBe(true); expect(component.findComponent(EmptyState).exists()).toBe(true);
}); });
it('should render a loading component', () => { it('should render a loading component', async () => {
store.dispatch('requestFunctionsLoading'); await store.dispatch('requestFunctionsLoading');
component = shallowMount(functionsComponent, { store });
expect(component.find(GlLoadingIcon).exists()).toBe(true); expect(component.findComponent(GlLoadingIcon).exists()).toBe(true);
}); });
it('should render empty state when there is no function data', () => { it('should render empty state when there is no function data', async () => {
store.dispatch('receiveFunctionsNoDataSuccess', { knative_installed: true }); await store.dispatch('receiveFunctionsNoDataSuccess', { knative_installed: true });
component = shallowMount(functionsComponent, { store });
expect( expect(
component.vm.$el component.vm.$el
...@@ -61,14 +65,12 @@ describe('functionsComponent', () => { ...@@ -61,14 +65,12 @@ describe('functionsComponent', () => {
); );
}); });
it('should render functions and a loader when functions are partially fetched', () => { it('should render functions and a loader when functions are partially fetched', async () => {
store.dispatch('receiveFunctionsPartial', { await store.dispatch('receiveFunctionsPartial', {
...mockServerlessFunctions, ...mockServerlessFunctions,
knative_installed: 'checking', knative_installed: 'checking',
}); });
component = shallowMount(functionsComponent, { store });
expect(component.find('.js-functions-wrapper').exists()).toBe(true); expect(component.find('.js-functions-wrapper').exists()).toBe(true);
expect(component.find('.js-functions-loader').exists()).toBe(true); expect(component.find('.js-functions-loader').exists()).toBe(true);
}); });
...@@ -76,11 +78,9 @@ describe('functionsComponent', () => { ...@@ -76,11 +78,9 @@ describe('functionsComponent', () => {
it('should render the functions list', async () => { it('should render the functions list', async () => {
store = createStore({ clustersPath: 'clustersPath', helpPath: 'helpPath', statusPath }); store = createStore({ clustersPath: 'clustersPath', helpPath: 'helpPath', statusPath });
component = shallowMount(functionsComponent, { store });
await component.vm.$store.dispatch('receiveFunctionsSuccess', mockServerlessFunctions); await component.vm.$store.dispatch('receiveFunctionsSuccess', mockServerlessFunctions);
await nextTick(); await nextTick();
expect(component.find(EnvironmentRow).exists()).toBe(true); expect(component.findComponent(EnvironmentRow).exists()).toBe(true);
}); });
}); });
import { GlBanner } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Cookies from 'js-cookie';
import { nextTick } from 'vue';
import SurveyBanner from '~/serverless/survey_banner.vue';
describe('Knative survey banner', () => {
let wrapper;
function mountBanner() {
wrapper = shallowMount(SurveyBanner, {
propsData: {
surveyUrl: 'http://somesurvey.com/',
},
});
}
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('should render the banner when the cookie is absent', () => {
jest.spyOn(Cookies, 'get').mockReturnValue(undefined);
mountBanner();
expect(Cookies.get).toHaveBeenCalled();
expect(wrapper.find(GlBanner).exists()).toBe(true);
});
it('should close the banner and set a cookie when close button is clicked', async () => {
jest.spyOn(Cookies, 'get').mockReturnValue(undefined);
jest.spyOn(Cookies, 'set');
mountBanner();
expect(wrapper.find(GlBanner).exists()).toBe(true);
wrapper.find(GlBanner).vm.$emit('close');
await nextTick();
expect(Cookies.set).toHaveBeenCalledWith('hide_serverless_survey', 'true', {
expires: 3650,
secure: false,
});
expect(wrapper.find(GlBanner).exists()).toBe(false);
});
it('should not render the banner when the cookie is set', () => {
jest.spyOn(Cookies, 'get').mockReturnValue('true');
mountBanner();
expect(Cookies.get).toHaveBeenCalled();
expect(wrapper.find(GlBanner).exists()).toBe(false);
});
});
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