Commit 4553557a authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch 'jswain_whats_new_notification' into 'master'

Whats new notification dot and count

See merge request gitlab-org/gitlab!42494
parents 61c0915d 647ec63b
......@@ -16,6 +16,15 @@ function initDeferred() {
const whatsNewTriggerEl = document.querySelector('.js-whats-new-trigger');
if (whatsNewTriggerEl) {
const storageKey = whatsNewTriggerEl.getAttribute('data-storage-key');
$('.header-help').on('show.bs.dropdown', () => {
const displayNotification = JSON.parse(localStorage.getItem(storageKey));
if (displayNotification === false) {
$('.js-whats-new-notification-count').remove();
}
});
whatsNewTriggerEl.addEventListener('click', () => {
import(/* webpackChunkName: 'whatsNewApp' */ '~/whats_new')
.then(({ default: initWhatsNew }) => {
......
......@@ -15,6 +15,11 @@ export default {
required: false,
default: null,
},
storageKey: {
type: String,
required: true,
default: null,
},
},
computed: {
...mapState(['open']),
......@@ -31,7 +36,7 @@ export default {
},
},
mounted() {
this.openDrawer();
this.openDrawer(this.storageKey);
},
methods: {
...mapActions(['openDrawer', 'closeDrawer']),
......@@ -41,7 +46,7 @@ export default {
<template>
<div>
<gl-drawer class="mt-6" :open="open" @close="closeDrawer">
<gl-drawer class="whats-new-drawer" :open="open" @close="closeDrawer">
<template #header>
<h4 class="page-title my-2">{{ __("What's new at GitLab") }}</h4>
</template>
......@@ -69,5 +74,6 @@ export default {
</div>
</div>
</gl-drawer>
<div v-if="open" class="whats-new-modal-backdrop modal-backdrop"></div>
</div>
</template>
......@@ -20,6 +20,7 @@ export default () => {
return createElement('app', {
props: {
features: whatsNewElm.getAttribute('data-features'),
storageKey: whatsNewElm.getAttribute('data-storage-key'),
},
});
},
......
......@@ -4,7 +4,11 @@ export default {
closeDrawer({ commit }) {
commit(types.CLOSE_DRAWER);
},
openDrawer({ commit }) {
openDrawer({ commit }, storageKey) {
commit(types.OPEN_DRAWER);
if (storageKey) {
localStorage.setItem(storageKey, JSON.stringify(false));
}
},
};
.whats-new-drawer {
margin-top: $header-height;
@include gl-shadow-none;
}
.with-performance-bar .whats-new-drawer {
margin-top: calc(#{$performance-bar-height} + #{$header-height});
}
.gl-badge.whats-new-item-badge {
background-color: $purple-light;
color: $purple;
font-weight: bold;
@include gl-font-weight-bold;
}
.whats-new-item-image {
border-color: $gray-50;
}
.whats-new-modal-backdrop {
z-index: 9;
}
.whats-new-notification-count {
@include gl-bg-gray-900;
@include gl-font-sm;
@include gl-line-height-normal;
@include gl-text-white;
@include gl-vertical-align-top;
border-radius: 20px;
padding: 3px 10px;
}
......@@ -3,6 +3,24 @@
module WhatsNewHelper
EMPTY_JSON = ''.to_json
def whats_new_most_recent_release_items_count
items = parsed_most_recent_release_items
return unless items.is_a?(Array)
items.count
end
def whats_new_storage_key
items = parsed_most_recent_release_items
return unless items.is_a?(Array)
release = items.first.try(:[], 'release')
['display-whats-new-notification', release].compact.join('-')
end
def whats_new_most_recent_release_items
YAML.load_file(most_recent_release_file_path).to_json
......@@ -14,6 +32,10 @@ module WhatsNewHelper
private
def parsed_most_recent_release_items
Gitlab::Json.parse(whats_new_most_recent_release_items)
end
def most_recent_release_file_path
Dir.glob(files_path).max
end
......
......@@ -100,7 +100,7 @@
= sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left')
- if ::Feature.enabled?(:whats_new_drawer)
#whats-new-app{ data: { features: whats_new_most_recent_release_items } }
#whats-new-app{ data: { features: whats_new_most_recent_release_items, storage_key: whats_new_storage_key } }
- if can?(current_user, :update_user_status, current_user)
.js-set-status-modal-wrapper{ data: { current_emoji: current_user.status.present? ? current_user.status.emoji : '', current_message: current_user.status.present? ? current_user.status.message : '' } }
......@@ -7,8 +7,8 @@
packages: [Ultimate, Gold]
url: https://docs.gitlab.com/ee/user/project/requirements/index.html
image_url:
published_at: 2020-04-22
release: 12.10
published_at: 2020-04-22
release: 12.10
- title: Retrieve CI/CD secrets from HashiCorp Vault
body: In this release, GitLab adds support for lightweight JSON Web Token (JWT) authentication to integrate with your existing HashiCorp Vault. Now, you can seamlessly provide secrets to CI/CD jobs by taking advantage of HashiCorp's JWT authentication method rather than manually having to provide secrets as a variable in GitLab.
stage: Release
......
- if ::Feature.enabled?(:whats_new_dropdown)
- if ::Feature.enabled?(:whats_new_drawer)
%li
%button.js-whats-new-trigger{ type: 'button' }
%button.js-whats-new-trigger{ type: 'button', data: { storage_key: whats_new_storage_key } }
= _("See what's new at GitLab")
%span.js-whats-new-notification-count.whats-new-notification-count.gl-ml-4
= whats_new_most_recent_release_items_count
- else
%li
= link_to _("See what's new at GitLab"), "#{promo_url}/releases/gitlab-com/", target: '_blank', rel: 'noopener noreferrer', data: { track_event: 'click_whats_new', track_property: 'question_menu' }
# frozen_string_literal: true
require "spec_helper"
RSpec.describe "renders a `whats new` dropdown item", :js do
let_it_be(:user) { create(:user) }
before do
stub_feature_flags(whats_new_dropdown: true, whats_new_drawer: true)
sign_in(user)
end
it 'shows notification count and removes it once viewed' do
visit root_dashboard_path
find('.header-help-dropdown-toggle').click
page.within '.header-help' do
expect(page).to have_button(text: "See what's new at GitLab")
expect(page).to have_selector('.js-whats-new-notification-count')
find('button', text: "See what's new at GitLab").click
end
find('.whats-new-drawer .gl-drawer-close-button').click
find('.header-help-dropdown-toggle').click
page.within '.header-help' do
expect(page).to have_button(text: "See what's new at GitLab")
expect(page).not_to have_selector('.js-whats-new-notification-count')
end
end
end
......@@ -11,7 +11,7 @@ describe('App', () => {
let store;
let actions;
let state;
let propsData = { features: '[ {"title":"Whats New Drawer"} ]' };
let propsData = { features: '[ {"title":"Whats New Drawer"} ]', storageKey: 'storage-key' };
const buildWrapper = () => {
actions = {
......@@ -51,6 +51,7 @@ describe('App', () => {
it('dispatches openDrawer when mounted', () => {
expect(actions.openDrawer).toHaveBeenCalled();
expect(actions.openDrawer).toHaveBeenCalledWith(expect.any(Object), 'storage-key');
});
it('dispatches closeDrawer when clicking close', () => {
......@@ -71,7 +72,7 @@ describe('App', () => {
});
it('handles bad json argument gracefully', () => {
propsData = { features: 'this is not json' };
propsData = { features: 'this is not json', storageKey: 'storage-key' };
buildWrapper();
expect(getDrawer().exists()).toBe(true);
......
import testAction from 'helpers/vuex_action_helper';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import actions from '~/whats_new/store/actions';
import * as types from '~/whats_new/store/mutation_types';
describe('whats new actions', () => {
describe('openDrawer', () => {
useLocalStorageSpy();
it('should commit openDrawer', () => {
testAction(actions.openDrawer, {}, {}, [{ type: types.OPEN_DRAWER }]);
testAction(actions.openDrawer, 'storage-key', {}, [{ type: types.OPEN_DRAWER }]);
expect(window.localStorage.setItem).toHaveBeenCalledWith('storage-key', 'false');
});
});
......
......@@ -3,6 +3,52 @@
require 'spec_helper'
RSpec.describe WhatsNewHelper do
describe '#whats_new_storage_key' do
subject { helper.whats_new_storage_key }
before do
allow(helper).to receive(:whats_new_most_recent_release_items).and_return(json)
end
context 'when recent release items exist' do
let(:json) { [{ release: 84.0 }].to_json }
it { is_expected.to eq('display-whats-new-notification-84.0') }
context 'when the release items are missing the release key' do
let(:json) { [{ title: 'bells!' }].to_json }
it { is_expected.to eq('display-whats-new-notification') }
end
end
context 'when recent release items do NOT exist' do
let(:json) { WhatsNewHelper::EMPTY_JSON }
it { is_expected.to be_nil }
end
end
describe '#whats_new_most_recent_release_items_count' do
subject { helper.whats_new_most_recent_release_items_count }
before do
allow(helper).to receive(:whats_new_most_recent_release_items).and_return(json)
end
context 'when recent release items exist' do
let(:json) { [:bells, :and, :whistles].to_json }
it { is_expected.to eq(3) }
end
context 'when recent release items do NOT exist' do
let(:json) { WhatsNewHelper::EMPTY_JSON }
it { is_expected.to be_nil }
end
end
describe '#whats_new_most_recent_release_items' do
let(:fixture_dir_glob) { Dir.glob(File.join('spec', 'fixtures', 'whats_new', '*.yml')) }
......
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