Remove the onboarding checklist.

Looking at the historical data, fewer than 50% of active users have
completed the checklist, which means that it is just persistent
clutter. We also have other better ways of encouraging people to send
traffic and get the apps now.

This commit removes both the frontend UI and backend work but leaves
the db row for now for the historical data.

(imported from commit e8f5780be37bbc75f794fb118e4dd41d8811f2bf)
This commit is contained in:
Jessica McKellar
2013-10-31 10:56:30 -04:00
parent 90457104a6
commit f1e90086f5
14 changed files with 4 additions and 225 deletions

View File

@@ -394,11 +394,7 @@ function send_message(request) {
$("#new_message_content").val('').focus();
autosize_textarea();
$("#send-status").hide(0);
if (request.type === "private") {
onboarding.mark_checklist_step("sent_private_message");
} else {
onboarding.mark_checklist_step("sent_stream_message");
}
clear_message_snapshot();
$("#compose-send-button").removeAttr('disabled');
$("#sending-indicator").hide();

View File

@@ -1,113 +0,0 @@
var onboarding = (function () {
var exports = {};
// The ordered list of onboarding steps we want new users to complete. If the
// steps are changed here, they must also be changed in create_user.py.
var steps = ["sent_stream_message", "sent_private_message", "made_app_sticky", "set_up_integration"];
// N.B. user_message is **unescaped HTML**, so please use caution
var step_info = {sent_stream_message: {"user_message": "Send a stream message"},
sent_private_message: {"user_message": "Send a private message"},
made_app_sticky: {"user_message": 'Get our <a id="get-the-app" href="/apps" target="_blank">apps</a>'},
set_up_integration: {"user_message": 'Set up an <a id="set-up-integration" href="/integrations" target="_blank">integration</a>'}};
var onboarding = false;
function update_onboarding_steps() {
var step_statuses = _.map(steps, function (step) {
return [step, step_info[step].status];
});
$.ajax({
type: 'POST',
url: '/json/update_onboarding_steps',
dataType: 'json',
data: {"onboarding_steps": JSON.stringify(step_statuses)}
});
}
function all_steps_completed() {
return steps.filter(function (step) {
return step_info[step].status === false;
}).length === 0;
}
function finish_onboarding() {
var checklist = $('#onboarding-checklist');
checklist.empty();
checklist.html("<i class='icon-vector-check onboarding_success'>Done");
$('#onboarding').fadeOut(5000, function () {
$(this).hide();
});
}
function update_checklist_ui(step) {
var checklist_item = $($('#onboarding-checklist').find("i")[steps.indexOf(step)]);
checklist_item.removeClass("icon-vector-check-empty").addClass("icon-vector-check");
if (all_steps_completed()) {
finish_onboarding();
}
}
exports.set_step_info = function (steps) {
_.each(steps, function (step) {
var step_name = step[0];
var status = step[1];
step_info[step_name].status = status;
if (status) {
update_checklist_ui(step_name);
}
});
};
exports.mark_checklist_step = function (step) {
if (!onboarding || step_info[step].status) {
return;
}
step_info[step].status = true;
update_checklist_ui(step);
update_onboarding_steps();
};
function set_up_checklist() {
var onboarding_checklist = $('#onboarding-checklist').empty();
if (all_steps_completed()) {
return;
}
_.each(steps, function (step) {
var entry = $('<div>');
if (step_info[step].status) {
entry.append($("<i class='icon-vector-check'>"));
} else {
entry.append($("<i class='icon-vector-check-empty'>"));
}
entry.append($('<span>').html(step_info[step].user_message)).attr("id", step);
onboarding_checklist.append(entry);
var register_action = step_info[step].register;
if (register_action !== undefined) {
register_action(step_info[step].status);
}
});
$(document.body).one('click', 'a[href="/apps"]', function (e) {
exports.mark_checklist_step("made_app_sticky");
});
$(document.body).one('click', "#set-up-integration", function (e) {
exports.mark_checklist_step("set_up_integration");
});
$("#onboarding").show();
}
exports.initialize = function () {
onboarding = true;
exports.set_step_info(page_params.onboarding_steps);
set_up_checklist();
};
return exports;
}());

View File

@@ -1563,7 +1563,6 @@ $(function () {
invite.initialize();
activity.initialize();
tutorial.initialize();
onboarding.initialize();
});

View File

@@ -779,9 +779,6 @@ function get_updates_success(data) {
case 'restart':
reload.initiate({message: "The application has been updated; reloading!"});
break;
case 'onboarding_steps':
onboarding.set_step_info(event.steps);
break;
case 'update_message':
messages_to_update.push(event);
break;

View File

@@ -2713,42 +2713,6 @@ div.edit_bot {
white-space: normal;
}
#onboarding-header {
font-size: 16px;
font-weight: bold;
text-align: left;
}
#onboarding-checklist {
font-size: 14px;
border: 1px solid #ddd;
background-color: #F7F7F7;
padding: 10px 0px 10px 10px;
width: 175px;
}
#onboarding {
display: none;
}
.onboarding_success {
font-size: 40px;
color: #00CC00;
text-align: center;
}
#sticky-popover h1 {
text-align: center;
}
.done-button {
text-align: center;
}
.sticky-popover-inner {
max-width: 300px;
}
.sticky-popover-inner p {
padding-bottom: 5px;
}
#feedback_section {
text-align: left;
padding-bottom: 10px;
@@ -3195,10 +3159,6 @@ div.edit_bot {
text-align: right;
}
#onboarding-checklist i {
margin-right: 0.25em;
}
#share-the-love {
margin-left: 0px;
margin-right: 0px;

