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

Commit 2f7895b

Browse files
UX: Applying more admin UI guidelines (#956)
This commit applies further admin UI guidelines, now that they have been more fleshed out in core, to the AI admin UI: * Tools * LLMs * Personas The changes include but are not limited to: * Applying the table CSS classes, for desktop and mobile * Adding a description and learn more link for each tab * Adding an empty list placeholder with CTA using `AdminConfigAreaEmptyList` * Replacing custom headings with `AdminPageSubheader`
1 parent 7a094cd commit 2f7895b

File tree

9 files changed

+177
-191
lines changed

9 files changed

+177
-191
lines changed
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
<AiToolEditor
2-
@tools={{this.allTools}}
3-
@model={{this.model}}
4-
@presets={{this.presets}}
5-
/>
1+
<section class="ai-persona-tool-editor__current admin-detail pull-left">
2+
<AiToolEditor
3+
@tools={{this.allTools}}
4+
@model={{this.model}}
5+
@presets={{this.presets}}
6+
/>
7+
</section>
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
<AiToolEditor
2-
@tools={{this.allTools}}
3-
@model={{this.model}}
4-
@presets={{this.presets}}
5-
/>
1+
<section class="ai-persona-tool-editor__current admin-detail pull-left">
2+
<AiToolEditor
3+
@tools={{this.allTools}}
4+
@model={{this.model}}
5+
@presets={{this.presets}}
6+
/>
7+
</section>

assets/javascripts/discourse/components/ai-llms-list-editor.gjs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { action } from "@ember/object";
44
import { LinkTo } from "@ember/routing";
55
import { service } from "@ember/service";
66
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
7-
import icon from "discourse-common/helpers/d-icon";
87
import i18n from "discourse-common/helpers/i18n";
98
import I18n from "discourse-i18n";
109
import AdminPageSubheader from "admin/components/admin-page-subheader";
@@ -124,8 +123,10 @@ export default class AiLlmsListEditor extends Component {
124123
<section class="ai-llms-list-editor__configured">
125124
<AdminPageSubheader
126125
@titleLabel="discourse_ai.llms.configured.title"
126+
@descriptionLabel="discourse_ai.llms.preconfigured.description"
127+
@learnMoreUrl="https://meta.discourse.org/t/discourse-ai-large-language-model-llm-settings-page/319903"
127128
/>
128-
<table>
129+
<table class="d-admin-table">
129130
<thead>
130131
<tr>
131132
<th>{{i18n "discourse_ai.llms.display_name"}}</th>
@@ -135,8 +136,11 @@ export default class AiLlmsListEditor extends Component {
135136
</thead>
136137
<tbody>
137138
{{#each @llms as |llm|}}
138-
<tr data-llm-id={{llm.name}} class="ai-llm-list__row">
139-
<td class="column-name">
139+
<tr
140+
data-llm-id={{llm.name}}
141+
class="ai-llm-list__row d-admin-row__content"
142+
>
143+
<td class="d-admin-row__overview">
140144
<h3>{{llm.display_name}}</h3>
141145
<p>
142146
{{this.modelDescription llm}}
@@ -149,18 +153,20 @@ export default class AiLlmsListEditor extends Component {
149153
</ul>
150154
{{/if}}
151155
</td>
152-
<td class="column-provider">
156+
<td class="d-admin-row__detail">
157+
<div class="d-admin-row__mobile-label">
158+
{{i18n "discourse_ai.llms.provider"}}
159+
</div>
153160
{{i18n
154161
(concat "discourse_ai.llms.providers." llm.provider)
155162
}}
156163
</td>
157-
<td class="column-edit">
164+
<td class="d-admin-row__controls">
158165
<LinkTo
159166
@route="adminPlugins.show.discourse-ai-llms.show"
160-
class="btn btn-default"
167+
class="btn btn-default btn-small ai-llm-list__edit-button"
161168
@model={{llm.id}}
162169
>
163-
{{icon "wrench"}}
164170
<div class="d-button-label">
165171
{{i18n "discourse_ai.llms.edit"}}
166172
</div>
@@ -173,7 +179,17 @@ export default class AiLlmsListEditor extends Component {
173179
</section>
174180
{{/if}}
175181
<section class="ai-llms-list-editor__templates">
176-
<AdminPageSubheader @titleLabel={{this.preconfiguredTitle}} />
182+
<AdminPageSubheader
183+
@titleLabel={{this.preconfiguredTitle}}
184+
@descriptionLabel={{unless
185+
this.hasLlmElements
186+
"discourse_ai.llms.preconfigured.description"
187+
}}
188+
@learnMoreUrl={{unless
189+
this.hasLlmElements
190+
"https://meta.discourse.org/t/discourse-ai-large-language-model-llm-settings-page/319903"
191+
}}
192+
/>
177193

178194
<AdminSectionLandingWrapper
179195
class="ai-llms-list-editor__templates-list"

assets/javascripts/discourse/components/ai-persona-list-editor.gjs

Lines changed: 69 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import Component from "@glimmer/component";
2-
import { tracked } from "@glimmer/tracking";
32
import { fn } from "@ember/helper";
43
import { on } from "@ember/modifier";
54
import { action } from "@ember/object";
@@ -9,26 +8,13 @@ import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
98
import DToggleSwitch from "discourse/components/d-toggle-switch";
109
import concatClass from "discourse/helpers/concat-class";
1110
import { popupAjaxError } from "discourse/lib/ajax-error";
12-
import { cook } from "discourse/lib/text";
13-
import icon from "discourse-common/helpers/d-icon";
1411
import i18n from "discourse-common/helpers/i18n";
15-
import I18n from "discourse-i18n";
12+
import AdminConfigAreaEmptyList from "admin/components/admin-config-area-empty-list";
13+
import AdminPageSubheader from "admin/components/admin-page-subheader";
1614
import AiPersonaEditor from "./ai-persona-editor";
1715

1816
export default class AiPersonaListEditor extends Component {
1917
@service adminPluginNavManager;
20-
@tracked _noPersonaText = null;
21-
22-
get noPersonaText() {
23-
if (this._noPersonaText === null) {
24-
const raw = I18n.t("discourse_ai.ai_persona.no_persona_selected");
25-
cook(raw).then((result) => {
26-
this._noPersonaText = result;
27-
});
28-
}
29-
30-
return this._noPersonaText;
31-
}
3218

3319
@action
3420
async toggleEnabled(persona) {
@@ -53,74 +39,76 @@ export default class AiPersonaListEditor extends Component {
5339
{{#if @currentPersona}}
5440
<AiPersonaEditor @model={{@currentPersona}} @personas={{@personas}} />
5541
{{else}}
56-
<div class="ai-persona-list-editor__header">
57-
<h3>{{i18n "discourse_ai.ai_persona.short_title"}}</h3>
58-
{{#unless @currentPersona.isNew}}
59-
<LinkTo
42+
<AdminPageSubheader
43+
@titleLabel="discourse_ai.ai_persona.short_title"
44+
@descriptionLabel="discourse_ai.ai_persona.persona_description"
45+
@learnMoreUrl="https://meta.discourse.org/t/ai-bot-personas/306099"
46+
>
47+
<:actions as |actions|>
48+
<actions.Primary
49+
@label="discourse_ai.ai_persona.new"
6050
@route="adminPlugins.show.discourse-ai-personas.new"
61-
class="btn btn-small btn-primary"
62-
>
63-
{{icon "plus"}}
64-
<span>{{I18n.t "discourse_ai.ai_persona.new"}}</span>
65-
</LinkTo>
66-
{{/unless}}
67-
</div>
51+
@icon="plus"
52+
class="ai-persona-list-editor__new-button"
53+
/>
54+
</:actions>
55+
</AdminPageSubheader>
6856

69-
<div class="ai-persona-list-editor__empty">
70-
<details class="details__boxed">
71-
<summary>{{i18n
72-
"discourse_ai.ai_persona.what_are_personas"
73-
}}</summary>
74-
{{this.noPersonaText}}
75-
</details>
76-
</div>
77-
78-
<table class="content-list ai-persona-list-editor">
79-
<thead>
80-
<tr>
81-
<th>{{i18n "discourse_ai.ai_persona.name"}}</th>
82-
<th>{{i18n "discourse_ai.ai_persona.enabled"}}</th>
83-
<th></th>
84-
</tr>
85-
</thead>
86-
<tbody>
87-
{{#each @personas as |persona|}}
88-
<tr
89-
data-persona-id={{persona.id}}
90-
class={{concatClass
91-
"ai-persona-list__row"
92-
(if persona.priority "priority")
93-
}}
94-
>
95-
<td>
96-
<div class="ai-persona-list__name-with-description">
97-
<div class="ai-persona-list__name">
98-
<strong>
99-
{{persona.name}}
100-
</strong>
101-
</div>
102-
<div class="ai-persona-list__description">
103-
{{persona.description}}
104-
</div>
105-
</div>
106-
</td>
107-
<td>
108-
<DToggleSwitch
109-
@state={{persona.enabled}}
110-
{{on "click" (fn this.toggleEnabled persona)}}
111-
/>
112-
</td>
113-
<td>
114-
<LinkTo
115-
@route="adminPlugins.show.discourse-ai-personas.show"
116-
@model={{persona}}
117-
class="btn btn-text btn-small"
118-
>{{i18n "discourse_ai.ai_persona.edit"}} </LinkTo>
119-
</td>
57+
{{#if @personas}}
58+
<table class="content-list ai-persona-list-editor d-admin-table">
59+
<thead>
60+
<tr>
61+
<th>{{i18n "discourse_ai.ai_persona.name"}}</th>
62+
<th>{{i18n "discourse_ai.ai_persona.enabled"}}</th>
63+
<th></th>
12064
</tr>
121-
{{/each}}
122-
</tbody>
123-
</table>
65+
</thead>
66+
<tbody>
67+
{{#each @personas as |persona|}}
68+
<tr
69+
data-persona-id={{persona.id}}
70+
class={{concatClass
71+
"ai-persona-list__row d-admin-row__content"
72+
(if persona.priority "priority")
73+
}}
74+
>
75+
<td class="d-admin-row__overview">
76+
<div class="ai-persona-list__name-with-description">
77+
<div class="ai-persona-list__name">
78+
<strong>
79+
{{persona.name}}
80+
</strong>
81+
</div>
82+
<div class="ai-persona-list__description">
83+
{{persona.description}}
84+
</div>
85+
</div>
86+
</td>
87+
<td class="d-admin-row__detail">
88+
<DToggleSwitch
89+
@state={{persona.enabled}}
90+
{{on "click" (fn this.toggleEnabled persona)}}
91+
/>
92+
</td>
93+
<td class="d-admin-row__controls">
94+
<LinkTo
95+
@route="adminPlugins.show.discourse-ai-personas.show"
96+
@model={{persona}}
97+
class="btn btn-text btn-small"
98+
>{{i18n "discourse_ai.ai_persona.edit"}} </LinkTo>
99+
</td>
100+
</tr>
101+
{{/each}}
102+
</tbody>
103+
</table>
104+
{{else}}
105+
<AdminConfigAreaEmptyList
106+
@ctaLabel="discourse_ai.ai_persona.new"
107+
@ctaRoute="adminPlugins.show.discourse-ai-personas.new"
108+
@ctaClass="ai-persona-list-editor__empty-new-button"
109+
@emptyLabel="discourse_ai.ai_persona.no_personas"
110+
/>
111+
{{/if}}
124112
{{/if}}
125113
</section>
126114
</template>

assets/javascripts/discourse/components/ai-tool-list-editor.gjs

Lines changed: 58 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import Component from "@glimmer/component";
22
import { LinkTo } from "@ember/routing";
33
import { service } from "@ember/service";
44
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
5-
import icon from "discourse-common/helpers/d-icon";
65
import i18n from "discourse-common/helpers/i18n";
76
import I18n from "discourse-i18n";
7+
import AdminConfigAreaEmptyList from "admin/components/admin-config-area-empty-list";
8+
import AdminPageSubheader from "admin/components/admin-page-subheader";
89

910
export default class AiToolListEditor extends Component {
1011
@service adminPluginNavManager;
@@ -15,44 +16,64 @@ export default class AiToolListEditor extends Component {
1516
@label={{i18n "discourse_ai.tools.short_title"}}
1617
/>
1718
<section class="ai-tool-list-editor__current admin-detail pull-left">
18-
<div class="ai-tool-list-editor__header">
19-
<h3>{{I18n.t "discourse_ai.tools.short_title"}}</h3>
20-
<LinkTo
21-
@route="adminPlugins.show.discourse-ai-tools.new"
22-
class="btn btn-small btn-primary ai-tool-list-editor__new-button"
23-
>
24-
{{icon "plus"}}
25-
<span>{{I18n.t "discourse_ai.tools.new"}}</span>
26-
</LinkTo>
27-
</div>
19+
<AdminPageSubheader
20+
@titleLabel="discourse_ai.tools.short_title"
21+
@learnMoreUrl="https://meta.discourse.org/t/ai-bot-custom-tools/314103"
22+
@descriptionLabel="discourse_ai.tools.subheader_description"
23+
>
24+
<:actions as |actions|>
25+
<actions.Primary
26+
@label="discourse_ai.tools.new"
27+
@route="adminPlugins.show.discourse-ai-tools.new"
28+
@icon="plus"
29+
class="ai-tool-list-editor__new-button"
30+
/>
31+
</:actions>
32+
</AdminPageSubheader>
2833

29-
<table class="content-list ai-tool-list-editor">
30-
<tbody>
31-
{{#each @tools as |tool|}}
32-
<tr data-tool-id={{tool.id}} class="ai-tool-list__row">
33-
<td>
34-
<div class="ai-tool-list__name-with-description">
35-
<div class="ai-tool-list__name">
36-
<strong>
37-
{{tool.name}}
38-
</strong>
34+
{{#if @tools}}
35+
<table class="d-admin-table ai-tool-list-editor">
36+
<thead>
37+
<th>{{i18n "discourse_ai.tools.name"}}</th>
38+
<th></th>
39+
</thead>
40+
<tbody>
41+
{{#each @tools as |tool|}}
42+
<tr
43+
data-tool-id={{tool.id}}
44+
class="ai-tool-list__row d-admin-row__content"
45+
>
46+
<td class="d-admin-row__overview">
47+
<div class="ai-tool-list__name-with-description">
48+
<div class="ai-tool-list__name">
49+
<strong>
50+
{{tool.name}}
51+
</strong>
52+
</div>
53+
<div class="ai-tool-list__description">
54+
{{tool.description}}
55+
</div>
3956
</div>
40-
<div class="ai-tool-list__description">
41-
{{tool.description}}
42-
</div>
43-
</div>
44-
</td>
45-
<td>
46-
<LinkTo
47-
@route="adminPlugins.show.discourse-ai-tools.show"
48-
@model={{tool}}
49-
class="btn btn-text btn-small"
50-
>{{I18n.t "discourse_ai.tools.edit"}}</LinkTo>
51-
</td>
52-
</tr>
53-
{{/each}}
54-
</tbody>
55-
</table>
57+
</td>
58+
<td class="d-admin-row__controls">
59+
<LinkTo
60+
@route="adminPlugins.show.discourse-ai-tools.show"
61+
@model={{tool}}
62+
class="btn btn-text btn-small"
63+
>{{I18n.t "discourse_ai.tools.edit"}}</LinkTo>
64+
</td>
65+
</tr>
66+
{{/each}}
67+
</tbody>
68+
</table>
69+
{{else}}
70+
<AdminConfigAreaEmptyList
71+
@ctaLabel="discourse_ai.tools.new"
72+
@ctaRoute="adminPlugins.show.discourse-ai-tools.new"
73+
@ctaClass="ai-tool-list-editor__empty-new-button"
74+
@emptyLabel="discourse_ai.tools.no_tools"
75+
/>
76+
{{/if}}
5677
</section>
5778
</template>
5879
}

0 commit comments

Comments
 (0)