UX: add gift emoji styling for new features (#24523)

When admin has unseen new feature, gift emoji is added to a link.

In addition, `/new-features` path was changed to `/whats-new`
This commit is contained in:
Krzysztof Kotlarek 2023-11-27 09:32:28 +11:00 committed by GitHub
parent 856ccb34e1
commit dc2a0854b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 64 additions and 62 deletions

View File

@ -13,7 +13,7 @@ export default class DashboardNewFeatures extends Component {
@bind
loadNewFeatures() {
ajax("/admin/dashboard/new-features.json")
ajax("/admin/dashboard/whats-new.json")
.then((json) => {
this.newFeatures = json.new_features;
this.isLoaded = true;

View File

@ -91,6 +91,7 @@ export default class AdminDashboardController extends Controller {
if (versionChecks) {
properties.versionCheck = VersionCheck.create(model.version_check);
}
properties.hasUnseenFeatures = model.hasUnseenFeatures;
this.setProperties(properties);
})

View File

@ -11,7 +11,10 @@ export default class AdminDashboard extends EmberObject {
static fetch() {
return ajax("/admin/dashboard.json").then((json) => {
const model = AdminDashboard.create();
model.set("version_check", json.version_check);
model.setProperties({
version_check: json.version_check,
hasUnseenFeatures: json.has_unseen_features,
});
return model;
});

View File

@ -15,7 +15,7 @@ export default function () {
resetNamespace: true,
});
this.route("admin.dashboardNewFeatures", {
path: "/dashboard/new-features",
path: "/dashboard/whats-new",
resetNamespace: true,
});
});

View File

@ -53,6 +53,9 @@
{{#if this.isNewFeaturesTabVisible}}
<li class="navigation-item new-features">
<LinkTo @route="admin.dashboardNewFeatures" class="navigation-link">
{{#if this.hasUnseenFeatures}}
{{replace-emoji ":gift:"}}
{{/if}}
{{i18n "admin.dashboard.new_features.title"}}
</LinkTo>
</li>

View File

@ -12,7 +12,7 @@ export default class extends NotificationTypeBase {
}
get linkHref() {
return getURL("/admin/dashboard/new-features");
return getURL("/admin/dashboard/whats-new");
}
get icon() {

View File

@ -142,6 +142,11 @@ acceptance("Dashboard", function (needs) {
await click(".dashboard .navigation-item.new-features .navigation-link");
assert.ok(
exists(
".dashboard .navigation-item.new-features .navigation-link .emoji[title='gift']"
)
);
assert.ok(exists(".dashboard-new-features"));
assert.ok(exists("img.admin-new-feature-item__screenshot"));
});

View File

@ -1,5 +1,5 @@
export default {
"/admin/dashboard/new-features.json": {
"/admin/dashboard/whats-new.json": {
new_features: [
{
id: 1,

View File

@ -1,5 +1,6 @@
export default {
"/admin/dashboard.json": {
updated_at: "2018-04-25T08:06:11.292Z",
has_unseen_features: true
},
};

View File

@ -24,6 +24,10 @@
display: block;
font-weight: bold;
padding: 0.6em 1em 0.5em 1em;
.emoji {
margin-right: 0.5em;
}
}
}

View File

@ -4,8 +4,13 @@
font-size: var(--font-down-1);
}
.navigation a.navigation-link {
padding: 0.5em;
padding: 0.4em;
font-size: var(--font-down-1);
.emoji {
width: 1.3em;
height: 1.3em;
margin-right: 0;
}
}
.dashboard-new-features .section-body {
grid-template-columns: none;

View File

@ -7,6 +7,7 @@ class Admin::DashboardController < Admin::StaffController
if SiteSetting.version_checks?
data.merge!(version_check: DiscourseUpdates.check_version.as_json)
end
data.merge!(has_unseen_features: DiscourseUpdates.has_unseen_features?(current_user.id))
render json: data
end
@ -38,11 +39,15 @@ class Admin::DashboardController < Admin::StaffController
has_unseen_features: DiscourseUpdates.has_unseen_features?(current_user.id),
release_notes_link: AdminDashboardGeneralData.fetch_cached_stats["release_notes_link"],
}
mark_new_features_as_seen
render json: data
end
private
def mark_new_features_as_seen
DiscourseUpdates.mark_new_features_as_seen(current_user.id)
render json: success_json
end
end

View File

@ -320,8 +320,7 @@ Discourse::Application.routes.draw do
get "dashboard/moderation" => "dashboard#moderation"
get "dashboard/security" => "dashboard#security"
get "dashboard/reports" => "dashboard#reports"
get "dashboard/new-features" => "dashboard#new_features"
put "dashboard/mark-new-features-as-seen" => "dashboard#mark_new_features_as_seen"
get "dashboard/whats-new" => "dashboard#new_features"
resources :dashboard, only: [:index] do
collection { get "problems" }

View File

@ -164,7 +164,7 @@ RSpec.describe Admin::DashboardController do
before { sign_in(admin) }
it "is empty by default" do
get "/admin/dashboard/new-features.json"
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(200)
json = response.parsed_body
expect(json["new_features"]).to eq(nil)
@ -172,7 +172,7 @@ RSpec.describe Admin::DashboardController do
it "fails gracefully for invalid JSON" do
Discourse.redis.set("new_features", "INVALID JSON")
get "/admin/dashboard/new-features.json"
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(200)
json = response.parsed_body
expect(json["new_features"]).to eq(nil)
@ -181,7 +181,7 @@ RSpec.describe Admin::DashboardController do
it "includes new features when available" do
populate_new_features
get "/admin/dashboard/new-features.json"
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(200)
json = response.parsed_body
@ -195,7 +195,7 @@ RSpec.describe Admin::DashboardController do
populate_new_features
DiscourseUpdates.mark_new_features_as_seen(admin.id)
get "/admin/dashboard/new-features.json"
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(200)
json = response.parsed_body
@ -209,7 +209,7 @@ RSpec.describe Admin::DashboardController do
expect(DiscourseUpdates.get_last_viewed_feature_date(admin.id)).to eq(nil)
get "/admin/dashboard/new-features.json"
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(200)
expect(DiscourseUpdates.get_last_viewed_feature_date(admin.id)).to be_within_one_second_of(
date2,
@ -218,15 +218,33 @@ RSpec.describe Admin::DashboardController do
date2 = 10.minutes.ago
populate_new_features(date1, date2)
get "/admin/dashboard/new-features.json"
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(200)
expect(DiscourseUpdates.get_last_viewed_feature_date(admin.id)).to be_within_one_second_of(
date2,
)
end
it "marks new features as seen" do
date1 = 30.minutes.ago
date2 = 20.minutes.ago
populate_new_features(date1, date2)
expect(DiscourseUpdates.new_features_last_seen(admin.id)).to eq(nil)
expect(DiscourseUpdates.has_unseen_features?(admin.id)).to eq(true)
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(200)
expect(DiscourseUpdates.new_features_last_seen(admin.id)).not_to eq(nil)
expect(DiscourseUpdates.has_unseen_features?(admin.id)).to eq(false)
expect(DiscourseUpdates.new_features_last_seen(moderator.id)).to eq(nil)
expect(DiscourseUpdates.has_unseen_features?(moderator.id)).to eq(true)
end
it "doesn't error when there are no new features" do
get "/admin/dashboard/new-features.json"
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(200)
end
end
@ -237,7 +255,7 @@ RSpec.describe Admin::DashboardController do
it "includes new features when available" do
populate_new_features
get "/admin/dashboard/new-features.json"
get "/admin/dashboard/whats-new.json"
json = response.parsed_body
@ -252,7 +270,7 @@ RSpec.describe Admin::DashboardController do
expect(DiscourseUpdates.get_last_viewed_feature_date(moderator.id)).to eq(nil)
get "/admin/dashboard/new-features.json"
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(200)
expect(DiscourseUpdates.get_last_viewed_feature_date(moderator.id)).to eq(nil)
end
@ -262,49 +280,7 @@ RSpec.describe Admin::DashboardController do
before { sign_in(user) }
it "denies access with a 404 response" do
get "/admin/dashboard/new-features.json"
expect(response.status).to eq(404)
expect(response.parsed_body["errors"]).to include(I18n.t("not_found"))
end
end
end
describe "#mark_new_features_as_seen" do
after { DiscourseUpdates.clean_state }
context "when logged in as an admin" do
before { sign_in(admin) }
it "resets last seen for a given user" do
populate_new_features
put "/admin/dashboard/mark-new-features-as-seen.json"
expect(response.status).to eq(200)
expect(DiscourseUpdates.new_features_last_seen(admin.id)).not_to eq(nil)
expect(DiscourseUpdates.has_unseen_features?(admin.id)).to eq(false)
end
end
context "when logged in as a moderator" do
before { sign_in(moderator) }
it "resets last seen for moderator" do
populate_new_features
put "/admin/dashboard/mark-new-features-as-seen.json"
expect(response.status).to eq(200)
expect(DiscourseUpdates.new_features_last_seen(moderator.id)).not_to eq(nil)
expect(DiscourseUpdates.has_unseen_features?(moderator.id)).to eq(false)
end
end
context "when logged in as a non-staff user" do
before { sign_in(user) }
it "prevents marking new feature as seen with a 404 response" do
put "/admin/dashboard/mark-new-features-as-seen.json"
get "/admin/dashboard/whats-new.json"
expect(response.status).to eq(404)
expect(response.parsed_body["errors"]).to include(I18n.t("not_found"))

View File

@ -4,7 +4,7 @@ module PageObjects
module Pages
class AdminDashboardNewFeatures < PageObjects::Pages::Base
def visit
page.visit("/admin/dashboard/new-features")
page.visit("/admin/dashboard/whats-new")
self
end