Merge branch 'revert-feature-highlight' into 'master'
Revert feature highlight Closes #38087 See merge request gitlab-org/gitlab-ce!14373
This commit is contained in:
commit
8cf2f51ca2
13 changed files with 7 additions and 735 deletions
|
@ -1,61 +0,0 @@
|
||||||
import Cookies from 'js-cookie';
|
|
||||||
import _ from 'underscore';
|
|
||||||
import {
|
|
||||||
getCookieName,
|
|
||||||
getSelector,
|
|
||||||
hidePopover,
|
|
||||||
setupDismissButton,
|
|
||||||
mouseenter,
|
|
||||||
mouseleave,
|
|
||||||
} from './feature_highlight_helper';
|
|
||||||
|
|
||||||
export const setupFeatureHighlightPopover = (id, debounceTimeout = 300) => {
|
|
||||||
const $selector = $(getSelector(id));
|
|
||||||
const $parent = $selector.parent();
|
|
||||||
const $popoverContent = $parent.siblings('.feature-highlight-popover-content');
|
|
||||||
const hideOnScroll = hidePopover.bind($selector);
|
|
||||||
const debouncedMouseleave = _.debounce(mouseleave, debounceTimeout);
|
|
||||||
|
|
||||||
$selector
|
|
||||||
// Setup popover
|
|
||||||
.data('content', $popoverContent.prop('outerHTML'))
|
|
||||||
.popover({
|
|
||||||
html: true,
|
|
||||||
// Override the existing template to add custom CSS classes
|
|
||||||
template: `
|
|
||||||
<div class="popover feature-highlight-popover" role="tooltip">
|
|
||||||
<div class="arrow"></div>
|
|
||||||
<div class="popover-content"></div>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
})
|
|
||||||
.on('mouseenter', mouseenter)
|
|
||||||
.on('mouseleave', debouncedMouseleave)
|
|
||||||
.on('inserted.bs.popover', setupDismissButton)
|
|
||||||
.on('show.bs.popover', () => {
|
|
||||||
window.addEventListener('scroll', hideOnScroll);
|
|
||||||
})
|
|
||||||
.on('hide.bs.popover', () => {
|
|
||||||
window.removeEventListener('scroll', hideOnScroll);
|
|
||||||
})
|
|
||||||
// Display feature highlight
|
|
||||||
.removeAttr('disabled');
|
|
||||||
};
|
|
||||||
|
|
||||||
export const shouldHighlightFeature = (id) => {
|
|
||||||
const element = document.querySelector(getSelector(id));
|
|
||||||
const previouslyDismissed = Cookies.get(getCookieName(id)) === 'true';
|
|
||||||
|
|
||||||
return element && !previouslyDismissed;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const highlightFeatures = (highlightOrder) => {
|
|
||||||
const featureId = highlightOrder.find(shouldHighlightFeature);
|
|
||||||
|
|
||||||
if (featureId) {
|
|
||||||
setupFeatureHighlightPopover(featureId);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
|
@ -1,57 +0,0 @@
|
||||||
import Cookies from 'js-cookie';
|
|
||||||
|
|
||||||
export const getCookieName = cookieId => `feature-highlighted-${cookieId}`;
|
|
||||||
export const getSelector = highlightId => `.js-feature-highlight[data-highlight=${highlightId}]`;
|
|
||||||
|
|
||||||
export const showPopover = function showPopover() {
|
|
||||||
if (this.hasClass('js-popover-show')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.popover('show');
|
|
||||||
this.addClass('disable-animation js-popover-show');
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const hidePopover = function hidePopover() {
|
|
||||||
if (!this.hasClass('js-popover-show')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.popover('hide');
|
|
||||||
this.removeClass('disable-animation js-popover-show');
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const dismiss = function dismiss(cookieId) {
|
|
||||||
Cookies.set(getCookieName(cookieId), true);
|
|
||||||
hidePopover.call(this);
|
|
||||||
this.hide();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mouseleave = function mouseleave() {
|
|
||||||
if (!$('.popover:hover').length > 0) {
|
|
||||||
const $featureHighlight = $(this);
|
|
||||||
hidePopover.call($featureHighlight);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mouseenter = function mouseenter() {
|
|
||||||
const $featureHighlight = $(this);
|
|
||||||
|
|
||||||
const showedPopover = showPopover.call($featureHighlight);
|
|
||||||
if (showedPopover) {
|
|
||||||
$('.popover')
|
|
||||||
.on('mouseleave', mouseleave.bind($featureHighlight));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setupDismissButton = function setupDismissButton() {
|
|
||||||
const popoverId = this.getAttribute('aria-describedby');
|
|
||||||
const cookieId = this.dataset.highlight;
|
|
||||||
const $popover = $(this);
|
|
||||||
const dismissWrapper = dismiss.bind($popover, cookieId);
|
|
||||||
|
|
||||||
$(`#${popoverId} .dismiss-feature-highlight`)
|
|
||||||
.on('click', dismissWrapper);
|
|
||||||
};
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { highlightFeatures } from './feature_highlight';
|
|
||||||
import bp from '../breakpoints';
|
|
||||||
|
|
||||||
const highlightOrder = ['issue-boards'];
|
|
||||||
|
|
||||||
export default function domContentLoaded(order) {
|
|
||||||
if (bp.getBreakpointSize() === 'lg') {
|
|
||||||
highlightFeatures(order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', domContentLoaded.bind(this, highlightOrder));
|
|
|
@ -101,7 +101,6 @@ import './label_manager';
|
||||||
import './labels';
|
import './labels';
|
||||||
import './labels_select';
|
import './labels_select';
|
||||||
import './layout_nav';
|
import './layout_nav';
|
||||||
import './feature_highlight/feature_highlight_options';
|
|
||||||
import LazyLoader from './lazy_loader';
|
import LazyLoader from './lazy_loader';
|
||||||
import './line_highlighter';
|
import './line_highlighter';
|
||||||
import './logo';
|
import './logo';
|
||||||
|
|
|
@ -52,4 +52,3 @@
|
||||||
@import "framework/snippets";
|
@import "framework/snippets";
|
||||||
@import "framework/memory_graph";
|
@import "framework/memory_graph";
|
||||||
@import "framework/responsive-tables";
|
@import "framework/responsive-tables";
|
||||||
@import "framework/feature_highlight";
|
|
||||||
|
|
|
@ -46,15 +46,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin btn-svg {
|
|
||||||
svg {
|
|
||||||
height: 15px;
|
|
||||||
width: 15px;
|
|
||||||
position: relative;
|
|
||||||
top: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) {
|
@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) {
|
||||||
background-color: $light;
|
background-color: $light;
|
||||||
border-color: $border-light;
|
border-color: $border-light;
|
||||||
|
@ -132,7 +123,6 @@
|
||||||
.btn {
|
.btn {
|
||||||
@include btn-default;
|
@include btn-default;
|
||||||
@include btn-white;
|
@include btn-white;
|
||||||
@include btn-svg;
|
|
||||||
|
|
||||||
color: $gl-text-color;
|
color: $gl-text-color;
|
||||||
|
|
||||||
|
@ -231,6 +221,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
svg,
|
svg,
|
||||||
.fa {
|
.fa {
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
.feature-highlight {
|
|
||||||
position: relative;
|
|
||||||
margin-left: $gl-padding;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 6px;
|
|
||||||
left: 6px;
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
background-color: $blue-500;
|
|
||||||
border-radius: 50%;
|
|
||||||
box-shadow: 0 0 0 rgba($blue-500, 0.4);
|
|
||||||
animation: pulse-highlight 2s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover::before,
|
|
||||||
&.disable-animation::before {
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[disabled]::before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-showing-fly-out {
|
|
||||||
.feature-highlight {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-highlight-popover-content {
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
hr {
|
|
||||||
margin: $gl-padding * 0.5 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-link {
|
|
||||||
@include btn-svg;
|
|
||||||
|
|
||||||
svg path {
|
|
||||||
fill: currentColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dismiss-feature-highlight {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg:first-child {
|
|
||||||
width: 100%;
|
|
||||||
background-color: $indigo-50;
|
|
||||||
border-top-left-radius: 2px;
|
|
||||||
border-top-right-radius: 2px;
|
|
||||||
border-bottom: 1px solid darken($gray-normal, 8%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover .feature-highlight-popover-content {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-highlight-popover {
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
.popover-content {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.feature-highlight-popover-sub-content {
|
|
||||||
padding: 9px 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include keyframes(pulse-highlight) {
|
|
||||||
0% {
|
|
||||||
box-shadow: 0 0 0 0 rgba($blue-200, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
70% {
|
|
||||||
box-shadow: 0 0 0 10px transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
box-shadow: 0 0 0 0 transparent;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="214" height="102" viewBox="0 0 214 102" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
||||||
<defs>
|
|
||||||
<path id="b" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,27 C48,28.1045695 47.1045695,29 46,29 L2,29 C0.8954305,29 1.3527075e-16,28.1045695 0,27 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
|
||||||
<filter id="a" width="102.1%" height="106.9%" x="-1%" y="-1.7%" filterUnits="objectBoundingBox">
|
|
||||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
|
||||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
|
||||||
</filter>
|
|
||||||
<path id="d" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
|
||||||
<filter id="c" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
|
||||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
|
||||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
|
||||||
</filter>
|
|
||||||
<path id="e" d="M5,0 L53,0 C55.7614237,-5.07265313e-16 58,2.23857625 58,5 L58,91 C58,93.7614237 55.7614237,96 53,96 L5,96 C2.23857625,96 3.38176876e-16,93.7614237 0,91 L0,5 C-3.38176876e-16,2.23857625 2.23857625,5.07265313e-16 5,0 Z"/>
|
|
||||||
<path id="h" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
|
||||||
<filter id="g" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
|
||||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
|
||||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
|
||||||
</filter>
|
|
||||||
<path id="j" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
|
||||||
<filter id="i" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
|
||||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
|
||||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
|
||||||
</filter>
|
|
||||||
<path id="l" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
|
||||||
<filter id="k" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
|
||||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
|
||||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
|
||||||
</filter>
|
|
||||||
<path id="n" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
|
||||||
<filter id="m" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
|
||||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
|
||||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
|
||||||
</filter>
|
|
||||||
<path id="p" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
|
||||||
<filter id="o" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
|
||||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
|
||||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
<g fill="none" fill-rule="evenodd">
|
|
||||||
<path fill="#D6D4DE" d="M14,21 L62,21 C64.7614237,21 67,23.2385763 67,26 L67,112 C67,114.761424 64.7614237,117 62,117 L14,117 C11.2385763,117 9,114.761424 9,112 L9,26 C9,23.2385763 11.2385763,21 14,21 Z"/>
|
|
||||||
<g transform="translate(11 23)">
|
|
||||||
<path fill="#FFFFFF" d="M5,0 L53,0 C55.7614237,-5.07265313e-16 58,2.23857625 58,5 L58,91 C58,93.7614237 55.7614237,96 53,96 L5,96 C2.23857625,96 3.38176876e-16,93.7614237 0,91 L0,5 C-3.38176876e-16,2.23857625 2.23857625,5.07265313e-16 5,0 Z"/>
|
|
||||||
<path fill="#FC6D26" d="M4,0 L54,0 C56.209139,-4.05812251e-16 58,1.790861 58,4 L0,4 C-2.705415e-16,1.790861 1.790861,4.05812251e-16 4,0 Z"/>
|
|
||||||
<g transform="translate(5 10)">
|
|
||||||
<use fill="black" filter="url(#a)" xlink:href="#b"/>
|
|
||||||
<use fill="#F9F9F9" xlink:href="#b"/>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(5 42)">
|
|
||||||
<use fill="black" filter="url(#c)" xlink:href="#d"/>
|
|
||||||
<use fill="#FEF0E8" xlink:href="#d"/>
|
|
||||||
<path fill="#FEE1D3" d="M9,8 L33,8 C34.1045695,8 35,8.8954305 35,10 C35,11.1045695 34.1045695,12 33,12 L9,12 C7.8954305,12 7,11.1045695 7,10 C7,8.8954305 7.8954305,8 9,8 Z"/>
|
|
||||||
<path fill="#FDC4A8" d="M9,17 L17,17 C18.1045695,17 19,17.8954305 19,19 C19,20.1045695 18.1045695,21 17,21 L9,21 C7.8954305,21 7,20.1045695 7,19 C7,17.8954305 7.8954305,17 9,17 Z"/>
|
|
||||||
<path fill="#FC6D26" d="M24,17 L32,17 C33.1045695,17 34,17.8954305 34,19 C34,20.1045695 33.1045695,21 32,21 L24,21 C22.8954305,21 22,20.1045695 22,19 C22,17.8954305 22.8954305,17 24,17 Z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<path fill="#D6D4DE" d="M148,26 L196,26 C198.761424,26 201,28.2385763 201,31 L201,117 C201,119.761424 198.761424,122 196,122 L148,122 C145.238576,122 143,119.761424 143,117 L143,31 C143,28.2385763 145.238576,26 148,26 Z"/>
|
|
||||||
<g transform="translate(145 28)">
|
|
||||||
<mask id="f" fill="white">
|
|
||||||
<use xlink:href="#e"/>
|
|
||||||
</mask>
|
|
||||||
<use fill="#FFFFFF" xlink:href="#e"/>
|
|
||||||
<path fill="#FC6D26" d="M4,0 L54,0 C56.209139,-4.05812251e-16 58,1.790861 58,4 L0,4 C-2.705415e-16,1.790861 1.790861,4.05812251e-16 4,0 Z" mask="url(#f)"/>
|
|
||||||
<g transform="translate(5 10)">
|
|
||||||
<use fill="black" filter="url(#g)" xlink:href="#h"/>
|
|
||||||
<use fill="#F9F9F9" xlink:href="#h"/>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(5 42)">
|
|
||||||
<use fill="black" filter="url(#i)" xlink:href="#j"/>
|
|
||||||
<use fill="#FEF0E8" xlink:href="#j"/>
|
|
||||||
<path fill="#FEE1D3" d="M9 8L33 8C34.1045695 8 35 8.8954305 35 10 35 11.1045695 34.1045695 12 33 12L9 12C7.8954305 12 7 11.1045695 7 10 7 8.8954305 7.8954305 8 9 8zM9 17L13 17C14.1045695 17 15 17.8954305 15 19 15 20.1045695 14.1045695 21 13 21L9 21C7.8954305 21 7 20.1045695 7 19 7 17.8954305 7.8954305 17 9 17z"/>
|
|
||||||
<path fill="#FC6D26" d="M20,17 L24,17 C25.1045695,17 26,17.8954305 26,19 C26,20.1045695 25.1045695,21 24,21 L20,21 C18.8954305,21 18,20.1045695 18,19 C18,17.8954305 18.8954305,17 20,17 Z"/>
|
|
||||||
<path fill="#FDC4A8" d="M31,17 L35,17 C36.1045695,17 37,17.8954305 37,19 C37,20.1045695 36.1045695,21 35,21 L31,21 C29.8954305,21 29,20.1045695 29,19 C29,17.8954305 29.8954305,17 31,17 Z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<path fill="#D6D4DE" d="M81,14 L129,14 C131.761424,14 134,16.2385763 134,19 L134,105 C134,107.761424 131.761424,110 129,110 L81,110 C78.2385763,110 76,107.761424 76,105 L76,19 C76,16.2385763 78.2385763,14 81,14 Z"/>
|
|
||||||
<g transform="translate(78 16)">
|
|
||||||
<path fill="#FFFFFF" d="M5,0 L53,0 C55.7614237,-5.07265313e-16 58,2.23857625 58,5 L58,91 C58,93.7614237 55.7614237,96 53,96 L5,96 C2.23857625,96 3.38176876e-16,93.7614237 0,91 L0,5 C-3.38176876e-16,2.23857625 2.23857625,5.07265313e-16 5,0 Z"/>
|
|
||||||
<g transform="translate(5 10)">
|
|
||||||
<use fill="black" filter="url(#k)" xlink:href="#l"/>
|
|
||||||
<use fill="#EFEDF8" xlink:href="#l"/>
|
|
||||||
<path fill="#E1DBF1" d="M9,8 L33,8 C34.1045695,8 35,8.8954305 35,10 C35,11.1045695 34.1045695,12 33,12 L9,12 C7.8954305,12 7,11.1045695 7,10 C7,8.8954305 7.8954305,8 9,8 Z"/>
|
|
||||||
<path fill="#6B4FBB" d="M9,17 L13,17 C14.1045695,17 15,17.8954305 15,19 C15,20.1045695 14.1045695,21 13,21 L9,21 C7.8954305,21 7,20.1045695 7,19 C7,17.8954305 7.8954305,17 9,17 Z"/>
|
|
||||||
<path fill="#C3B8E3" d="M20,17 L28,17 C29.1045695,17 30,17.8954305 30,19 C30,20.1045695 29.1045695,21 28,21 L20,21 C18.8954305,21 18,20.1045695 18,19 C18,17.8954305 18.8954305,17 20,17 Z"/>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(5 42)">
|
|
||||||
<use fill="black" filter="url(#m)" xlink:href="#n"/>
|
|
||||||
<use fill="#F9F9F9" xlink:href="#n"/>
|
|
||||||
</g>
|
|
||||||
<g transform="translate(5 74)">
|
|
||||||
<rect width="34" height="4" x="7" y="7" fill="#E1DBF1" rx="2"/>
|
|
||||||
<use fill="black" filter="url(#o)" xlink:href="#p"/>
|
|
||||||
<use fill="#F9F9F9" xlink:href="#p"/>
|
|
||||||
</g>
|
|
||||||
<path fill="#6B4FBB" d="M4,0 L54,0 C56.209139,-4.05812251e-16 58,1.790861 58,4 L0,4 C-2.705415e-16,1.790861 1.790861,4.05812251e-16 4,0 Z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 8.8 KiB |
|
@ -117,20 +117,6 @@
|
||||||
= link_to project_boards_path(@project), title: boards_link_text do
|
= link_to project_boards_path(@project), title: boards_link_text do
|
||||||
%span
|
%span
|
||||||
= boards_link_text
|
= boards_link_text
|
||||||
.feature-highlight.js-feature-highlight{ disabled: true, data: { trigger: 'manual', container: 'body', toggle: 'popover', placement: 'right', highlight: 'issue-boards' } }
|
|
||||||
.feature-highlight-popover-content
|
|
||||||
= render 'feature_highlight/issue_boards.svg'
|
|
||||||
.feature-highlight-popover-sub-content
|
|
||||||
%span= _('Use')
|
|
||||||
= link_to 'Issue Boards', project_boards_path(@project)
|
|
||||||
%span= _('to create customized software development workflows like')
|
|
||||||
%strong= _('Scrum')
|
|
||||||
%span= _('or')
|
|
||||||
%strong= _('Kanban')
|
|
||||||
%hr
|
|
||||||
%button.btn-link.dismiss-feature-highlight{ type: 'button' }
|
|
||||||
%span= _("Got it! Don't show this again")
|
|
||||||
= custom_icon('thumbs_up')
|
|
||||||
|
|
||||||
= nav_link(controller: :labels) do
|
= nav_link(controller: :labels) do
|
||||||
= link_to project_labels_path(@project), title: 'Labels' do
|
= link_to project_labels_path(@project), title: 'Labels' do
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.33 5h5.282a2 2 0 0 1 1.963 2.38l-.563 2.905a3 3 0 0 1-.243.732l-1.104 2.286A3 3 0 0 1 10.964 15H7a3 3 0 0 1-3-3V5.7a2 2 0 0 1 .436-1.247l3.11-3.9A.632.632 0 0 1 8.486.5l.138.137a1 1 0 0 1 .28.87L8.33 5zM1 6h2v7H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></svg>
|
|
Before Width: | Height: | Size: 368 B |
|
@ -1,219 +0,0 @@
|
||||||
import Cookies from 'js-cookie';
|
|
||||||
import {
|
|
||||||
getCookieName,
|
|
||||||
getSelector,
|
|
||||||
showPopover,
|
|
||||||
hidePopover,
|
|
||||||
dismiss,
|
|
||||||
mouseleave,
|
|
||||||
mouseenter,
|
|
||||||
setupDismissButton,
|
|
||||||
} from '~/feature_highlight/feature_highlight_helper';
|
|
||||||
|
|
||||||
describe('feature highlight helper', () => {
|
|
||||||
describe('getCookieName', () => {
|
|
||||||
it('returns `feature-highlighted-` prefix', () => {
|
|
||||||
const cookieId = 'cookieId';
|
|
||||||
expect(getCookieName(cookieId)).toEqual(`feature-highlighted-${cookieId}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getSelector', () => {
|
|
||||||
it('returns js-feature-highlight selector', () => {
|
|
||||||
const highlightId = 'highlightId';
|
|
||||||
expect(getSelector(highlightId)).toEqual(`.js-feature-highlight[data-highlight=${highlightId}]`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('showPopover', () => {
|
|
||||||
it('returns true when popover is shown', () => {
|
|
||||||
const context = {
|
|
||||||
hasClass: () => false,
|
|
||||||
popover: () => {},
|
|
||||||
addClass: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(showPopover.call(context)).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false when popover is already shown', () => {
|
|
||||||
const context = {
|
|
||||||
hasClass: () => true,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(showPopover.call(context)).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shows popover', (done) => {
|
|
||||||
const context = {
|
|
||||||
hasClass: () => false,
|
|
||||||
popover: () => {},
|
|
||||||
addClass: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(context, 'popover').and.callFake((method) => {
|
|
||||||
expect(method).toEqual('show');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
showPopover.call(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adds disable-animation and js-popover-show class', (done) => {
|
|
||||||
const context = {
|
|
||||||
hasClass: () => false,
|
|
||||||
popover: () => {},
|
|
||||||
addClass: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(context, 'addClass').and.callFake((classNames) => {
|
|
||||||
expect(classNames).toEqual('disable-animation js-popover-show');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
showPopover.call(context);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('hidePopover', () => {
|
|
||||||
it('returns true when popover is hidden', () => {
|
|
||||||
const context = {
|
|
||||||
hasClass: () => true,
|
|
||||||
popover: () => {},
|
|
||||||
removeClass: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(hidePopover.call(context)).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns false when popover is already hidden', () => {
|
|
||||||
const context = {
|
|
||||||
hasClass: () => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(hidePopover.call(context)).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('hides popover', (done) => {
|
|
||||||
const context = {
|
|
||||||
hasClass: () => true,
|
|
||||||
popover: () => {},
|
|
||||||
removeClass: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(context, 'popover').and.callFake((method) => {
|
|
||||||
expect(method).toEqual('hide');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
hidePopover.call(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removes disable-animation and js-popover-show class', (done) => {
|
|
||||||
const context = {
|
|
||||||
hasClass: () => true,
|
|
||||||
popover: () => {},
|
|
||||||
removeClass: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(context, 'removeClass').and.callFake((classNames) => {
|
|
||||||
expect(classNames).toEqual('disable-animation js-popover-show');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
hidePopover.call(context);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('dismiss', () => {
|
|
||||||
const context = {
|
|
||||||
hide: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
spyOn(Cookies, 'set').and.callFake(() => {});
|
|
||||||
spyOn(hidePopover, 'call').and.callFake(() => {});
|
|
||||||
spyOn(context, 'hide').and.callFake(() => {});
|
|
||||||
dismiss.call(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets cookie to true', () => {
|
|
||||||
expect(Cookies.set).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls hide popover', () => {
|
|
||||||
expect(hidePopover.call).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls hide', () => {
|
|
||||||
expect(context.hide).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('mouseleave', () => {
|
|
||||||
it('calls hide popover if .popover:hover is false', () => {
|
|
||||||
const fakeJquery = {
|
|
||||||
length: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn($.fn, 'init').and.callFake(selector => (selector === '.popover:hover' ? fakeJquery : $.fn));
|
|
||||||
spyOn(hidePopover, 'call');
|
|
||||||
mouseleave();
|
|
||||||
expect(hidePopover.call).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not call hide popover if .popover:hover is true', () => {
|
|
||||||
const fakeJquery = {
|
|
||||||
length: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn($.fn, 'init').and.callFake(selector => (selector === '.popover:hover' ? fakeJquery : $.fn));
|
|
||||||
spyOn(hidePopover, 'call');
|
|
||||||
mouseleave();
|
|
||||||
expect(hidePopover.call).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('mouseenter', () => {
|
|
||||||
const context = {};
|
|
||||||
|
|
||||||
it('shows popover', () => {
|
|
||||||
spyOn(showPopover, 'call').and.returnValue(false);
|
|
||||||
mouseenter.call(context);
|
|
||||||
expect(showPopover.call).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('registers mouseleave event if popover is showed', (done) => {
|
|
||||||
spyOn(showPopover, 'call').and.returnValue(true);
|
|
||||||
spyOn($.fn, 'on').and.callFake((eventName) => {
|
|
||||||
expect(eventName).toEqual('mouseleave');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
mouseenter.call(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not register mouseleave event if popover is not showed', () => {
|
|
||||||
spyOn(showPopover, 'call').and.returnValue(false);
|
|
||||||
const spy = spyOn($.fn, 'on').and.callFake(() => {});
|
|
||||||
mouseenter.call(context);
|
|
||||||
expect(spy).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('setupDismissButton', () => {
|
|
||||||
it('registers click event callback', (done) => {
|
|
||||||
const context = {
|
|
||||||
getAttribute: () => 'popoverId',
|
|
||||||
dataset: {
|
|
||||||
highlight: 'cookieId',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn($.fn, 'on').and.callFake((event) => {
|
|
||||||
expect(event).toEqual('click');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
setupDismissButton.call(context);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,45 +0,0 @@
|
||||||
import domContentLoaded from '~/feature_highlight/feature_highlight_options';
|
|
||||||
import bp from '~/breakpoints';
|
|
||||||
|
|
||||||
describe('feature highlight options', () => {
|
|
||||||
describe('domContentLoaded', () => {
|
|
||||||
const highlightOrder = [];
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// Check for when highlightFeatures is called
|
|
||||||
spyOn(highlightOrder, 'find').and.callFake(() => {});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not call highlightFeatures when breakpoint is xs', () => {
|
|
||||||
spyOn(bp, 'getBreakpointSize').and.returnValue('xs');
|
|
||||||
|
|
||||||
domContentLoaded(highlightOrder);
|
|
||||||
expect(bp.getBreakpointSize).toHaveBeenCalled();
|
|
||||||
expect(highlightOrder.find).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not call highlightFeatures when breakpoint is sm', () => {
|
|
||||||
spyOn(bp, 'getBreakpointSize').and.returnValue('sm');
|
|
||||||
|
|
||||||
domContentLoaded(highlightOrder);
|
|
||||||
expect(bp.getBreakpointSize).toHaveBeenCalled();
|
|
||||||
expect(highlightOrder.find).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not call highlightFeatures when breakpoint is md', () => {
|
|
||||||
spyOn(bp, 'getBreakpointSize').and.returnValue('md');
|
|
||||||
|
|
||||||
domContentLoaded(highlightOrder);
|
|
||||||
expect(bp.getBreakpointSize).toHaveBeenCalled();
|
|
||||||
expect(highlightOrder.find).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call highlightFeatures when breakpoint is lg', () => {
|
|
||||||
spyOn(bp, 'getBreakpointSize').and.returnValue('lg');
|
|
||||||
|
|
||||||
domContentLoaded(highlightOrder);
|
|
||||||
expect(bp.getBreakpointSize).toHaveBeenCalled();
|
|
||||||
expect(highlightOrder.find).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,122 +0,0 @@
|
||||||
import Cookies from 'js-cookie';
|
|
||||||
import * as featureHighlightHelper from '~/feature_highlight/feature_highlight_helper';
|
|
||||||
import * as featureHighlight from '~/feature_highlight/feature_highlight';
|
|
||||||
|
|
||||||
describe('feature highlight', () => {
|
|
||||||
describe('setupFeatureHighlightPopover', () => {
|
|
||||||
const selector = '.js-feature-highlight[data-highlight=test]';
|
|
||||||
beforeEach(() => {
|
|
||||||
setFixtures(`
|
|
||||||
<div>
|
|
||||||
<div class="js-feature-highlight" data-highlight="test" disabled>
|
|
||||||
Trigger
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="feature-highlight-popover-content">
|
|
||||||
Content
|
|
||||||
<div class="dismiss-feature-highlight">
|
|
||||||
Dismiss
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
spyOn(window, 'addEventListener');
|
|
||||||
spyOn(window, 'removeEventListener');
|
|
||||||
featureHighlight.setupFeatureHighlightPopover('test', 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setups popover content', () => {
|
|
||||||
const $popoverContent = $('.feature-highlight-popover-content');
|
|
||||||
const outerHTML = $popoverContent.prop('outerHTML');
|
|
||||||
|
|
||||||
expect($(selector).data('content')).toEqual(outerHTML);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setups mouseenter', () => {
|
|
||||||
const showSpy = spyOn(featureHighlightHelper.showPopover, 'call');
|
|
||||||
$(selector).trigger('mouseenter');
|
|
||||||
|
|
||||||
expect(showSpy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setups debounced mouseleave', (done) => {
|
|
||||||
const hideSpy = spyOn(featureHighlightHelper.hidePopover, 'call');
|
|
||||||
$(selector).trigger('mouseleave');
|
|
||||||
|
|
||||||
// Even though we've set the debounce to 0ms, setTimeout is needed for the debounce
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(hideSpy).toHaveBeenCalled();
|
|
||||||
done();
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setups inserted.bs.popover', () => {
|
|
||||||
$(selector).trigger('mouseenter');
|
|
||||||
const popoverId = $(selector).attr('aria-describedby');
|
|
||||||
const spyEvent = spyOnEvent(`#${popoverId} .dismiss-feature-highlight`, 'click');
|
|
||||||
|
|
||||||
$(`#${popoverId} .dismiss-feature-highlight`).click();
|
|
||||||
expect(spyEvent).toHaveBeenTriggered();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setups show.bs.popover', () => {
|
|
||||||
$(selector).trigger('show.bs.popover');
|
|
||||||
expect(window.addEventListener).toHaveBeenCalledWith('scroll', jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setups hide.bs.popover', () => {
|
|
||||||
$(selector).trigger('hide.bs.popover');
|
|
||||||
expect(window.removeEventListener).toHaveBeenCalledWith('scroll', jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removes disabled attribute', () => {
|
|
||||||
expect($('.js-feature-highlight').is(':disabled')).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('displays popover', () => {
|
|
||||||
expect($(selector).attr('aria-describedby')).toBeFalsy();
|
|
||||||
$(selector).trigger('mouseenter');
|
|
||||||
expect($(selector).attr('aria-describedby')).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('shouldHighlightFeature', () => {
|
|
||||||
it('should return false if element is not found', () => {
|
|
||||||
spyOn(document, 'querySelector').and.returnValue(null);
|
|
||||||
spyOn(Cookies, 'get').and.returnValue(null);
|
|
||||||
|
|
||||||
expect(featureHighlight.shouldHighlightFeature()).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return false if previouslyDismissed', () => {
|
|
||||||
spyOn(document, 'querySelector').and.returnValue(document.createElement('div'));
|
|
||||||
spyOn(Cookies, 'get').and.returnValue('true');
|
|
||||||
|
|
||||||
expect(featureHighlight.shouldHighlightFeature()).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return true if element is found and not previouslyDismissed', () => {
|
|
||||||
spyOn(document, 'querySelector').and.returnValue(document.createElement('div'));
|
|
||||||
spyOn(Cookies, 'get').and.returnValue(null);
|
|
||||||
|
|
||||||
expect(featureHighlight.shouldHighlightFeature()).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('highlightFeatures', () => {
|
|
||||||
it('calls setupFeatureHighlightPopover if shouldHighlightFeature returns true', () => {
|
|
||||||
// Mimic shouldHighlightFeature set to true
|
|
||||||
const highlightOrder = ['issue-boards'];
|
|
||||||
spyOn(highlightOrder, 'find').and.returnValue(highlightOrder[0]);
|
|
||||||
|
|
||||||
expect(featureHighlight.highlightFeatures(highlightOrder)).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not call setupFeatureHighlightPopover if shouldHighlightFeature returns false', () => {
|
|
||||||
// Mimic shouldHighlightFeature set to false
|
|
||||||
const highlightOrder = ['issue-boards'];
|
|
||||||
spyOn(highlightOrder, 'find').and.returnValue(null);
|
|
||||||
|
|
||||||
expect(featureHighlight.highlightFeatures(highlightOrder)).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in a new issue