UX: group admin new features by month (#28106)

Display new features grouped by month and show additional information about the version.
This commit is contained in:
Krzysztof Kotlarek 2024-07-29 14:20:12 +10:00 committed by GitHub
parent e1f2376392
commit 2a9dcade0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 126 additions and 19 deletions

View File

@ -1,13 +1,20 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking"; import { tracked } from "@glimmer/tracking";
import i18n from "discourse-common/helpers/i18n"; import I18n from "discourse-i18n";
export default class AdminConfigAreaCard extends Component { export default class AdminConfigAreaCard extends Component {
@tracked collapsed = false; @tracked collapsed = false;
get computedHeading() {
if (this.args.heading) {
return I18n.t(this.args.heading);
}
return this.args.translatedHeading;
}
<template> <template>
<section class="admin-config-area-card" ...attributes> <section class="admin-config-area-card" ...attributes>
<h3 class="admin-config-area-card__title">{{i18n @heading}}</h3> <h3 class="admin-config-area-card__title">{{this.computedHeading}}</h3>
<div class="admin-config-area-card__content"> <div class="admin-config-area-card__content">
{{yield}} {{yield}}
</div> </div>

View File

@ -14,6 +14,11 @@ const DashboardNewFeatureItem = <template>
<h3> <h3>
{{@item.title}} {{@item.title}}
</h3> </h3>
{{#if @item.discourse_version}}
<div class="admin-new-feature-item__new-feature-version">
{{@item.discourse_version}}
</div>
{{/if}}
</div> </div>
{{#if @item.screenshot_url}} {{#if @item.screenshot_url}}

View File

@ -1,21 +1,42 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking"; import { tracked } from "@glimmer/tracking";
import didInsert from "@ember/render-modifiers/modifiers/did-insert"; import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { service } from "@ember/service";
import { htmlSafe } from "@ember/template"; import { htmlSafe } from "@ember/template";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import i18n from "discourse-common/helpers/i18n"; import i18n from "discourse-common/helpers/i18n";
import { bind } from "discourse-common/utils/decorators"; import { bind } from "discourse-common/utils/decorators";
import AdminConfigAreaCard from "admin/components/admin-config-area-card";
import DashboardNewFeatureItem from "admin/components/dashboard-new-feature-item"; import DashboardNewFeatureItem from "admin/components/dashboard-new-feature-item";
export default class DashboardNewFeatures extends Component { export default class DashboardNewFeatures extends Component {
@service currentUser;
@tracked newFeatures = null; @tracked newFeatures = null;
@tracked groupedNewFeatures = null;
@tracked isLoaded = false; @tracked isLoaded = false;
@bind @bind
loadNewFeatures() { loadNewFeatures() {
ajax("/admin/dashboard/whats-new.json") ajax("/admin/dashboard/whats-new.json")
.then((json) => { .then((json) => {
this.newFeatures = json.new_features; const items = json.new_features.reduce((acc, feature) => {
const key = moment(feature.released_at || feature.created_at).format(
"YYYY-MM"
);
acc[key] = acc[key] || [];
acc[key].push(feature);
return acc;
}, {});
this.groupedNewFeatures = Object.keys(items).map((date) => {
return {
date: moment
.tz(date, this.currentUser.user_option.timezone)
.format("MMMM YYYY"),
features: items[date],
};
});
this.isLoaded = true; this.isLoaded = true;
}) })
.finally(() => { .finally(() => {
@ -24,11 +45,15 @@ export default class DashboardNewFeatures extends Component {
} }
<template> <template>
<div class="section-body" {{didInsert this.loadNewFeatures}}> <div class="admin-config-area" {{didInsert this.loadNewFeatures}}>
{{#if this.newFeatures}} {{#if this.groupedNewFeatures}}
{{#each this.newFeatures as |feature|}} {{#each this.groupedNewFeatures as |groupedFeatures|}}
<AdminConfigAreaCard @translatedHeading={{groupedFeatures.date}}>
{{#each groupedFeatures.features as |feature|}}
<DashboardNewFeatureItem @item={{feature}} /> <DashboardNewFeatureItem @item={{feature}} />
{{/each}} {{/each}}
</AdminConfigAreaCard>
{{/each}}
{{else if this.isLoaded}} {{else if this.isLoaded}}
{{htmlSafe {{htmlSafe
(i18n (i18n

View File

@ -1,4 +1,7 @@
<ConditionalLoadingSpinner @condition={{this.isLoading}}> <ConditionalLoadingSpinner @condition={{this.isLoading}}>
<div class="admin-config-area">
<h2>{{i18n "admin.dashboard.new_features.title"}}</h2> <h2>{{i18n "admin.dashboard.new_features.title"}}</h2>
<p>{{html-safe (i18n "admin.dashboard.new_features.subtitle")}}</p>
<DashboardNewFeatures /> <DashboardNewFeatures />
</div>
</ConditionalLoadingSpinner> </ConditionalLoadingSpinner>

View File

@ -1,2 +1,5 @@
<h2>{{i18n "admin.new_features.title"}}</h2> <div class="admin-config-area">
<DashboardNewFeatures /> <h2>{{i18n "admin.dashboard.new_features.title"}}</h2>
<p>{{html-safe (i18n "admin.dashboard.new_features.subtitle")}}</p>
<DashboardNewFeatures />
</div>

View File

@ -644,13 +644,26 @@
} }
} }
.whats-new,
.dashboard {
.admin-config-area-card__title {
font-size: var(--font-up-1);
margin-bottom: 1em;
}
.admin-new-feature-item__learn-more {
margin-bottom: 1em;
display: inline-block;
}
}
.admin-new-feature-item { .admin-new-feature-item {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
margin-bottom: 1.5em; margin-bottom: 1.5em;
background-color: var(--primary-very-low); border-bottom: 1px solid var(--primary-low);
padding: 1em; &:last-child {
max-width: 45rem; border-bottom: none;
}
&__new-feature-emoji { &__new-feature-emoji {
font-size: 1.2em; font-size: 1.2em;
@ -665,11 +678,14 @@
&__header { &__header {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
font-size: var(--font-up-1);
font-weight: bold; font-weight: bold;
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
&__screenshot { &__screenshot {
width: 100%; width: 100%;
} }
&__new-feature-version {
margin-left: auto;
color: var(--primary-low-mid);
}
} }

View File

@ -21,3 +21,12 @@
} }
} }
} }
.admin-new-feature-item {
h3 {
margin-right: 0.5em;
}
&__new-feature-version {
font-size: var(--font-down-1);
}
}

View File

@ -5010,6 +5010,7 @@ en:
problems_found: "Some advice based on your current site settings" problems_found: "Some advice based on your current site settings"
new_features: new_features:
title: "What's new" title: "What's new"
subtitle: "For even more detail about new features and improvements we are adding all the time, see <a href='https://meta.discourse.org/tags/c/announcements/67/release-notes' target='_blank'>Release notes</a>."
previous_announcements: "You can see previous new feature announcements on <a href='%{url}' target='_blank'>Discourse Meta</a>" previous_announcements: "You can see previous new feature announcements on <a href='%{url}' target='_blank'>Discourse Meta</a>"
learn_more: "Learn more..." learn_more: "Learn more..."
last_checked: "Last checked" last_checked: "Last checked"

View File

@ -17,19 +17,47 @@ describe "Admin Dashboard New Features Page", type: :system do
"description" => "New feature description", "description" => "New feature description",
"link" => "https://meta.discourse.org", "link" => "https://meta.discourse.org",
"tier" => [], "tier" => [],
"discourse_version" => "", "discourse_version" => "3.3.0.beta4",
"created_at" => "2023-11-10T02:52:41.462Z", "created_at" => "2023-11-10T02:52:41.462Z",
"updated_at" => "2023-11-10T04:28:47.020Z", "updated_at" => "2023-11-10T04:28:47.020Z",
"screenshot_url" => "screenshot_url" =>
"/uploads/default/original/1X/bab053dc94dc4e0d357b0e777e3357bb1ac99e12.jpeg", "/uploads/default/original/1X/bab053dc94dc4e0d357b0e777e3357bb1ac99e12.jpeg",
}, },
{
"id" => 8,
"user_id" => 1,
"emoji" => "🐼",
"title" => "New feature from previous release",
"description" => "New feature description",
"link" => "https://meta.discourse.org",
"tier" => [],
"discourse_version" => "3.3.0.beta3",
"created_at" => "2023-09-10T02:52:41.462Z",
"updated_at" => "2023-09-10T04:28:47.020Z",
"released_at" => "2023-08-10T04:28:47.020Z",
"screenshot_url" =>
"/uploads/default/original/1X/bab054dc94dc4e0d357b0e777e3357bb1ac99e13.jpeg",
},
], ],
) )
new_features_page.visit new_features_page.visit
within find(".admin-config-area-card:first-child") do
expect(new_features_page).to have_screenshot expect(new_features_page).to have_screenshot
expect(new_features_page).to have_learn_more_link expect(new_features_page).to have_learn_more_link
expect(new_features_page).to have_no_emoji expect(new_features_page).to have_no_emoji
expect(new_features_page).to have_date("November 2023")
expect(new_features_page).to have_version("3.3.0.beta4")
end
within find(".admin-config-area-card:last-child") do
expect(new_features_page).to have_screenshot
expect(new_features_page).to have_learn_more_link
expect(new_features_page).to have_no_emoji
expect(new_features_page).to have_date("August 2023")
expect(new_features_page).to have_version("3.3.0.beta3")
end
end end
it "displays new features with emoji when no screenshot" do it "displays new features with emoji when no screenshot" do

View File

@ -27,6 +27,16 @@ module PageObjects
def has_no_emoji? def has_no_emoji?
page.has_no_css?(".admin-new-feature-item__new-feature-emoji") page.has_no_css?(".admin-new-feature-item__new-feature-emoji")
end end
def has_version?(version)
element = find(".admin-new-feature-item__new-feature-version")
element.has_text?(version)
end
def has_date?(date)
element = find(".admin-config-area-card__title")
element.has_text?(date)
end
end end
end end
end end