Commit 606a16ed authored by Martin Wortschack's avatar Martin Wortschack Committed by Fatih Acet

Add onboarding welcome page

- Add "Learn Gitlab" item to help menu
- Add onboarding endpoint
- Add feature flag helper
- Add styles for blue popovers
- Move controller and template to /ee
- Update PO file
- Add changelog entry
parent f42e8221
......@@ -10,6 +10,26 @@
color: $gray-600;
}
}
&.blue {
background-color: $blue-600;
.popover-body {
color: $white-light;
}
&.bs-popover-bottom {
.arrow::after {
border-bottom-color: $blue-600;
}
}
&.bs-popover-top {
.arrow::after {
border-top-color: $blue-600;
}
}
}
}
.mr-popover {
......@@ -18,3 +38,16 @@
line-height: 1.33;
}
}
.onboarding-welcome-page {
.popover {
min-width: auto;
max-width: 40%;
.popover-body {
padding-top: $gl-padding;
padding-bottom: $gl-padding;
font-size: $gl-font-size-small;
}
}
}
......@@ -2,6 +2,7 @@
- if current_user_menu?(:help)
%li
= link_to _("Help"), help_path
= render_if_exists "shared/learn_gitlab_menu_item"
%li.divider
%li
= link_to _("Submit feedback"), "https://about.gitlab.com/submit-feedback"
......
const STORAGE_KEY = 'onboarding_state';
export default STORAGE_KEY;
<script>
import { __ } from '~/locale';
import { GlLink, GlPopover } from '@gitlab/ui';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
import { redirectTo } from '~/lib/utils/url_utility';
import { resetOnboardingLocalStorage, updateLocalStorage } from './../../utils';
export default {
components: {
GlLink,
GlPopover,
UserAvatarImage,
},
props: {
userAvatarUrl: {
type: String,
required: false,
default: '',
},
projectFullPath: {
type: String,
required: true,
},
skipUrl: {
type: String,
required: true,
},
},
data() {
return {
helpText: __(
"Don't worry, you can access this tour by clicking on the help icon in the top right corner and choose <strong>Learn GitLab</strong>.",
),
};
},
mounted() {
// workaround for appending a custom class to the bs popover which cannot be done via props
// see https://github.com/bootstrap-vue/bootstrap-vue/issues/1983
this.$root.$on('bv::popover::show', bvEventObj => {
const {
target: { dataset },
} = bvEventObj;
if (dataset.class) {
bvEventObj.relatedTarget.classList.add(dataset.class);
}
});
},
methods: {
startTour() {
resetOnboardingLocalStorage();
redirectTo(this.projectFullPath);
},
skipTour() {
updateLocalStorage({ dismissed: true });
redirectTo(this.skipUrl);
},
},
};
</script>
<template>
<div class="onboarding-welcome-page content col-lg-6 ml-auto mr-auto">
<div class="text-center">
<user-avatar-image
:img-src="userAvatarUrl"
:size="64"
css-classes="ml-auto mr-auto"
class="d-inline-block"
/>
<h1>{{ __('Hello there') }}</h1>
<p class="large">{{ __('Welcome to the Guided GitLab Tour') }}</p>
</div>
<p class="mt-4">
{{
__(
'We created a short guided tour that will help you learn the basics of GitLab and how it will help you be better at your job. It should only take a couple of minutes. You willl be guided by two types of helpers, best recognized by their color.',
)
}}
</p>
<div class="text-center mt-4 mb-4">
<div
id="popover-container"
class="popover-container d-flex justify-content-around align-items-end mb-8"
>
<button id="help-popover-trigger" type="button" class="btn-link btn-disabled"></button>
<button
id="action-popover-trigger"
type="button"
class="btn-link btn-disabled mb-3"
data-class="blue"
></button>
<gl-popover
target="help-popover-trigger"
placement="top"
container="popover-container"
show
>
<p class="mb-2">
{{ __('White helpers give contextual information.') }}
</p>
<button disabled type="button" :aria-label="__('OK')" class="btn btn-xs popover-btn">
{{ __('OK') }}
</button>
</gl-popover>
<gl-popover
target="action-popover-trigger"
placement="top"
container="popover-container"
show
>
{{ __('Blue helpers indicate an action to be taken.') }}
</gl-popover>
</div>
<gl-link class="btn btn-success" @click="startTour">
{{ __("Ok let's go") }}
</gl-link>
<p class="small mt-8">
<gl-link @click="skipTour">
{{ __('Skip this for now') }}
</gl-link>
</p>
<p class="small ml-4 mr-4" v-html="helpText"></p>
</div>
</div>
</template>
<style scoped>
.popover-container {
height: 140px;
}
.popover-btn[disabled] {
background-color: #1b69b6 !important;
border-color: #1b69b6 !important;
color: white !important;
}
p.large {
font-size: 16px;
}
p.small {
font-size: 12px;
}
.btn-success {
width: 200px;
}
</style>
import Vue from 'vue';
import WelcomePage from './components/welcome_page.vue';
export default function() {
const el = document.getElementById('js-onboarding-welcome');
if (!el) {
return false;
}
const { userAvatarUrl, projectFullPath, skipUrl } = el.dataset;
return new Vue({
el,
render(h) {
return h(WelcomePage, {
props: {
userAvatarUrl,
projectFullPath,
skipUrl,
},
});
},
});
}
import STORAGE_KEY from './constants';
/**
* onboarding_state:
* activeTour: Number
* dismissed: Boolean
*/
const ONBOARDING_PROPS_DEFAULTS = {
activeTourKey: 1,
dismissed: false,
};
export const resetOnboardingLocalStorage = () => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(ONBOARDING_PROPS_DEFAULTS));
};
export const getOnboardingLocalStorageState = () => JSON.parse(localStorage.getItem(STORAGE_KEY));
export const updateLocalStorage = updatedProps => {
let currentState = getOnboardingLocalStorageState();
if (!currentState) {
currentState = resetOnboardingLocalStorage();
}
const onboardingState = {
...currentState,
...updatedProps,
};
localStorage.setItem(STORAGE_KEY, JSON.stringify(onboardingState));
};
import initOnboardingWelcome from 'ee/onboarding/onboarding_welcome';
document.addEventListener('DOMContentLoaded', () => initOnboardingWelcome());
# frozen_string_literal: true
class Explore::OnboardingController < Explore::ApplicationController
before_action :authenticate_user!
before_action :set_project!
layout 'onboarding'
private
def set_project!
@project = get_onboarding_demo_project
render_404 unless @project && can?(current_user, :read_project, @project)
end
def get_onboarding_demo_project
if Gitlab.com? && Feature.enabled?(:user_onboarding)
Project.find_by_full_path("gitlab-org/gitlab-ce")
end
end
end
......@@ -117,6 +117,10 @@ module EE
show
end
def user_onboarding_enabled?
::Gitlab.com? && ::Feature.enabled?(:user_onboarding)
end
private
def appearance
......
.container.container-limited.limit-container-width.navless-container
#js-onboarding-welcome{ data: { user_avatar_url: avatar_icon_for_user(current_user), project_full_path: @project.web_url, skip_url: root_dashboard_path } }
- page_title _("Onboarding")
- header_title _("Onboarding")
%html{ lang: I18n.locale, class: page_class }
= render "layouts/head"
%body.navless
= yield
- return unless user_onboarding_enabled?
%li
%a{ href: explore_onboarding_index_path }
= _("Learn GitLab")
%span.badge.badge-success= s_("Badge|New")
# frozen_string_literal: true
namespace :explore do
resources :onboarding, only: [:index]
end
# frozen_string_literal: true
require 'spec_helper'
describe 'User Onboarding' do
let(:user) { create(:user) }
let(:project) { create(:project) }
before do
allow(Gitlab).to receive(:com?) { true }
sign_in(user)
end
context 'when the feature is enabled', :js do
before do
stub_feature_flags(user_onboarding: true)
end
describe 'help menu' do
it 'shows the "Learn GitLab" item in the help menu' do
visit root_dashboard_path
find('.header-help-dropdown-toggle').click
page.within('.header-help') do
expect(page).to have_link('Learn GitLab', href: explore_onboarding_index_path)
end
end
end
context 'welcome page' do
before do
allow(Project).to receive(:find_by_full_path).and_return(project)
project.add_guest(user)
end
it 'shows the "Learn GitLab" welcome page' do
visit explore_onboarding_index_path
expect(page).to have_content('Welcome to the Guided GitLab Tour')
end
end
end
context 'when the feature is disabled' do
before do
stub_feature_flags(user_onboarding: false)
end
describe 'help menu' do
it 'does not show the "Learn GitLab" item in the help menu' do
visit root_dashboard_path
find('.header-help-dropdown-toggle').click
page.within('.header-help') do
expect(page).not_to have_link('Learn GitLab')
end
end
end
end
end
......@@ -1720,6 +1720,9 @@ msgstr ""
msgid "Badges|e.g. %{exampleUrl}"
msgstr ""
msgid "Badge|New"
msgstr ""
msgid "Balsamiq file could not be loaded."
msgstr ""
......@@ -1846,6 +1849,9 @@ msgstr ""
msgid "Blog"
msgstr ""
msgid "Blue helpers indicate an action to be taken."
msgstr ""
msgid "Boards"
msgstr ""
......@@ -4172,6 +4178,9 @@ msgstr ""
msgid "Don't show again"
msgstr ""
msgid "Don't worry, you can access this tour by clicking on the help icon in the top right corner and choose <strong>Learn GitLab</strong>."
msgstr ""
msgid "Done"
msgstr ""
......@@ -6301,6 +6310,9 @@ msgstr ""
msgid "HealthCheck|Unhealthy"
msgstr ""
msgid "Hello there"
msgstr ""
msgid "Help"
msgstr ""
......@@ -7135,6 +7147,9 @@ msgstr ""
msgid "Lead"
msgstr ""
msgid "Learn GitLab"
msgstr ""
msgid "Learn how to %{link_start}contribute to the built-in templates%{link_end}"
msgstr ""
......@@ -8423,6 +8438,12 @@ msgstr ""
msgid "OfSearchInADropdown|Filter"
msgstr ""
msgid "Ok let's go"
msgstr ""
msgid "Onboarding"
msgstr ""
msgid "Once imported, repositories can be mirrored over SSH. Read more %{ssh_link}"
msgstr ""
......@@ -11195,6 +11216,9 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
msgid "Skip this for now"
msgstr ""
msgid "Slack application"
msgstr ""
......@@ -13673,6 +13697,9 @@ msgstr ""
msgid "We couldn't find any results matching"
msgstr ""
msgid "We created a short guided tour that will help you learn the basics of GitLab and how it will help you be better at your job. It should only take a couple of minutes. You willl be guided by two types of helpers, best recognized by their color."
msgstr ""
msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
msgstr ""
......@@ -13712,6 +13739,9 @@ msgstr ""
msgid "Weight %{weight}"
msgstr ""
msgid "Welcome to the Guided GitLab Tour"
msgstr ""
msgid "Welcome to your Issue Board!"
msgstr ""
......@@ -13732,6 +13762,9 @@ msgstr[1] ""
msgid "When:"
msgstr ""
msgid "White helpers give contextual information."
msgstr ""
msgid "Who can see this group?"
msgstr ""
......
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