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:
parent
e1f2376392
commit
2a9dcade0a
|
@ -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>
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,3 +21,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-new-feature-item {
|
||||||
|
h3 {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
&__new-feature-version {
|
||||||
|
font-size: var(--font-down-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue