Status badge (#454)

* Add status badge display

* Add storybook entries for dot/badge
This commit is contained in:
Rijk van Zanten
2020-04-22 16:18:25 -04:00
committed by GitHub
parent 96db381fbf
commit d7b3a2573d
9 changed files with 250 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
import DisplayIcon from './icon/';
import DisplayFormatTitle from './format-title/';
import DisplayStatusDot from './status-dot/';
import DisplayStatusBadge from './status-badge/';
export const displays = [DisplayIcon, DisplayFormatTitle, DisplayStatusDot];
export const displays = [DisplayIcon, DisplayFormatTitle, DisplayStatusDot, DisplayStatusBadge];
export default displays;

View File

@@ -0,0 +1,11 @@
import { defineDisplay } from '@/displays/define';
import DisplayStatusBadge from './status-badge.vue';
export default defineDisplay(({ i18n }) => ({
id: 'status-badge',
name: i18n.t('status_badge'),
types: ['status'],
icon: 'box',
handler: DisplayStatusBadge,
options: null,
}));

View File

@@ -0,0 +1,4 @@
# Status Badge
Renders the set status formatted according to the status mapping set in the interface options.

View File

@@ -0,0 +1,53 @@
import withPadding from '../../../.storybook/decorators/with-padding';
import { withKnobs, text, object } from '@storybook/addon-knobs';
import readme from './readme.md';
import { defineComponent } from '@vue/composition-api';
export default {
title: 'Displays / Status (Badge)',
decorators: [withPadding, withKnobs],
parameters: {
notes: readme,
},
};
const defaultStatusMapping = {
published: {
name: 'Published',
value: 'published',
text_color: '#fff',
background_color: 'var(--primary)',
},
draft: {
name: 'Draft',
value: 'draft',
text_color: 'var(--primary-subdued)',
background_color: 'var(--background-subdued)',
},
deleted: {
name: 'Deleted',
value: 'deleted',
text_color: 'var(--danger)',
background_color: 'var(--danger-alt)',
},
};
export const basic = () =>
defineComponent({
props: {
value: {
default: text('Value', 'published'),
},
statusMapping: {
default: object('Status Mapping', defaultStatusMapping),
},
},
template: `
<display-status-badge
:value="value"
:interface-options="{
status_mapping: statusMapping,
}"
/>
`,
});

View File

@@ -0,0 +1,75 @@
import DisplayStatusBadge from './status-badge.vue';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import VIcon from '@/components/v-icon';
import VueCompositionAPI from '@vue/composition-api';
import Tooltip from '@/directives/tooltip';
const localVue = createLocalVue();
localVue.component('v-icon', VIcon);
localVue.use(VueCompositionAPI);
localVue.directive('tooltip', Tooltip);
describe('Displays / Status Badge', () => {
it('Renders an empty span if no value is passed', () => {
const component = shallowMount(DisplayStatusBadge, {
localVue,
propsData: {
value: null,
},
});
expect(component.find('span').exists()).toBe(true);
expect(component.find('span').text()).toBe('');
});
it('Renders a question mark icon is status is unknown in interface options', () => {
const component = shallowMount(DisplayStatusBadge, {
localVue,
propsData: {
value: 'draft',
interfaceOptions: {
status_mapping: {
published: {},
},
},
},
});
expect(component.find(VIcon).exists()).toBe(true);
expect(component.attributes('name')).toBe('help_outline');
});
it('Renders the badge with the correct colors', () => {
const component = shallowMount(DisplayStatusBadge, {
localVue,
propsData: {
value: 'draft',
interfaceOptions: {
status_mapping: {
draft: {
background_color: 'rgb(171, 202, 188)',
text_color: 'rgb(150, 100, 125)',
},
},
},
},
});
expect(component.exists()).toBe(true);
expect(component.attributes('style')).toBe(
'background-color: rgb(171, 202, 188); color: rgb(150, 100, 125);'
);
});
it('Sets status to null if interface options are missing', () => {
const component = shallowMount(DisplayStatusBadge, {
localVue,
propsData: {
value: 'draft',
interfaceOptions: null,
},
});
expect((component.vm as any).status).toBe(null);
});
});

View File

@@ -0,0 +1,50 @@
<template>
<span v-if="!value" />
<v-icon name="help_outline" v-else-if="!status" />
<div
v-else
class="badge"
:style="{
backgroundColor: status.background_color,
color: status.text_color,
}"
>
{{ status.name }}
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from '@vue/composition-api';
export default defineComponent({
props: {
value: {
type: String,
default: null,
},
interfaceOptions: {
type: Object,
default: null,
},
},
setup(props) {
const status = computed(() => {
if (props.interfaceOptions === null) return null;
return props.interfaceOptions.status_mapping?.[props.value];
});
return { status };
},
});
</script>
<style lang="scss" scoped>
.badge {
display: inline-block;
padding: 8px;
color: var(--foreground-inverted);
line-height: 1;
border-radius: var(--border-radius);
}
</style>

View File

@@ -0,0 +1,53 @@
import withPadding from '../../../.storybook/decorators/with-padding';
import { withKnobs, text, object } from '@storybook/addon-knobs';
import readme from './readme.md';
import { defineComponent } from '@vue/composition-api';
export default {
title: 'Displays / Status (Dot)',
decorators: [withPadding, withKnobs],
parameters: {
notes: readme,
},
};
const defaultStatusMapping = {
published: {
name: 'Published',
value: 'published',
text_color: '#fff',
background_color: 'var(--primary)',
},
draft: {
name: 'Draft',
value: 'draft',
text_color: 'var(--primary-subdued)',
background_color: 'var(--background-subdued)',
},
deleted: {
name: 'Deleted',
value: 'deleted',
text_color: 'var(--danger)',
background_color: 'var(--danger-alt)',
},
};
export const basic = () =>
defineComponent({
props: {
value: {
default: text('Value', 'published'),
},
statusMapping: {
default: object('Status Mapping', defaultStatusMapping),
},
},
template: `
<display-status-dot
:value="value"
:interface-options="{
status_mapping: statusMapping,
}"
/>
`,
});

View File

@@ -1,6 +1,6 @@
<template>
<span v-if="!value" />
<v-icon name="help_outline" v-else-if="!status" />
<v-icon name="help_outline" small v-else-if="!status" />
<div
v-else
class="dot"

View File

@@ -273,6 +273,7 @@
"select_statuses": "Select Statuses",
"status_dot": "Status (Dot)",
"status_badge": "Status (Badge)",
"about_directus": "About Directus",
"activity_log": "Activity Log",