Commit 9db64056 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '335519-project-avatar-env-dashboard' into 'master'

Use GlAvatar in env dashboard project header

See merge request gitlab-org/gitlab!80776
parents a4821a75 3fcf9eda
<script> <script>
import { GlDropdown, GlDropdownItem, GlTooltipDirective, GlLink, GlIcon } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem, GlTooltipDirective, GlLink, GlIcon } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import ProjectAvatar from '~/vue_shared/components/deprecated_project_avatar/default.vue'; import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
export default { export default {
components: { components: {
...@@ -28,27 +28,44 @@ export default { ...@@ -28,27 +28,44 @@ export default {
removeProjectText: s__('EnvironmentsDashboard|Remove'), removeProjectText: s__('EnvironmentsDashboard|Remove'),
moreActionsText: s__('EnvironmentsDashboard|More actions'), moreActionsText: s__('EnvironmentsDashboard|More actions'),
avatarSize: 24,
}; };
</script> </script>
<template> <template>
<div <div
class="gl-display-flex gl-align-items-center page-title-holder text-secondary gl-justify-content-space-between pb-2 mb-3" class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-justify-content-space-between gl-pb-3 gl-mb-5 gl-border-b-solid gl-border-gray-100 gl-border-1"
> >
<div class="gl-display-flex gl-align-items-center"> <div class="gl-display-flex gl-align-items-center">
<project-avatar :project="project.namespace" :size="20" class="flex-shrink-0" /> <project-avatar
<gl-link class="js-namespace-link text-secondary" :href="`/${project.namespace.full_path}`"> :project-name="project.namespace.name"
<span class="js-namespace gl-mr-3"> {{ project.namespace.name }} </span> :project-avatar-url="project.namespace.avatar_url"
:size="$options.avatarSize"
class="gl-mr-3"
/>
<gl-link
class="gl-text-gray-500 gl-mr-3"
:href="`/${project.namespace.full_path}`"
data-testid="namespace-link"
>
{{ project.namespace.name }}
</gl-link> </gl-link>
<span class="gl-mr-3">&gt;</span> <span class="gl-mr-3">&gt;</span>
<project-avatar :project="project" :size="20" class="flex-shrink-0" />
<gl-link class="js-project-link text-secondary" :href="project.web_url"> <project-avatar
<span class="js-name gl-mr-3"> {{ project.name }} </span> :project-name="project.name"
:project-avatar-url="project.avatar_url"
:size="$options.avatarSize"
class="gl-mr-3"
/>
<gl-link class="gl-text-gray-500 gl-mr-3" :href="project.web_url" data-testid="project-link">
{{ project.name }}
</gl-link> </gl-link>
</div> </div>
<div class="gl-display-flex js-more-actions"> <div class="gl-display-flex">
<gl-dropdown <gl-dropdown
toggle-class="js-more-actions-toggle gl-display-flex gl-align-items-center gl-px-3! gl-bg-transparent gl-shadow-none!" toggle-class="gl-display-flex gl-align-items-center gl-px-3! gl-bg-transparent gl-shadow-none!"
right right
> >
<template #button-content> <template #button-content>
...@@ -56,11 +73,11 @@ export default { ...@@ -56,11 +73,11 @@ export default {
v-gl-tooltip v-gl-tooltip
:title="$options.moreActionsText" :title="$options.moreActionsText"
name="ellipsis_v" name="ellipsis_v"
class="text-secondary" class="gl-text-gray-500"
/> />
</template> </template>
<gl-dropdown-item class="js-remove-button" variant="link" @click="onRemove()"> <gl-dropdown-item variant="link" data-testid="remove-project-button" @click="onRemove()">
<span class="text-danger"> {{ $options.removeProjectText }} </span> <span class="gl-text-red-500"> {{ $options.removeProjectText }} </span>
</gl-dropdown-item> </gl-dropdown-item>
</gl-dropdown> </gl-dropdown>
</div> </div>
......
...@@ -2,26 +2,26 @@ ...@@ -2,26 +2,26 @@
exports[`Project Header matches the snapshot 1`] = ` exports[`Project Header matches the snapshot 1`] = `
<div <div
class="gl-display-flex gl-align-items-center page-title-holder text-secondary gl-justify-content-space-between pb-2 mb-3" class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-justify-content-space-between gl-pb-3 gl-mb-5 gl-border-b-solid gl-border-gray-100 gl-border-1"
> >
<div <div
class="gl-display-flex gl-align-items-center" class="gl-display-flex gl-align-items-center"
> >
<project-avatar-stub <project-avatar-stub
class="flex-shrink-0" class="gl-mr-3"
project="[object Object]" projectavatarurl="/namespace-avatar"
size="20" projectname="hello"
size="24"
/> />
<gl-link-stub <gl-link-stub
class="js-namespace-link text-secondary" class="gl-text-gray-500 gl-mr-3"
data-testid="namespace-link"
href="/hello" href="/hello"
> >
<span
class="js-namespace gl-mr-3"
>
hello hello
</span>
</gl-link-stub> </gl-link-stub>
<span <span
...@@ -31,24 +31,24 @@ exports[`Project Header matches the snapshot 1`] = ` ...@@ -31,24 +31,24 @@ exports[`Project Header matches the snapshot 1`] = `
</span> </span>
<project-avatar-stub <project-avatar-stub
class="flex-shrink-0" class="gl-mr-3"
project="[object Object]" projectavatarurl="/project-avatar"
size="20" projectname="world"
size="24"
/> />
<gl-link-stub <gl-link-stub
class="js-project-link text-secondary" class="gl-text-gray-500 gl-mr-3"
> data-testid="project-link"
<span
class="js-name gl-mr-3"
> >
world world
</span>
</gl-link-stub> </gl-link-stub>
</div> </div>
<div <div
class="gl-display-flex js-more-actions" class="gl-display-flex"
> >
<gl-dropdown-stub <gl-dropdown-stub
category="primary" category="primary"
...@@ -61,13 +61,13 @@ exports[`Project Header matches the snapshot 1`] = ` ...@@ -61,13 +61,13 @@ exports[`Project Header matches the snapshot 1`] = `
right="true" right="true"
size="medium" size="medium"
text="" text=""
toggleclass="js-more-actions-toggle gl-display-flex gl-align-items-center gl-px-3! gl-bg-transparent gl-shadow-none!" toggleclass="gl-display-flex gl-align-items-center gl-px-3! gl-bg-transparent gl-shadow-none!"
variant="default" variant="default"
> >
<gl-dropdown-item-stub <gl-dropdown-item-stub
avatarurl="" avatarurl=""
class="js-remove-button" data-testid="remove-project-button"
iconcolor="" iconcolor=""
iconname="" iconname=""
iconrightarialabel="" iconrightarialabel=""
...@@ -76,7 +76,7 @@ exports[`Project Header matches the snapshot 1`] = ` ...@@ -76,7 +76,7 @@ exports[`Project Header matches the snapshot 1`] = `
variant="link" variant="link"
> >
<span <span
class="text-danger" class="gl-text-red-500"
> >
Remove Remove
</span> </span>
......
import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import component from 'ee/environments_dashboard/components/dashboard/project_header.vue'; import component from 'ee/environments_dashboard/components/dashboard/project_header.vue';
import ProjectAvatar from '~/vue_shared/components/deprecated_project_avatar/default.vue'; import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
describe('Project Header', () => { const mockProject = {
let wrapper;
let propsData;
beforeEach(() => {
propsData = {
project: {
namespace: { namespace: {
name: 'hello', name: 'hello',
full_path: 'hello', full_path: 'hello',
avatar_url: '/namespace-avatar',
}, },
name: 'world', name: 'world',
remove_path: '/hello/world/remove', remove_path: '/hello/world/remove',
}, avatar_url: '/project-avatar',
}; };
});
describe('Project Header', () => {
let wrapper;
const findRemoveButton = () =>
wrapper
.findComponent(GlDropdown)
.findAllComponents(GlDropdownItem)
.filter((w) => w.text() === 'Remove');
beforeEach(() => { beforeEach(() => {
wrapper = shallowMount(component, { wrapper = shallowMountExtended(component, {
propsData, propsData: { project: mockProject },
}); });
}); });
...@@ -38,50 +41,46 @@ describe('Project Header', () => { ...@@ -38,50 +41,46 @@ describe('Project Header', () => {
describe('renders project namespace, name, and avatars', () => { describe('renders project namespace, name, and avatars', () => {
it('shows the project namespace avatar', () => { it('shows the project namespace avatar', () => {
const projectNamespaceAvatar = wrapper.findAllComponents(ProjectAvatar).at(0); const projectNamespaceAvatar = wrapper.findAllComponents(ProjectAvatar).at(0);
expect(projectNamespaceAvatar.props('project')).toEqual(propsData.project.namespace); expect(projectNamespaceAvatar.props()).toMatchObject({
projectName: mockProject.namespace.name,
projectAvatarUrl: mockProject.namespace.avatar_url,
}); });
it('shows the project namespace', () => {
expect(wrapper.find('.js-namespace').text()).toBe(propsData.project.namespace.name);
}); });
it('links to the project namespace', () => { it('links to the project namespace', () => {
const expectedUrl = `/${propsData.project.namespace.full_path}`; const expectedUrl = `/${mockProject.namespace.full_path}`;
expect(wrapper.find('.js-namespace-link').attributes('href')).toBe(expectedUrl); const namespaceLink = wrapper.findByTestId('namespace-link');
expect(namespaceLink.attributes('href')).toBe(expectedUrl);
expect(namespaceLink.text()).toMatchInterpolatedText(mockProject.namespace.name);
}); });
it('shows the project avatar', () => { it('shows the project avatar', () => {
const projectAvatar = wrapper.findAllComponents(ProjectAvatar).at(1); const projectAvatar = wrapper.findAllComponents(ProjectAvatar).at(1);
expect(projectAvatar.props('project')).toEqual(propsData.project); expect(projectAvatar.props()).toMatchObject({
projectName: mockProject.name,
projectAvatarUrl: mockProject.avatar_url,
}); });
it('shows the project name', () => {
expect(wrapper.find('.js-name').text()).toBe(propsData.project.name);
}); });
it('links to the project', () => { it('links to the project', () => {
expect(wrapper.find('.js-project-link').attributes('href')).toBe(propsData.project.web_url); const projectLink = wrapper.findByTestId('project-link');
expect(projectLink.attributes('href')).toBe(mockProject.web_url);
expect(projectLink.text()).toMatchInterpolatedText(mockProject.name);
}); });
}); });
describe('more actions', () => { describe('more actions', () => {
it('should list "remove" as an action', () => { it('should list "remove" as an action', () => {
const removeLink = wrapper expect(findRemoveButton().exists()).toBe(true);
.findComponent(GlDropdown)
.findAllComponents(GlDropdownItem)
.filter((w) => w.text() === 'Remove');
expect(removeLink.exists()).toBe(true);
}); });
it('should emit a "remove" event when "remove" is clicked', async () => { it('should emit a "remove" event when "remove" is clicked', async () => {
const removeLink = wrapper findRemoveButton().at(0).vm.$emit('click');
.findComponent(GlDropdown)
.findAllComponents(GlDropdownItem)
.filter((w) => w.text() === 'Remove');
removeLink.at(0).vm.$emit('click');
await nextTick(); await nextTick();
expect(wrapper.emitted('remove')).toContainEqual([propsData.project.remove_path]);
expect(wrapper.emitted('remove')).toContainEqual([mockProject.remove_path]);
}); });
}); });
}); });
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