Skip to content

Commit b986560

Browse files
committed
DEV: Port the about page extra groups functionality into core
1 parent c2ae2e2 commit b986560

File tree

15 files changed

+522
-2
lines changed

15 files changed

+522
-2
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import Component from "@glimmer/component";
2+
import { cached } from "@glimmer/tracking";
3+
import { action } from "@ember/object";
4+
import { service } from "@ember/service";
5+
import Form from "discourse/components/form";
6+
import { ajax } from "discourse/lib/ajax";
7+
import { popupAjaxError } from "discourse/lib/ajax-error";
8+
import { i18n } from "discourse-i18n";
9+
import GroupChooser from "select-kit/components/group-chooser";
10+
11+
export default class AdminConfigAreasAboutExtraGroups extends Component {
12+
@service site;
13+
@service toasts;
14+
15+
@cached
16+
get data() {
17+
return {
18+
aboutPageExtraGroups:
19+
this.args.extraGroups.aboutPageExtraGroups.value
20+
.split("|")
21+
.map(Number) || [],
22+
aboutPageExtraGroupsInitialMembers:
23+
this.args.extraGroups.aboutPageExtraGroupsInitialMembers.value,
24+
aboutPageExtraGroupsOrder:
25+
this.args.extraGroups.aboutPageExtraGroupsOrder.value,
26+
aboutPageExtraGroupsShowDescription:
27+
this.args.extraGroups.aboutPageExtraGroupsShowDescription.value ===
28+
"true",
29+
};
30+
}
31+
32+
@action
33+
async save(data) {
34+
this.args.setGlobalSavingStatus(true);
35+
try {
36+
await ajax("/admin/config/about.json", {
37+
type: "PUT",
38+
data: {
39+
extra_groups: {
40+
groups: data.aboutPageExtraGroups.join("|"),
41+
initial_members: data.aboutPageExtraGroupsInitialMembers,
42+
order: data.aboutPageExtraGroupsOrder,
43+
show_description: data.aboutPageExtraGroupsShowDescription,
44+
},
45+
},
46+
});
47+
this.toasts.success({
48+
duration: 30000,
49+
data: {
50+
message: i18n("admin.config_areas.about.toasts.extra_groups_saved"),
51+
},
52+
});
53+
} catch (err) {
54+
popupAjaxError(err);
55+
} finally {
56+
this.args.setGlobalSavingStatus(false);
57+
}
58+
}
59+
60+
get orderings() {
61+
return this.args.extraGroups.aboutPageExtraGroupsOrder.choices;
62+
}
63+
64+
<template>
65+
<Form @data={{this.data}} @onSubmit={{this.save}} as |form|>
66+
<form.Field
67+
@name="aboutPageExtraGroups"
68+
@title={{i18n "admin.config_areas.about.extra_groups.groups"}}
69+
@format="large"
70+
as |field|
71+
>
72+
<field.Custom>
73+
<GroupChooser
74+
@content={{this.site.groups}}
75+
@value={{field.value}}
76+
@onChange={{field.set}}
77+
/>
78+
</field.Custom>
79+
</form.Field>
80+
81+
<form.Field
82+
@name="aboutPageExtraGroupsInitialMembers"
83+
@title={{i18n "admin.config_areas.about.extra_groups.initial_members"}}
84+
@description={{i18n
85+
"admin.config_areas.about.extra_groups.initial_members_description"
86+
}}
87+
@validation="required"
88+
@format="large"
89+
as |field|
90+
>
91+
<field.Input @type="number" />
92+
</form.Field>
93+
94+
<form.Field
95+
@name="aboutPageExtraGroupsOrder"
96+
@title={{i18n "admin.config_areas.about.extra_groups.order"}}
97+
@validation="required"
98+
@format="large"
99+
as |field|
100+
>
101+
<field.Select as |select|>
102+
{{#each this.orderings as |ordering|}}
103+
<select.Option @value={{ordering}}>
104+
{{ordering}}
105+
</select.Option>
106+
{{/each}}
107+
</field.Select>
108+
</form.Field>
109+
110+
<form.Field
111+
@name="aboutPageExtraGroupsShowDescription"
112+
@title={{i18n "admin.config_areas.about.extra_groups.show_description"}}
113+
@validation="required"
114+
@format="large"
115+
as |field|
116+
>
117+
<field.Checkbox />
118+
</form.Field>
119+
120+
<form.Submit
121+
@label="admin.config_areas.about.update"
122+
@disabled={{@globalSavingStatus}}
123+
/>
124+
</Form>
125+
</template>
126+
}

app/assets/javascripts/admin/addon/components/admin-config-areas/about.gjs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { tracked } from "@glimmer/tracking";
33
import { action } from "@ember/object";
44
import AdminConfigAreaCard from "admin/components/admin-config-area-card";
55
import AdminConfigAreasAboutContactInformation from "admin/components/admin-config-area-cards/about/contact-information";
6+
import AdminConfigAreasAboutExtraGroups from "admin/components/admin-config-area-cards/about/extra-groups";
67
import AdminConfigAreasAboutGeneralSettings from "admin/components/admin-config-area-cards/about/general-settings";
78
import AdminConfigAreasAboutYourOrganization from "admin/components/admin-config-area-cards/about/your-organization";
89

@@ -39,6 +40,23 @@ export default class AdminConfigAreasAbout extends Component {
3940
};
4041
}
4142

43+
get extraGroups() {
44+
return {
45+
aboutPageExtraGroups: this.#lookupSettingFromData(
46+
"about_page_extra_groups"
47+
),
48+
aboutPageExtraGroupsInitialMembers: this.#lookupSettingFromData(
49+
"about_page_extra_groups_initial_members"
50+
),
51+
aboutPageExtraGroupsOrder: this.#lookupSettingFromData(
52+
"about_page_extra_groups_order"
53+
),
54+
aboutPageExtraGroupsShowDescription: this.#lookupSettingFromData(
55+
"about_page_extra_groups_show_description"
56+
),
57+
};
58+
}
59+
4260
@action
4361
setSavingStatus(status) {
4462
this.saving = status;
@@ -91,6 +109,20 @@ export default class AdminConfigAreasAbout extends Component {
91109
/>
92110
</:content>
93111
</AdminConfigAreaCard>
112+
<AdminConfigAreaCard
113+
@heading="admin.config_areas.about.extra_groups.heading"
114+
@description="admin.config_areas.about.extra_groups.description"
115+
@collapsable={{true}}
116+
class="admin-config-area-about__extra-groups-section"
117+
>
118+
<:content>
119+
<AdminConfigAreasAboutExtraGroups
120+
@extraGroups={{this.extraGroups}}
121+
@setGlobalSavingStatus={{this.setSavingStatus}}
122+
@globalSavingStatus={{this.saving}}
123+
/>
124+
</:content>
125+
</AdminConfigAreaCard>
94126
</div>
95127
</div>
96128
</template>
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import Component from "@glimmer/component";
2+
import { tracked } from "@glimmer/tracking";
3+
import { action } from "@ember/object";
4+
import { service } from "@ember/service";
5+
import { htmlSafe } from "@ember/template";
6+
import AboutPageUsers from "discourse/components/about-page-users";
7+
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
8+
import { ajax } from "discourse/lib/ajax";
9+
10+
export default class AboutPageExtraGroups extends Component {
11+
@service store;
12+
@service site;
13+
@service siteSettings;
14+
15+
@tracked groups = [];
16+
@tracked loading = false;
17+
18+
constructor() {
19+
super(...arguments);
20+
this.loadGroups();
21+
}
22+
23+
groupName(group) {
24+
return group.full_name || group.name.replace(/[_-]/g, " ");
25+
}
26+
27+
@action
28+
async loadGroups() {
29+
this.loading = true;
30+
try {
31+
const groupsSetting =
32+
this.siteSettings.about_page_extra_groups?.split("|").map(Number) || [];
33+
34+
let groupsToFetch = this.site.groups.filter((group) =>
35+
groupsSetting.includes(group.id)
36+
);
37+
38+
// ordered alphabetically by default
39+
if (
40+
this.siteSettings.about_page_extra_groups_order === "order of creation"
41+
) {
42+
groupsToFetch.sort((a, b) => a.id - b.id);
43+
}
44+
45+
const groupPromises = groupsToFetch.map(async (group) => {
46+
try {
47+
const groupDetails = await this.loadGroupDetails(group.name);
48+
group.members = await this.loadGroupMembers(group.name);
49+
Object.assign(group, groupDetails);
50+
return group;
51+
} catch (error) {
52+
// eslint-disable-next-line no-console
53+
console.error(
54+
`Error loading members for group ${group.name}:`,
55+
error
56+
);
57+
return null;
58+
}
59+
});
60+
61+
const groupsWithMembers = (await Promise.all(groupPromises)).filter(
62+
(group) => group && group.members.length > 0
63+
);
64+
65+
this.groups = groupsWithMembers;
66+
} catch (error) {
67+
// eslint-disable-next-line no-console
68+
console.error("Error loading groups:", error);
69+
this.groups = [];
70+
} finally {
71+
this.loading = false;
72+
}
73+
}
74+
75+
async loadGroupDetails(groupName) {
76+
try {
77+
const response = await ajax(`/g/${groupName}`);
78+
return response.group;
79+
} catch (error) {
80+
// eslint-disable-next-line no-console
81+
console.error(`Error loading details for group ${groupName}:`, error);
82+
return "";
83+
}
84+
}
85+
86+
async loadGroupMembers(groupName) {
87+
try {
88+
const response = await ajax(`/g/${groupName}/members?asc=true`);
89+
return response.members || [];
90+
} catch (error) {
91+
// eslint-disable-next-line no-console
92+
console.error(`Error loading members for group ${groupName}:`, error);
93+
return [];
94+
}
95+
}
96+
97+
get showGroupDescription() {
98+
return this.siteSettings.about_page_extra_groups_show_description;
99+
}
100+
101+
get showInitialMembers() {
102+
return this.siteSettings.about_page_extra_groups_initial_members;
103+
}
104+
105+
<template>
106+
<ConditionalLoadingSpinner @condition={{this.loading}}>
107+
{{#if this.groups}}
108+
{{#each this.groups as |group|}}
109+
<section
110+
class="about__{{group.name}}
111+
--custom-group
112+
{{if this.showGroupDescription '--has-description'}}"
113+
>
114+
<h3>
115+
<a href="/g/{{group.name}}">{{this.groupName group}}</a>
116+
</h3>
117+
{{#if this.showGroupDescription}}
118+
<p>{{htmlSafe group.bio_cooked}}</p>
119+
{{/if}}
120+
<AboutPageUsers
121+
@users={{group.members}}
122+
@truncateAt={{this.showInitialMembers}}
123+
/>
124+
</section>
125+
{{/each}}
126+
{{/if}}
127+
</ConditionalLoadingSpinner>
128+
</template>
129+
}

app/assets/javascripts/discourse/app/components/about-page.gjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { hash } from "@ember/helper";
33
import { LinkTo } from "@ember/routing";
44
import { service } from "@ember/service";
55
import { htmlSafe } from "@ember/template";
6+
import { isBlank } from "@ember/utils";
7+
import AboutPageExtraGroups from "discourse/components/about-page-extra-groups";
68
import AboutPageUsers from "discourse/components/about-page-users";
79
import PluginOutlet from "discourse/components/plugin-outlet";
810
import icon from "discourse/helpers/d-icon";
@@ -230,6 +232,13 @@ export default class AboutPage extends Component {
230232
return configs;
231233
}
232234

235+
get showExtraGroups() {
236+
return (
237+
this.siteSettings.show_additional_about_groups &&
238+
!isBlank(this.siteSettings.about_page_extra_groups)
239+
);
240+
}
241+
233242
<template>
234243
{{#if this.currentUser.admin}}
235244
<p>
@@ -294,6 +303,9 @@ export default class AboutPage extends Component {
294303
@connectorTagName="section"
295304
@outletArgs={{hash model=@model}}
296305
/>
306+
{{#if this.showExtraGroups}}
307+
<AboutPageExtraGroups />
308+
{{/if}}
297309
</div>
298310

299311
<div class="about__right-side">

app/assets/stylesheets/common/base/about.scss

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,36 @@
66
flex-wrap: wrap;
77
gap: 2em;
88
max-width: 1100px;
9+
10+
.--custom-group {
11+
max-width: unset;
12+
margin-top: 3em;
13+
14+
h3 {
15+
a {
16+
color: var(--primary);
17+
18+
&:hover {
19+
color: var(--tertiary);
20+
}
21+
}
22+
23+
&::first-letter {
24+
text-transform: capitalize;
25+
}
26+
}
27+
28+
p {
29+
margin-top: 0;
30+
color: var(--primary-high);
31+
}
32+
33+
&.--has-description {
34+
h3 {
35+
margin-bottom: 0;
36+
}
37+
}
38+
}
939
}
1040

1141
&__header {

app/controllers/admin/config/about_controller.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ def update
5757
}
5858
end
5959

60+
if extra_groups = params[:extra_groups]
61+
settings << { setting_name: "about_page_extra_groups", value: extra_groups[:groups] }
62+
settings << {
63+
setting_name: "about_page_extra_groups_initial_members",
64+
value: extra_groups[:initial_members],
65+
}
66+
settings << { setting_name: "about_page_extra_groups_order", value: extra_groups[:order] }
67+
settings << {
68+
setting_name: "about_page_extra_groups_show_description",
69+
value: extra_groups[:show_description],
70+
}
71+
end
72+
6073
SiteSetting::Update.call(
6174
guardian:,
6275
params: {

0 commit comments

Comments
 (0)