Commit 7f7a6d2d authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '13076-fix-over-triggering-cycle-analytics-stage-select-event' into 'master'

Fix select event triggering from cycle analytics stage

See merge request gitlab-org/gitlab!19729
parents bc94b5b1 8c74c7ec
<script>
import Icon from '~/vue_shared/components/icon.vue';
import { GlButton } from '@gitlab/ui';
export default {
name: 'StageCardListItem',
components: {
Icon,
GlButton,
},
props: {
isActive: {
type: Boolean,
required: true,
},
canEdit: {
type: Boolean,
default: false,
required: false,
},
},
};
</script>
<template>
<div
:class="{ active: isActive }"
class="stage-nav-item d-flex pl-4 pr-4 m-0 mb-1 ml-2 rounded border-color-default border-style-solid border-width-1px"
>
<slot></slot>
<div v-if="canEdit" class="dropdown">
<gl-button
:title="__('More actions')"
class="more-actions-toggle btn btn-transparent p-0"
data-toggle="dropdown"
>
<icon class="icon" name="ellipsis_v" />
</gl-button>
<ul class="more-actions-dropdown dropdown-menu dropdown-open-left">
<slot name="dropdown-options"></slot>
</ul>
</div>
</div>
</template>
<script> <script>
import StageCardListItem from './stage_card_list_item.vue';
export default { export default {
name: 'StageNavItem', name: 'StageNavItem',
components: {
StageCardListItem,
},
props: { props: {
isDefaultStage: { isDefaultStage: {
type: Boolean, type: Boolean,
...@@ -40,16 +35,16 @@ export default { ...@@ -40,16 +35,16 @@ export default {
hasValue() { hasValue() {
return this.value && this.value.length > 0; return this.value && this.value.length > 0;
}, },
editable() {
return this.isUserAllowed && this.canEdit;
},
}, },
}; };
</script> </script>
<template> <template>
<li @click="$emit('select')"> <li @click="$emit('select')">
<stage-card-list-item :is-active="isActive" :can-edit="editable"> <div
:class="{ active: isActive }"
class="stage-nav-item d-flex pl-4 pr-4 m-0 mb-1 ml-2 rounded border-color-default border-style-solid border-width-1px"
>
<div class="stage-nav-item-cell stage-name p-0" :class="{ 'font-weight-bold': isActive }"> <div class="stage-nav-item-cell stage-name p-0" :class="{ 'font-weight-bold': isActive }">
{{ title }} {{ title }}
</div> </div>
...@@ -62,27 +57,6 @@ export default { ...@@ -62,27 +57,6 @@ export default {
<span class="not-available">{{ __('Not available') }}</span> <span class="not-available">{{ __('Not available') }}</span>
</template> </template>
</div> </div>
<template v-slot:dropdown-options> </div>
<template v-if="isDefaultStage">
<li>
<button type="button" class="btn-default btn-transparent">
{{ __('Hide stage') }}
</button>
</li>
</template>
<template v-else>
<li>
<button type="button" class="btn-default btn-transparent">
{{ __('Edit stage') }}
</button>
</li>
<li>
<button type="button" class="btn-danger danger">
{{ __('Remove stage') }}
</button>
</li>
</template>
</template>
</stage-card-list-item>
</li> </li>
</template> </template>
<script> <script>
import Icon from '~/vue_shared/components/icon.vue';
import { GlButton } from '@gitlab/ui';
export default { export default {
name: 'StageCardListItem', name: 'StageCardListItem',
components: {
Icon,
GlButton,
},
props: { props: {
isActive: { isActive: {
type: Boolean, type: Boolean,
...@@ -34,17 +27,5 @@ export default { ...@@ -34,17 +27,5 @@ export default {
class="stage-nav-item d-flex pl-4 pr-4 m-0 mb-1 ml-2 rounded border-width-1px border-style-solid" class="stage-nav-item d-flex pl-4 pr-4 m-0 mb-1 ml-2 rounded border-width-1px border-style-solid"
> >
<slot></slot> <slot></slot>
<div v-if="canEdit" class="dropdown">
<gl-button
:title="__('More actions')"
class="more-actions-toggle btn btn-transparent p-0"
data-toggle="dropdown"
>
<icon class="icon" name="ellipsis_v" />
</gl-button>
<ul class="more-actions-dropdown dropdown-menu dropdown-open-left">
<slot name="dropdown-options"></slot>
</ul>
</div>
</div> </div>
</template> </template>
<script> <script>
import { GlButton } from '@gitlab/ui';
import StageCardListItem from './stage_card_list_item.vue'; import StageCardListItem from './stage_card_list_item.vue';
import Icon from '~/vue_shared/components/icon.vue';
export default { export default {
name: 'StageNavItem', name: 'StageNavItem',
components: { components: {
StageCardListItem, StageCardListItem,
Icon,
GlButton,
}, },
props: { props: {
isDefaultStage: { isDefaultStage: {
...@@ -32,6 +36,11 @@ export default { ...@@ -32,6 +36,11 @@ export default {
required: false, required: false,
}, },
}, },
data() {
return {
isHover: false,
};
},
computed: { computed: {
hasValue() { hasValue() {
return this.value && this.value.length > 0; return this.value && this.value.length > 0;
...@@ -40,11 +49,26 @@ export default { ...@@ -40,11 +49,26 @@ export default {
return this.canEdit; return this.canEdit;
}, },
}, },
methods: {
handleDropdownAction(action) {
this.$emit(action);
},
handleSelectStage(e) {
// we don't want to emit the select event when we click the more actions dropdown
// But we should still trigger the event if we click anywhere else in the list item
if (!this.$refs.dropdown.contains(e.target)) {
this.$emit('select');
}
},
handleHover(hoverState = false) {
this.isHover = hoverState;
},
},
}; };
</script> </script>
<template> <template>
<li @click="$emit('select')"> <li @click="handleSelectStage" @mouseover="handleHover(true)" @mouseleave="handleHover()">
<stage-card-list-item :is-active="isActive" :can-edit="editable"> <stage-card-list-item :is-active="isActive" :can-edit="editable">
<div class="stage-nav-item-cell stage-name p-0" :class="{ 'font-weight-bold': isActive }"> <div class="stage-nav-item-cell stage-name p-0" :class="{ 'font-weight-bold': isActive }">
{{ title }} {{ title }}
...@@ -53,27 +77,48 @@ export default { ...@@ -53,27 +77,48 @@ export default {
<span v-if="hasValue">{{ value }}</span> <span v-if="hasValue">{{ value }}</span>
<span v-else class="stage-empty">{{ __('Not enough data') }}</span> <span v-else class="stage-empty">{{ __('Not enough data') }}</span>
</div> </div>
<template v-slot:dropdown-options> <div v-show="canEdit && isHover" ref="dropdown" class="dropdown">
<gl-button
:title="__('More actions')"
class="more-actions-toggle btn btn-transparent p-0"
data-toggle="dropdown"
>
<icon class="icon" name="ellipsis_v" />
</gl-button>
<ul class="more-actions-dropdown dropdown-menu dropdown-open-left">
<template v-if="isDefaultStage"> <template v-if="isDefaultStage">
<li> <li>
<button type="button" class="btn-default btn-transparent"> <button
type="button"
class="btn-default btn-transparent"
@click="handleDropdownAction('hide', $event)"
>
{{ __('Hide stage') }} {{ __('Hide stage') }}
</button> </button>
</li> </li>
</template> </template>
<template v-else> <template v-else>
<li> <li>
<button type="button" class="btn-default btn-transparent"> <button
type="button"
class="btn-default btn-transparent"
@click="handleDropdownAction('edit', $event)"
>
{{ __('Edit stage') }} {{ __('Edit stage') }}
</button> </button>
</li> </li>
<li> <li>
<button type="button" class="btn-danger danger"> <button
type="button"
class="btn-danger danger"
@click="handleDropdownAction('remove', $event)"
>
{{ __('Remove stage') }} {{ __('Remove stage') }}
</button> </button>
</li> </li>
</template> </template>
</template> </ul>
</div>
</stage-card-list-item> </stage-card-list-item>
</li> </li>
</template> </template>
...@@ -133,45 +133,19 @@ describe('StageNavItem', () => { ...@@ -133,45 +133,19 @@ describe('StageNavItem', () => {
hasStageName(); hasStageName();
}); });
it('renders options menu', () => { it('does not render options menu', () => {
expect(wrapper.find('.more-actions-toggle').exists()).toBe(true); expect(wrapper.find('.more-actions-toggle').exists()).toBe(false);
}); });
describe('Default stages', () => {
beforeEach(() => {
wrapper = createComponent(
{ canEdit: true, isUserAllowed: true, isDefaultStage: true },
false,
);
});
it('can hide the stage', () => {
expect(wrapper.text()).toContain('Hide stage');
});
it('can not edit the stage', () => { it('can not edit the stage', () => {
expect(wrapper.text()).not.toContain('Edit stage'); expect(wrapper.text()).not.toContain('Edit stage');
}); });
it('can not remove the stage', () => { it('can not remove the stage', () => {
expect(wrapper.text()).not.toContain('Remove stage'); expect(wrapper.text()).not.toContain('Remove stage');
}); });
});
describe('Custom stages', () => {
beforeEach(() => {
wrapper = createComponent(
{ canEdit: true, isUserAllowed: true, isDefaultStage: false },
false,
);
});
it('can edit the stage', () => {
expect(wrapper.text()).toContain('Edit stage');
});
it('can remove the stage', () => {
expect(wrapper.text()).toContain('Remove stage');
});
it('can not hide the stage', () => { it('can not hide the stage', () => {
expect(wrapper.text()).not.toContain('Hide stage'); expect(wrapper.text()).not.toContain('Hide stage');
}); });
}); });
});
}); });
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