Commit 9667a0aa authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch '342697-ask-for-feedback-on-the-agent-listing-page' into 'master'

Ask for feedback on the Agent listing page

See merge request gitlab-org/gitlab!78567
parents 42fbc7c1 7257b683
<script> <script>
import { GlAlert, GlKeysetPagination, GlLoadingIcon } from '@gitlab/ui'; import { GlAlert, GlKeysetPagination, GlLoadingIcon, GlBanner } from '@gitlab/ui';
import { MAX_LIST_COUNT, ACTIVE_CONNECTION_TIME } from '../constants'; import { s__ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import {
MAX_LIST_COUNT,
ACTIVE_CONNECTION_TIME,
AGENT_FEEDBACK_ISSUE,
AGENT_FEEDBACK_KEY,
} from '../constants';
import getAgentsQuery from '../graphql/queries/get_agents.query.graphql'; import getAgentsQuery from '../graphql/queries/get_agents.query.graphql';
import AgentEmptyState from './agent_empty_state.vue'; import AgentEmptyState from './agent_empty_state.vue';
import AgentTable from './agent_table.vue'; import AgentTable from './agent_table.vue';
export default { export default {
i18n: {
feedbackBannerTitle: s__('ClusterAgents|Tell us what you think'),
feedbackBannerText: s__(
'ClusterAgents|We would love to learn more about your experience with the GitLab Agent.',
),
feedbackBannerButton: s__('ClusterAgents|Give feedback'),
error: s__('ClusterAgents|An error occurred while loading your Agents'),
},
AGENT_FEEDBACK_ISSUE,
AGENT_FEEDBACK_KEY,
apollo: { apollo: {
agents: { agents: {
query: getAgentsQuery, query: getAgentsQuery,
...@@ -31,7 +49,10 @@ export default { ...@@ -31,7 +49,10 @@ export default {
GlAlert, GlAlert,
GlKeysetPagination, GlKeysetPagination,
GlLoadingIcon, GlLoadingIcon,
GlBanner,
LocalStorageSync,
}, },
mixins: [glFeatureFlagMixin()],
inject: ['projectPath'], inject: ['projectPath'],
props: { props: {
defaultBranchName: { defaultBranchName: {
...@@ -57,6 +78,7 @@ export default { ...@@ -57,6 +78,7 @@ export default {
last: null, last: null,
}, },
folderList: {}, folderList: {},
feedbackBannerDismissed: false,
}; };
}, },
computed: { computed: {
...@@ -86,6 +108,12 @@ export default { ...@@ -86,6 +108,12 @@ export default {
treePageInfo() { treePageInfo() {
return this.agents?.project?.repository?.tree?.trees?.pageInfo || {}; return this.agents?.project?.repository?.tree?.trees?.pageInfo || {};
}, },
feedbackBannerEnabled() {
return this.glFeatures.showGitlabAgentFeedback;
},
feedbackBannerClasses() {
return this.isChildComponent ? 'gl-my-2' : 'gl-mb-4';
},
}, },
methods: { methods: {
reloadAgents() { reloadAgents() {
...@@ -142,6 +170,9 @@ export default { ...@@ -142,6 +170,9 @@ export default {
const count = this.agents?.project?.clusterAgents?.count; const count = this.agents?.project?.clusterAgents?.count;
this.$emit('onAgentsLoad', count); this.$emit('onAgentsLoad', count);
}, },
handleBannerClose() {
this.feedbackBannerDismissed = true;
},
}, },
}; };
</script> </script>
...@@ -151,6 +182,24 @@ export default { ...@@ -151,6 +182,24 @@ export default {
<section v-else-if="agentList"> <section v-else-if="agentList">
<div v-if="agentList.length"> <div v-if="agentList.length">
<local-storage-sync
v-if="feedbackBannerEnabled"
v-model="feedbackBannerDismissed"
:storage-key="$options.AGENT_FEEDBACK_KEY"
>
<gl-banner
v-if="!feedbackBannerDismissed"
variant="introduction"
:class="feedbackBannerClasses"
:title="$options.i18n.feedbackBannerTitle"
:button-text="$options.i18n.feedbackBannerButton"
:button-link="$options.AGENT_FEEDBACK_ISSUE"
@close="handleBannerClose"
>
<p>{{ $options.i18n.feedbackBannerText }}</p>
</gl-banner>
</local-storage-sync>
<agent-table <agent-table
:agents="agentList" :agents="agentList"
:default-branch-name="defaultBranchName" :default-branch-name="defaultBranchName"
...@@ -166,6 +215,6 @@ export default { ...@@ -166,6 +215,6 @@ export default {
</section> </section>
<gl-alert v-else variant="danger" :dismissible="false"> <gl-alert v-else variant="danger" :dismissible="false">
{{ s__('ClusterAgents|An error occurred while loading your GitLab Agents') }} {{ $options.i18n.error }}
</gl-alert> </gl-alert>
</template> </template>
...@@ -123,7 +123,7 @@ export default { ...@@ -123,7 +123,7 @@ export default {
<div v-show="!isLoading" data-testid="clusters-cards-container"> <div v-show="!isLoading" data-testid="clusters-cards-container">
<gl-card <gl-card
header-class="gl-bg-white gl-display-flex gl-align-items-center gl-justify-content-space-between gl-py-4" header-class="gl-bg-white gl-display-flex gl-align-items-center gl-justify-content-space-between gl-py-4"
body-class="gl-pb-0" body-class="gl-pb-0 cluster-card-item"
footer-class="gl-text-right" footer-class="gl-text-right"
> >
<template #header> <template #header>
...@@ -198,7 +198,7 @@ export default { ...@@ -198,7 +198,7 @@ export default {
<gl-card <gl-card
class="gl-mt-6" class="gl-mt-6"
header-class="gl-bg-white gl-display-flex gl-align-items-center gl-justify-content-space-between" header-class="gl-bg-white gl-display-flex gl-align-items-center gl-justify-content-space-between"
body-class="gl-pb-0" body-class="gl-pb-0 cluster-card-item"
footer-class="gl-text-right" footer-class="gl-text-right"
> >
<template #header> <template #header>
......
...@@ -267,3 +267,6 @@ export const MODAL_TYPE_EMPTY = 'empty_state'; ...@@ -267,3 +267,6 @@ export const MODAL_TYPE_EMPTY = 'empty_state';
export const MODAL_TYPE_REGISTER = 'agent_registration'; export const MODAL_TYPE_REGISTER = 'agent_registration';
export const DELETE_AGENT_MODAL_ID = 'delete-agent-modal-%{agentName}'; export const DELETE_AGENT_MODAL_ID = 'delete-agent-modal-%{agentName}';
export const AGENT_FEEDBACK_ISSUE = 'https://gitlab.com/gitlab-org/gitlab/-/issues/342696';
export const AGENT_FEEDBACK_KEY = 'agent_feedback_banner';
...@@ -7,13 +7,6 @@ ...@@ -7,13 +7,6 @@
} }
} }
.gl-card-body {
@include media-breakpoint-up(sm) {
@include gl-pt-2;
min-height: 372px;
}
}
@include media-breakpoint-down(xs) { @include media-breakpoint-down(xs) {
.nav-controls { .nav-controls {
@include gl-w-full; @include gl-w-full;
...@@ -27,6 +20,13 @@ ...@@ -27,6 +20,13 @@
} }
} }
.cluster-card-item {
@include media-breakpoint-up(sm) {
@include gl-pt-2;
min-height: 372px;
}
}
.agent-activity-list { .agent-activity-list {
.system-note .timeline-entry-inner { .system-note .timeline-entry-inner {
.timeline-icon { .timeline-icon {
......
...@@ -6,6 +6,7 @@ class Projects::ClustersController < Clusters::ClustersController ...@@ -6,6 +6,7 @@ class Projects::ClustersController < Clusters::ClustersController
before_action do before_action do
push_frontend_feature_flag(:prometheus_computed_alerts) push_frontend_feature_flag(:prometheus_computed_alerts)
push_frontend_feature_flag(:show_gitlab_agent_feedback, type: :ops, default_enabled: :yaml)
end end
layout 'project' layout 'project'
......
---
name: show_gitlab_agent_feedback
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78567
rollout_issue_url:
milestone: '14.8'
type: ops
group: group::configure
default_enabled: true
...@@ -7587,7 +7587,7 @@ msgstr "" ...@@ -7587,7 +7587,7 @@ msgstr ""
msgid "ClusterAgents|All" msgid "ClusterAgents|All"
msgstr "" msgstr ""
msgid "ClusterAgents|An error occurred while loading your GitLab Agents" msgid "ClusterAgents|An error occurred while loading your Agents"
msgstr "" msgstr ""
msgid "ClusterAgents|An error occurred while loading your agent" msgid "ClusterAgents|An error occurred while loading your agent"
...@@ -7674,6 +7674,9 @@ msgstr "" ...@@ -7674,6 +7674,9 @@ msgstr ""
msgid "ClusterAgents|GitLab Agent for Kubernetes" msgid "ClusterAgents|GitLab Agent for Kubernetes"
msgstr "" msgstr ""
msgid "ClusterAgents|Give feedback"
msgstr ""
msgid "ClusterAgents|Go to the repository files" msgid "ClusterAgents|Go to the repository files"
msgstr "" msgstr ""
...@@ -7758,6 +7761,9 @@ msgstr "" ...@@ -7758,6 +7761,9 @@ msgstr ""
msgid "ClusterAgents|Select an agent to register with GitLab" msgid "ClusterAgents|Select an agent to register with GitLab"
msgstr "" msgstr ""
msgid "ClusterAgents|Tell us what you think"
msgstr ""
msgid "ClusterAgents|The GitLab Agent provides an increased level of security when connecting Kubernetes clusters to GitLab. %{linkStart}Learn more about the GitLab Agent.%{linkEnd}" msgid "ClusterAgents|The GitLab Agent provides an increased level of security when connecting Kubernetes clusters to GitLab. %{linkStart}Learn more about the GitLab Agent.%{linkEnd}"
msgstr "" msgstr ""
...@@ -7799,6 +7805,9 @@ msgstr "" ...@@ -7799,6 +7805,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters" msgid "ClusterAgents|View all %{number} clusters"
msgstr "" msgstr ""
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
msgid "ClusterAgents|What is GitLab Agent activity?" msgid "ClusterAgents|What is GitLab Agent activity?"
msgstr "" msgstr ""
......
import { GlAlert, GlKeysetPagination, GlLoadingIcon } from '@gitlab/ui'; import { GlAlert, GlKeysetPagination, GlLoadingIcon, GlBanner } from '@gitlab/ui';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import AgentEmptyState from '~/clusters_list/components/agent_empty_state.vue'; import AgentEmptyState from '~/clusters_list/components/agent_empty_state.vue';
import AgentTable from '~/clusters_list/components/agent_table.vue'; import AgentTable from '~/clusters_list/components/agent_table.vue';
import Agents from '~/clusters_list/components/agents.vue'; import Agents from '~/clusters_list/components/agents.vue';
import { ACTIVE_CONNECTION_TIME } from '~/clusters_list/constants'; import {
ACTIVE_CONNECTION_TIME,
AGENT_FEEDBACK_KEY,
AGENT_FEEDBACK_ISSUE,
} from '~/clusters_list/constants';
import getAgentsQuery from '~/clusters_list/graphql/queries/get_agents.query.graphql'; import getAgentsQuery from '~/clusters_list/graphql/queries/get_agents.query.graphql';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(VueApollo); localVue.use(VueApollo);
...@@ -24,6 +29,7 @@ describe('Agents', () => { ...@@ -24,6 +29,7 @@ describe('Agents', () => {
const createWrapper = async ({ const createWrapper = async ({
props = {}, props = {},
glFeatures = {},
agents = [], agents = [],
pageInfo = null, pageInfo = null,
trees = [], trees = [],
...@@ -51,20 +57,29 @@ describe('Agents', () => { ...@@ -51,20 +57,29 @@ describe('Agents', () => {
...defaultProps, ...defaultProps,
...props, ...props,
}, },
provide: provideData, provide: {
...provideData,
glFeatures,
},
stubs: {
GlBanner,
LocalStorageSync,
},
}); });
await nextTick(); await nextTick();
}; };
const findAgentTable = () => wrapper.find(AgentTable); const findAgentTable = () => wrapper.findComponent(AgentTable);
const findEmptyState = () => wrapper.find(AgentEmptyState); const findEmptyState = () => wrapper.findComponent(AgentEmptyState);
const findPaginationButtons = () => wrapper.find(GlKeysetPagination); const findPaginationButtons = () => wrapper.findComponent(GlKeysetPagination);
const findAlert = () => wrapper.findComponent(GlAlert);
const findBanner = () => wrapper.findComponent(GlBanner);
afterEach(() => { afterEach(() => {
if (wrapper) { wrapper.destroy();
wrapper.destroy();
} localStorage.removeItem(AGENT_FEEDBACK_KEY);
}); });
describe('when there is a list of agents', () => { describe('when there is a list of agents', () => {
...@@ -150,6 +165,49 @@ describe('Agents', () => { ...@@ -150,6 +165,49 @@ describe('Agents', () => {
expect(wrapper.emitted().onAgentsLoad).toEqual([[count]]); expect(wrapper.emitted().onAgentsLoad).toEqual([[count]]);
}); });
describe.each`
featureFlagEnabled | localStorageItemExists | bannerShown
${true} | ${false} | ${true}
${true} | ${true} | ${false}
${false} | ${true} | ${false}
${false} | ${false} | ${false}
`(
'when the feature flag enabled is $featureFlagEnabled and dismissed localStorage item exists is $localStorageItemExists',
({ featureFlagEnabled, localStorageItemExists, bannerShown }) => {
const glFeatures = {
showGitlabAgentFeedback: featureFlagEnabled,
};
beforeEach(() => {
if (localStorageItemExists) {
localStorage.setItem(AGENT_FEEDBACK_KEY, true);
}
return createWrapper({ glFeatures, agents, count, trees });
});
it(`should ${bannerShown ? 'show' : 'hide'} the feedback banner`, () => {
expect(findBanner().exists()).toBe(bannerShown);
});
},
);
describe('when the agent feedback banner is present', () => {
const glFeatures = {
showGitlabAgentFeedback: true,
};
beforeEach(() => {
return createWrapper({ glFeatures, agents, count, trees });
});
it('should render the correct title', () => {
expect(findBanner().props('title')).toBe('Tell us what you think');
});
it('should render the correct issue link', () => {
expect(findBanner().props('buttonLink')).toBe(AGENT_FEEDBACK_ISSUE);
});
});
describe('when the agent has recently connected tokens', () => { describe('when the agent has recently connected tokens', () => {
it('should set agent status to active', () => { it('should set agent status to active', () => {
expect(findAgentTable().props('agents')).toMatchObject(expectedAgentsList); expect(findAgentTable().props('agents')).toMatchObject(expectedAgentsList);
...@@ -223,6 +281,10 @@ describe('Agents', () => { ...@@ -223,6 +281,10 @@ describe('Agents', () => {
expect(findAgentTable().exists()).toBe(false); expect(findAgentTable().exists()).toBe(false);
expect(findEmptyState().exists()).toBe(true); expect(findEmptyState().exists()).toBe(true);
}); });
it('should not show agent feedback alert', () => {
expect(findAlert().exists()).toBe(false);
});
}); });
describe('when agents query has errored', () => { describe('when agents query has errored', () => {
...@@ -231,7 +293,7 @@ describe('Agents', () => { ...@@ -231,7 +293,7 @@ describe('Agents', () => {
}); });
it('displays an alert message', () => { it('displays an alert message', () => {
expect(wrapper.find(GlAlert).exists()).toBe(true); expect(findAlert().text()).toBe('An error occurred while loading your Agents');
}); });
}); });
......
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