View File

@@ -1,15 +0,0 @@
{{! Contents of the "make the app sticky" onboarding popup }}
<div id="sticky-popover">
<h1>Get our app!</h1>
<p>Zulip works best when it's always open, which is why we also
have apps!</p>
<p>Visit <a target="_blank" href="/apps">our apps page</a> for
Mac, Linux, Windows, Android, and iPhone/iPad instructions.</p>
<div class="done-button">
<input type="submit" id="sticky_done" value="Done" class="btn btn-big btn-primary" />
</div>
</div>

View File

@@ -26,11 +26,6 @@
<i class="icon-vector-comment"></i>&nbsp;&nbsp;Send feedback
</button>
</div>
<div id="onboarding">
<p id="onboarding-header">Get started with Zulip!</p>
<div id="onboarding-checklist">
</div>
</div>
<div id="user-list">
<div id="userlist-header">
<h4 class='sidebar-title' id='userlist-title'>USERS</h4>

View File

@@ -25,7 +25,7 @@ var globals =
+ ' compose compose_fade rows hotkeys narrow reload notifications_bar search subs'
+ ' composebox_typeahead typeahead_helper notifications hashchange'
+ ' invite ui util activity timerender MessageList MessageListView blueslip unread stream_list'
+ ' onboarding message_edit tab_bar emoji popovers navigate message_tour'
+ ' message_edit tab_bar emoji popovers navigate message_tour'
+ ' avatar feature_flags search_suggestion referral stream_color Dict'
+ ' Filter summary admin stream_data muting WinChan muting_ui Socket'

View File

