Commit 24a67257 authored by Phil Hughes's avatar Phil Hughes

Adds support for level 1 icons in MR widget extensions

Changes the status icon in the current extension to match
the new design.

Closes https://gitlab.com/gitlab-org/gitlab/-/issues/341042
parent 5eaaf70a
<script>
import { GlButton, GlLoadingIcon, GlIcon, GlLink, GlBadge, GlSafeHtmlDirective } from '@gitlab/ui';
import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue';
import StatusIcon from '../mr_widget_status_icon.vue';
import { EXTENSION_ICON_CLASS } from '../../constants';
import StatusIcon from './status_icon.vue';
export const LOADING_STATES = {
collapsedLoading: 'collapsedLoading',
......@@ -45,14 +46,6 @@ export default {
return true;
},
statusIconName() {
if (this.isLoadingSummary) {
return 'loading';
}
if (this.loadingState === LOADING_STATES.collapsedError) {
return 'warning';
}
return this.statusIcon(this.collapsedData);
},
},
......@@ -96,13 +89,18 @@ export default {
});
},
},
EXTENSION_ICON_CLASS,
};
</script>
<template>
<section class="media-section mr-widget-border-top">
<div class="media gl-p-5">
<status-icon :status="statusIconName" class="align-self-center" />
<status-icon
:name="$options.name"
:is-loading="isLoadingSummary"
:icon-name="statusIconName"
/>
<div class="media-body d-flex flex-align-self-center align-items-center">
<div class="code-text">
<template v-if="isLoadingSummary">
......
<script>
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { EXTENSION_ICON_CLASS, EXTENSION_ICONS } from '../../constants';
export default {
components: {
GlLoadingIcon,
GlIcon,
},
props: {
name: {
type: String,
required: true,
},
isLoading: {
type: Boolean,
required: true,
},
iconName: {
type: String,
required: true,
},
},
computed: {
iconAriaLabel() {
const statusLabel = Object.keys(EXTENSION_ICONS).find(
(k) => EXTENSION_ICONS[k] === this.iconName,
);
return `${capitalizeFirstCharacter(statusLabel)} ${this.name}`;
},
},
EXTENSION_ICON_CLASS,
};
</script>
<template>
<div
:class="[$options.EXTENSION_ICON_CLASS[iconName], { 'mr-widget-extension-icon': !isLoading }]"
class="align-self-center gl-rounded-full gl-mr-3 gl-relative gl-p-2"
>
<gl-loading-icon v-if="isLoading" size="md" inline class="gl-display-block" />
<gl-icon
v-else
:name="iconName"
:size="16"
:aria-label="iconAriaLabel"
class="gl-display-block"
/>
</div>
</template>
......@@ -91,4 +91,19 @@ export const stateToTransitionMap = {
export const stateToComponentMap = {
[states.MERGING]: classStateMap[stateKey.merging],
};
export const EXTENSION_ICONS = {
failed: 'status-failed',
warning: 'status-alert',
success: 'status-success',
neutral: 'status-neutral',
};
export const EXTENSION_ICON_CLASS = {
[EXTENSION_ICONS.failed]: 'gl-text-red-500',
[EXTENSION_ICONS.warning]: 'gl-text-orange-500',
[EXTENSION_ICONS.success]: 'gl-text-green-500',
[EXTENSION_ICONS.neutral]: 'gl-text-gray-400',
};
export { STATE_MACHINE };
/* eslint-disable */
import { EXTENSION_ICONS } from '../constants';
import issuesCollapsedQuery from './issues_collapsed.query.graphql';
import issuesQuery from './issues.query.graphql';
export default {
// Give the extension a name
// Make it easier to track in Vue dev tools
name: 'WidgetIssues',
name: 'Issues',
// Add an array of props
// These then get mapped to values stored in the MR Widget store
props: ['targetProjectFullPath'],
......@@ -14,12 +15,12 @@ export default {
// Small summary text to be displayed in the collapsed state
// Receives the collapsed data as an argument
summary(count) {
return `<strong>${count}</strong> open issue`;
return 'Summary text';
},
// Status icon to be used next to the summary text
// Receives the collapsed data as an argument
statusIcon(count) {
return count > 0 ? 'warning' : 'success';
return EXTENSION_ICONS.warning;
},
},
methods: {
......
......@@ -1040,3 +1040,17 @@ $tabs-holder-z-index: 250;
margin-bottom: 1px;
}
}
.mr-widget-extension-icon::before {
@include gl-content-empty;
@include gl-absolute;
@include gl-left-0;
@include gl-top-0;
@include gl-opacity-3;
@include gl-border-solid;
@include gl-border-4;
@include gl-rounded-full;
width: 24px;
height: 24px;
}
import { GlIcon, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import StatusIcon from '~/vue_merge_request_widget/components/extensions/status_icon.vue';
let wrapper;
function factory(propsData = {}) {
wrapper = shallowMount(StatusIcon, {
propsData,
});
}
describe('MR widget extensions status icon', () => {
afterEach(() => {
wrapper.destroy();
});
it('renders loading icon', () => {
factory({ name: 'test', isLoading: true, iconName: 'status-failed' });
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
it('renders status icon', () => {
factory({ name: 'test', isLoading: false, iconName: 'status-failed' });
expect(wrapper.findComponent(GlIcon).exists()).toBe(true);
expect(wrapper.findComponent(GlIcon).props('name')).toBe('status-failed');
});
it('sets aria-label for status icon', () => {
factory({ name: 'test', isLoading: false, iconName: 'status-failed' });
expect(wrapper.findComponent(GlIcon).props('ariaLabel')).toBe('Failed test');
});
});
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