Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit 98afd7f

Browse files
authored
FEATURE: Display features that rely on multiple personas. (#1411)
* FEATURE: Display features that rely on multiple personas. This change makes the previously hidden feature page visible while displaying features, like the AI helper, which relies on multiple personas. * Fix system specs
1 parent 33fd680 commit 98afd7f

File tree

17 files changed

+412
-335
lines changed

17 files changed

+412
-335
lines changed

admin/assets/javascripts/discourse/routes/admin-plugins-show-discourse-ai-features-edit.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default class AdminPluginsShowDiscourseAiFeaturesEdit extends DiscourseRo
1212

1313
const { site_settings } = await ajax("/admin/config/site_settings.json", {
1414
data: {
15-
filter_area: `ai-features/${currentFeature.ref}`,
15+
filter_area: `ai-features/${currentFeature.module_name}`,
1616
plugin: "discourse-ai",
1717
category: "discourse_ai",
1818
},

admin/assets/javascripts/discourse/templates/admin-plugins/show/discourse-ai-features/index.gjs

Lines changed: 0 additions & 156 deletions
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<AiFeatures @features={{this.model}} />

app/controllers/discourse_ai/admin/ai_features_controller.rb

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,22 @@ def index
1111

1212
def edit
1313
raise Discourse::InvalidParameters.new(:id) if params[:id].blank?
14-
render json: serialize_feature(DiscourseAi::Features.find_feature_by_id(params[:id].to_i))
14+
render json: serialize_module(DiscourseAi::Features.find_module_by_id(params[:id].to_i))
1515
end
1616

1717
private
1818

19-
def serialize_features(features)
20-
features.map { |feature| feature.merge(persona: serialize_persona(feature[:persona])) }
19+
def serialize_features(modules)
20+
modules.map { |a_module| serialize_module(a_module) }
2121
end
2222

23-
def serialize_feature(feature)
24-
return nil if feature.blank?
23+
def serialize_module(a_module)
24+
return nil if a_module.blank?
2525

26-
feature.merge(persona: serialize_persona(feature[:persona]))
26+
a_module.merge(
27+
features:
28+
a_module[:features].map { |f| f.merge(persona: serialize_persona(f[:persona])) },
29+
)
2730
end
2831

2932
def serialize_persona(persona)

assets/javascripts/discourse/admin/models/ai-feature.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,6 @@ import RestModel from "discourse/models/rest";
22

33
export default class AiFeature extends RestModel {
44
createProperties() {
5-
return this.getProperties(
6-
"id",
7-
"name",
8-
"ref",
9-
"description",
10-
"enable_setting",
11-
"persona",
12-
"persona_setting"
13-
);
5+
return this.getProperties("id", "module", "global_enabled", "features");
146
}
157
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { concat } from "@ember/helper";
2+
import { gt } from "truth-helpers";
3+
import DButton from "discourse/components/d-button";
4+
import { i18n } from "discourse-i18n";
5+
6+
const AiFeaturesList = <template>
7+
<div class="ai-features-list">
8+
{{#each @modules as |module|}}
9+
<div class="ai-module" data-module-name={{module.module_name}}>
10+
<div class="ai-module__header">
11+
<div class="ai-module__module-title">
12+
<h3>{{i18n
13+
(concat "discourse_ai.features." module.module_name ".name")
14+
}}</h3>
15+
<DButton
16+
class="edit"
17+
@label="discourse_ai.features.edit"
18+
@route="adminPlugins.show.discourse-ai-features.edit"
19+
@routeModels={{module.id}}
20+
/>
21+
</div>
22+
<div>{{i18n
23+
(concat
24+
"discourse_ai.features." module.module_name ".description"
25+
)
26+
}}</div>
27+
</div>
28+
29+
<div class="admin-section-landing-wrapper ai-feature-cards">
30+
{{#each module.features as |feature|}}
31+
<div
32+
class="admin-section-landing-item ai-feature-card"
33+
data-feature-name={{feature.name}}
34+
>
35+
<div class="admin-section-landing-item__content">
36+
<div class="ai-feature-card__feature-name">
37+
{{i18n
38+
(concat
39+
"discourse_ai.features."
40+
module.module_name
41+
"."
42+
feature.name
43+
)
44+
}}
45+
{{#unless feature.enabled}}
46+
<span>{{i18n "discourse_ai.features.disabled"}}</span>
47+
{{/unless}}
48+
</div>
49+
<div class="ai-feature-card__persona">
50+
<span>{{i18n "discourse_ai.features.persona"}}</span>
51+
{{#if feature.persona}}
52+
<DButton
53+
class="btn-flat btn-small ai-feature-card__persona-button"
54+
@translatedLabel={{feature.persona.name}}
55+
@route="adminPlugins.show.discourse-ai-personas.edit"
56+
@routeModels={{feature.persona.id}}
57+
/>
58+
{{else}}
59+
{{i18n "discourse_ai.features.no_persona"}}
60+
{{/if}}
61+
</div>
62+
{{#if feature.persona}}
63+
<div class="ai-feature-card__groups">
64+
<span>{{i18n "discourse_ai.features.groups"}}</span>
65+
{{#if (gt feature.persona.allowed_groups.length 0)}}
66+
<ul class="ai-feature-card__item-groups">
67+
{{#each feature.persona.allowed_groups as |group|}}
68+
<li>{{group.name}}</li>
69+
{{/each}}
70+
</ul>
71+
{{else}}
72+
{{i18n "discourse_ai.features.no_groups"}}
73+
{{/if}}
74+
</div>
75+
{{/if}}
76+
</div>
77+
</div>
78+
{{/each}}
79+
</div>
80+
</div>
81+
{{/each}}
82+
</div>
83+
</template>;
84+
85+
export default AiFeaturesList;
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import Component from "@glimmer/component";
2+
import { tracked } from "@glimmer/tracking";
3+
import { fn } from "@ember/helper";
4+
import { action } from "@ember/object";
5+
import { service } from "@ember/service";
6+
import { eq } from "truth-helpers";
7+
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
8+
import DButton from "discourse/components/d-button";
9+
import DPageSubheader from "discourse/components/d-page-subheader";
10+
import concatClass from "discourse/helpers/concat-class";
11+
import { i18n } from "discourse-i18n";
12+
import AiFeaturesList from "./ai-features-list";
13+
14+
const CONFIGURED = "configured";
15+
const UNCONFIGURED = "unconfigured";
16+
17+
export default class AiFeatures extends Component {
18+
@service adminPluginNavManager;
19+
20+
@tracked selectedFeatureGroup = CONFIGURED;
21+
22+
constructor() {
23+
super(...arguments);
24+
25+
if (this.configuredFeatures.length === 0) {
26+
this.selectedFeatureGroup = UNCONFIGURED;
27+
}
28+
}
29+
30+
get featureGroups() {
31+
return [
32+
{ id: CONFIGURED, label: "discourse_ai.features.nav.configured" },
33+
{ id: UNCONFIGURED, label: "discourse_ai.features.nav.unconfigured" },
34+
];
35+
}
36+
37+
get configuredFeatures() {
38+
return this.args.features.filter(
39+
(feature) => feature.module_enabled === true
40+
);
41+
}
42+
43+
get unconfiguredFeatures() {
44+
return this.args.features.filter(
45+
(feature) => feature.module_enabled === false
46+
);
47+
}
48+
49+
@action
50+
selectFeatureGroup(groupId) {
51+
this.selectedFeatureGroup = groupId;
52+
}
53+
54+
<template>
55+
<DBreadcrumbsItem
56+
@path="/admin/plugins/{{this.adminPluginNavManager.currentPlugin.name}}/ai-features"
57+
@label={{i18n "discourse_ai.features.short_title"}}
58+
/>
59+
<section class="ai-features admin-detail">
60+
<DPageSubheader
61+
@titleLabel={{i18n "discourse_ai.features.short_title"}}
62+
@descriptionLabel={{i18n "discourse_ai.features.description"}}
63+
@learnMoreUrl="todo"
64+
/>
65+
66+
<div class="ai-feature-groups">
67+
{{#each this.featureGroups as |groupData|}}
68+
<DButton
69+
class={{concatClass
70+
groupData.id
71+
(if
72+
(eq this.selectedFeatureGroup groupData.id)
73+
"btn-primary"
74+
"btn-default"
75+
)
76+
}}
77+
@action={{fn this.selectFeatureGroup groupData.id}}
78+
@label={{groupData.label}}
79+
/>
80+
{{/each}}
81+
</div>
82+
83+
{{#if (eq this.selectedFeatureGroup "configured")}}
84+
<AiFeaturesList @modules={{this.configuredFeatures}} />
85+
{{else}}
86+
<AiFeaturesList @modules={{this.unconfiguredFeatures}} />
87+
{{/if}}
88+
</section>
89+
</template>
90+
}

0 commit comments

Comments
 (0)