@@ -87,10 +87,6 @@ class ZulipSession extends Session
content
}, message_send_time.cbTimer()
@post '/json/update_onboarding_steps', {
onboarding_steps: '[["sent_stream_message",true],["sent_private_message",true],["made_app_sticky",true]]'
}, update_onboarding_steps_time.cbTimer()
send_private_message: (recipients, content) ->
@post '/json/send_message', {
client: 'website'
@@ -161,7 +157,6 @@ stats = [
message_latency = new Stat("Message Latency")
message_send_time = new Stat("Message Send Time")
update_status_time = new Stat("/json/update_status_time Time")
update_onboarding_steps_time = new Stat("/json/update_onboarding_steps Time")
total_reload_time = new Stat("Total reload time")
get_old_messages_time = new Stat("/json/get_old_messages Time")
]

View File

@@ -1407,18 +1407,6 @@ def subscribed_to_stream(user_profile, stream):
except Subscription.DoesNotExist:
return False
def do_update_onboarding_steps(user_profile, steps):
user_profile.onboarding_steps = ujson.dumps(steps)
user_profile.save(update_fields=["onboarding_steps"])
log_event({'type': 'update_onboarding',
'user': user_profile.email,
'steps': steps})
notice = dict(event=dict(type="onboarding_steps", steps=steps),
users=[user_profile.id])
tornado_callbacks.send_notification(notice)
def do_update_message(user_profile, message_id, subject, propagate_mode, content):
try:
message = Message.objects.select_related().get(id=message_id)
@@ -1674,9 +1662,6 @@ def do_events_register(user_profile, user_client, apply_markdown=True,
'is_bot' : userdict['is_bot'],
'full_name' : userdict['full_name']}
for userdict in get_active_user_dicts_in_realm(user_profile.realm)]
if event_types is None or "onboarding_steps" in event_types:
ret['onboarding_steps'] = {'email' : user_profile.email,
'steps' : user_profile.onboarding_steps}
if event_types is None or "subscription" in event_types:
subscriptions, unsubscribed, email_dict = gather_subscriptions_helper(user_profile)
ret['subscriptions'] = subscriptions
@@ -1705,8 +1690,6 @@ def do_events_register(user_profile, user_client, apply_markdown=True,
ret['max_message_id'] = max(ret['max_message_id'], event['message']['id'])
elif event['type'] == "pointer":
ret['pointer'] = max(ret['pointer'], event['pointer'])
elif event['type'] == "onboarding_steps":
ret['onboarding_steps'] = event['steps']
elif event['type'] == "realm_user":
# We handle update by just removing the old value and
# adding the new one.

View File

@@ -8,13 +8,6 @@ import ujson
import os
import string
# The ordered list of onboarding steps we want new users to complete. If the
# steps are changed here, they must also be changed in onboarding.js.
onboarding_steps = ["sent_stream_message", "sent_private_message", "made_app_sticky", "set_up_integration"]
def create_onboarding_steps_blob():
return ujson.dumps([(step, False) for step in onboarding_steps])
def random_api_key():
choices = string.ascii_letters + string.digits
altchars = ''.join([choices[ord(os.urandom(1)) % 62] for _ in range(2)])
@@ -34,7 +27,7 @@ def create_user_profile(realm, email, password, active, bot, full_name, short_na
full_name=full_name, short_name=short_name,
last_login=now, date_joined=now, realm=realm,
pointer=-1, is_bot=bot, bot_owner=bot_owner,
onboarding_steps=create_onboarding_steps_blob())
onboarding_steps=ujson.dumps([]))
if bot or not active:
user_profile.set_unusable_password()

View File

@@ -35,7 +35,7 @@ from zerver.lib.actions import do_remove_subscription, bulk_remove_subscriptions
update_user_presence, bulk_add_subscriptions, do_update_message_flags, \
recipient_for_emails, extract_recipients, do_events_register, \
get_status_dict, do_change_enable_offline_email_notifications, \
do_update_onboarding_steps, do_update_message, internal_prep_message, \
do_update_message, internal_prep_message, \
do_send_messages, do_add_subscription, get_default_subs, do_deactivate, \
user_email_is_unique, do_invite_users, do_refer_friend, compute_mit_user_fullname, \
do_add_alert_words, do_remove_alert_words, do_set_alert_words, get_subscriber_emails, \
@@ -681,7 +681,6 @@ def home(request):
max_message_id = register_ret['max_message_id'],
unread_count = approximate_unread_count(user_profile),
furthest_read_time = sent_time_in_epoch_seconds(latest_read),
onboarding_steps = ujson.loads(user_profile.onboarding_steps),
staging = settings.STAGING_DEPLOYED or not settings.DEPLOYED,
alert_words = register_ret['alert_words'],
muted_topics = register_ret['muted_topics'],
@@ -1178,14 +1177,6 @@ def json_change_enter_sends(request, user_profile,
do_change_enter_sends(user_profile, enter_sends)
return json_success()
@authenticated_json_post_view
@has_request_variables
def json_update_onboarding_steps(request, user_profile,
onboarding_steps=REQ(converter=json_to_list,
default=[])):
do_update_onboarding_steps(user_profile, onboarding_steps)
return json_success()
def is_super_user_api(request):
return request.user.is_authenticated() and is_super_user(request.user)

View File

@@ -435,7 +435,6 @@ JS_SPECS = {
'js/invite.js',
'js/message_list_view.js',
'js/message_list.js',
'js/onboarding.js',
'js/alert_words.js',
'js/alert_words_ui.js',
'js/zulip.js',

View File

@@ -130,7 +130,6 @@ urlpatterns += patterns('zerver.views',
url(r'^json/messages_in_narrow$', 'json_messages_in_narrow'),
url(r'^json/create_bot$', 'json_create_bot'),
url(r'^json/get_bots$', 'json_get_bots'),
url(r'^json/update_onboarding_steps$', 'json_update_onboarding_steps'),
url(r'^json/update_message$', 'json_update_message'),
url(r'^json/fetch_raw_message$', 'json_fetch_raw_message'),
url(r'^json/refer_friend$', 'json_refer_friend'),