mirror of
https://github.com/discourse/discourse.git
synced 2025-06-06 21:24:45 +08:00
FEATURE: Allow showing only experiments on "What's new?" (#31347)
This commit allows admins to filter the list of feature feed items on the "What's new?" page to _only_ show experiments. This is useful to both find existing experiments they may have enabled, and to get a better overview of new ones they would like to try. This will eventually not be required when we build a dedicated config page for experiments.
This commit is contained in:
@ -1,8 +1,11 @@
|
|||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { on } from "@ember/modifier";
|
||||||
|
import { action } from "@ember/object";
|
||||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
||||||
|
import DToggleSwitch from "discourse/components/d-toggle-switch";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { bind } from "discourse/lib/decorators";
|
import { bind } from "discourse/lib/decorators";
|
||||||
@ -15,8 +18,8 @@ export default class DashboardNewFeatures extends Component {
|
|||||||
@service currentUser;
|
@service currentUser;
|
||||||
|
|
||||||
@tracked newFeatures = null;
|
@tracked newFeatures = null;
|
||||||
@tracked groupedNewFeatures = null;
|
|
||||||
@tracked isLoading = true;
|
@tracked isLoading = true;
|
||||||
|
@tracked onlyExperiments = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
@ -32,7 +35,7 @@ export default class DashboardNewFeatures extends Component {
|
|||||||
const json = await ajax(
|
const json = await ajax(
|
||||||
"/admin/whats-new.json?force_refresh=" + opts.forceRefresh
|
"/admin/whats-new.json?force_refresh=" + opts.forceRefresh
|
||||||
);
|
);
|
||||||
const items = json.new_features.reduce((acc, feature) => {
|
this.newFeatures = json.new_features.reduce((acc, feature) => {
|
||||||
const key = moment(feature.released_at || feature.created_at).format(
|
const key = moment(feature.released_at || feature.created_at).format(
|
||||||
"YYYY-MM"
|
"YYYY-MM"
|
||||||
);
|
);
|
||||||
@ -40,15 +43,6 @@ export default class DashboardNewFeatures extends Component {
|
|||||||
acc[key].push(feature);
|
acc[key].push(feature);
|
||||||
return acc;
|
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],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
popupAjaxError(err);
|
popupAjaxError(err);
|
||||||
} finally {
|
} finally {
|
||||||
@ -56,14 +50,60 @@ export default class DashboardNewFeatures extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get groupedNewFeatures() {
|
||||||
|
return Object.keys(this.newFeatures)
|
||||||
|
.map((date) => {
|
||||||
|
const visibleFeatures = this.newFeatures[date].filter(this.showFeature);
|
||||||
|
|
||||||
|
if (visibleFeatures.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
date: moment
|
||||||
|
.tz(date, this.currentUser.user_option.timezone)
|
||||||
|
.format("MMMM YYYY"),
|
||||||
|
features: visibleFeatures,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
showFeature(feature) {
|
||||||
|
if (!this.onlyExperiments) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return feature.experiment_setting !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleOnlyExperiments() {
|
||||||
|
this.onlyExperiments = !this.onlyExperiments;
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="admin-config-area__primary-content"
|
class="admin-config-area__primary-content"
|
||||||
{{didInsert this.loadNewFeatures}}
|
{{didInsert this.loadNewFeatures}}
|
||||||
>
|
>
|
||||||
<ConditionalLoadingSpinner @condition={{this.isLoading}}>
|
<ConditionalLoadingSpinner @condition={{this.isLoading}}>
|
||||||
|
<div class="admin-new-features__experiments-filter">
|
||||||
|
<DToggleSwitch
|
||||||
|
@state={{this.onlyExperiments}}
|
||||||
|
{{on "click" this.toggleOnlyExperiments}}
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
{{i18n "admin.dashboard.new_features.only_experiments"}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
{{#each this.groupedNewFeatures as |groupedFeatures|}}
|
{{#each this.groupedNewFeatures as |groupedFeatures|}}
|
||||||
<AdminConfigAreaCard @translatedHeading={{groupedFeatures.date}}>
|
<AdminConfigAreaCard
|
||||||
|
@translatedHeading={{groupedFeatures.date}}
|
||||||
|
class="admin-new-features__group"
|
||||||
|
data-new-features-group={{groupedFeatures.date}}
|
||||||
|
>
|
||||||
<:content>
|
<:content>
|
||||||
{{#each groupedFeatures.features as |feature|}}
|
{{#each groupedFeatures.features as |feature|}}
|
||||||
<DashboardNewFeatureItem @item={{feature}} />
|
<DashboardNewFeatureItem @item={{feature}} />
|
||||||
|
@ -789,3 +789,13 @@
|
|||||||
color: var(--primary-low-mid);
|
color: var(--primary-low-mid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-new-features__experiments-filter {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.d-toggle-switch {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5244,6 +5244,7 @@ en:
|
|||||||
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..."
|
||||||
experimental: "Experimental"
|
experimental: "Experimental"
|
||||||
|
only_experiments: "Only show experimental features"
|
||||||
experiment_enabled: "You have enabled the experimental feature."
|
experiment_enabled: "You have enabled the experimental feature."
|
||||||
experiment_disabled: "You have disabled the experimental feature."
|
experiment_disabled: "You have disabled the experimental feature."
|
||||||
experiment_toggled_too_fast: "You have toggled the experimental feature too fast. Please wait a few seconds before trying again."
|
experiment_toggled_too_fast: "You have toggled the experimental feature too fast. Please wait a few seconds before trying again."
|
||||||
|
@ -51,14 +51,14 @@ describe "Admin New Features Page", type: :system do
|
|||||||
|
|
||||||
new_features_page.visit
|
new_features_page.visit
|
||||||
|
|
||||||
within find(".admin-config-area-card:first-child") do
|
within find(".admin-config-area-card[data-new-features-group='November 2023']") 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_date("November 2023")
|
||||||
end
|
end
|
||||||
|
|
||||||
within find(".admin-config-area-card:last-child") do
|
within find(".admin-config-area-card[data-new-features-group='August 2023']") 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
|
||||||
@ -155,6 +155,45 @@ describe "Admin New Features Page", type: :system do
|
|||||||
expect(new_features_page).to have_no_experimental_text
|
expect(new_features_page).to have_no_experimental_text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "allows filtering to only show experimental items" do
|
||||||
|
DiscourseUpdates.stubs(:new_features).returns(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id" => 7,
|
||||||
|
"user_id" => 1,
|
||||||
|
"emoji" => "😍",
|
||||||
|
"title" => "New feature",
|
||||||
|
"description" => "New feature description",
|
||||||
|
"link" => "https://meta.discourse.org",
|
||||||
|
"tier" => [],
|
||||||
|
"discourse_version" => "",
|
||||||
|
"created_at" => "2023-11-10T02:52:41.462Z",
|
||||||
|
"updated_at" => "2023-11-10T04:28:47.020Z",
|
||||||
|
"experiment_setting" => "experimental_form_templates",
|
||||||
|
"experiment_enabled" => true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id" => 8,
|
||||||
|
"user_id" => 1,
|
||||||
|
"emoji" => "🥹",
|
||||||
|
"title" => "Non experimental feature",
|
||||||
|
"description" => "Cool description",
|
||||||
|
"link" => "https://meta.discourse.org",
|
||||||
|
"tier" => [],
|
||||||
|
"discourse_version" => "",
|
||||||
|
"created_at" => "2023-11-10T02:52:41.462Z",
|
||||||
|
"updated_at" => "2023-11-10T04:28:47.020Z",
|
||||||
|
"experiment_setting" => nil,
|
||||||
|
"experiment_enabled" => false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
new_features_page.visit
|
||||||
|
new_features_page.toggle_experiments_only
|
||||||
|
expect(new_features_page).to have_experimental_text
|
||||||
|
expect(new_features_page).not_to have_text("Non experimental feature")
|
||||||
|
end
|
||||||
|
|
||||||
it "displays a new feature indicator on the sidebar and clears it when navigating to what's new" do
|
it "displays a new feature indicator on the sidebar and clears it when navigating to what's new" do
|
||||||
DiscourseUpdates.stubs(:has_unseen_features?).returns(true)
|
DiscourseUpdates.stubs(:has_unseen_features?).returns(true)
|
||||||
visit "/admin"
|
visit "/admin"
|
||||||
|
@ -47,6 +47,14 @@ module PageObjects
|
|||||||
def has_no_experimental_text?
|
def has_no_experimental_text?
|
||||||
page.has_no_css?(".admin-new-feature-item__header-experimental")
|
page.has_no_css?(".admin-new-feature-item__header-experimental")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def toggle_experiments_only
|
||||||
|
toggle_switch =
|
||||||
|
PageObjects::Components::DToggleSwitch.new(
|
||||||
|
".admin-new-features__experiments-filter .d-toggle-switch__checkbox",
|
||||||
|
)
|
||||||
|
toggle_switch.toggle
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user