mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-07-08 15:22:47 +00:00
UX: add features to persona list and other style updates (#1405)
This commit is contained in:
parent
02bc9f645e
commit
22da440130
@ -9,15 +9,16 @@ module DiscourseAi
|
|||||||
|
|
||||||
def index
|
def index
|
||||||
ai_personas =
|
ai_personas =
|
||||||
AiPersona.ordered.map do |persona|
|
AiPersona
|
||||||
# we use a special serializer here cause names and descriptions are
|
.ordered
|
||||||
# localized for system personas
|
.includes(:user, :uploads)
|
||||||
LocalizedAiPersonaSerializer.new(persona, root: false)
|
.map { |persona| LocalizedAiPersonaSerializer.new(persona, root: false) }
|
||||||
end
|
|
||||||
tools =
|
tools =
|
||||||
DiscourseAi::Personas::Persona.all_available_tools.map do |tool|
|
DiscourseAi::Personas::Persona.all_available_tools.map do |tool|
|
||||||
AiToolSerializer.new(tool, root: false)
|
AiToolSerializer.new(tool, root: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
AiTool
|
AiTool
|
||||||
.where(enabled: true)
|
.where(enabled: true)
|
||||||
.each do |tool|
|
.each do |tool|
|
||||||
@ -31,10 +32,12 @@ module DiscourseAi
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
llms =
|
llms =
|
||||||
DiscourseAi::Configuration::LlmEnumerator.values_for_serialization(
|
DiscourseAi::Configuration::LlmEnumerator.values_for_serialization(
|
||||||
allowed_seeded_llm_ids: SiteSetting.ai_bot_allowed_seeded_models_map,
|
allowed_seeded_llm_ids: SiteSetting.ai_bot_allowed_seeded_models_map,
|
||||||
)
|
)
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
ai_personas: ai_personas,
|
ai_personas: ai_personas,
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -32,7 +32,8 @@ class LocalizedAiPersonaSerializer < ApplicationSerializer
|
|||||||
:allow_personal_messages,
|
:allow_personal_messages,
|
||||||
:force_default_llm,
|
:force_default_llm,
|
||||||
:response_format,
|
:response_format,
|
||||||
:examples
|
:examples,
|
||||||
|
:features
|
||||||
|
|
||||||
has_one :user, serializer: BasicUserSerializer, embed: :object
|
has_one :user, serializer: BasicUserSerializer, embed: :object
|
||||||
has_many :rag_uploads, serializer: UploadSerializer, embed: :object
|
has_many :rag_uploads, serializer: UploadSerializer, embed: :object
|
||||||
@ -53,4 +54,10 @@ class LocalizedAiPersonaSerializer < ApplicationSerializer
|
|||||||
def default_llm
|
def default_llm
|
||||||
LlmModel.find_by(id: object.default_llm_id)
|
LlmModel.find_by(id: object.default_llm_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def features
|
||||||
|
object.features.map do |feature|
|
||||||
|
{ id: feature.module_id, module_name: feature.module_name, name: feature.name }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,20 +1,114 @@
|
|||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { fn } from "@ember/helper";
|
import { tracked } from "@glimmer/tracking";
|
||||||
import { on } from "@ember/modifier";
|
import { concat, fn, hash } from "@ember/helper";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { LinkTo } from "@ember/routing";
|
import { LinkTo } from "@ember/routing";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
|
import { gt } from "truth-helpers";
|
||||||
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
|
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
import DPageSubheader from "discourse/components/d-page-subheader";
|
import DPageSubheader from "discourse/components/d-page-subheader";
|
||||||
import DToggleSwitch from "discourse/components/d-toggle-switch";
|
import DSelect from "discourse/components/d-select";
|
||||||
|
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||||
|
import FilterInput from "discourse/components/filter-input";
|
||||||
|
import avatar from "discourse/helpers/avatar";
|
||||||
import concatClass from "discourse/helpers/concat-class";
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
|
import icon from "discourse/helpers/d-icon";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { i18n } from "discourse-i18n";
|
import { i18n } from "discourse-i18n";
|
||||||
import AdminConfigAreaEmptyList from "admin/components/admin-config-area-empty-list";
|
import AdminConfigAreaEmptyList from "admin/components/admin-config-area-empty-list";
|
||||||
|
import DMenu from "float-kit/components/d-menu";
|
||||||
import AiPersonaEditor from "./ai-persona-editor";
|
import AiPersonaEditor from "./ai-persona-editor";
|
||||||
|
|
||||||
|
const LAYOUT_BUTTONS = [
|
||||||
|
{
|
||||||
|
id: "table",
|
||||||
|
label: "discourse_ai.layout.table",
|
||||||
|
icon: "discourse-table",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "card",
|
||||||
|
label: "discourse_ai.layout.card",
|
||||||
|
icon: "table",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default class AiPersonaListEditor extends Component {
|
export default class AiPersonaListEditor extends Component {
|
||||||
@service adminPluginNavManager;
|
@service adminPluginNavManager;
|
||||||
|
@service keyValueStore;
|
||||||
|
@service capabilities;
|
||||||
|
|
||||||
|
@tracked filterValue = "";
|
||||||
|
@tracked featureFilter = "all";
|
||||||
|
@tracked currentLayout = LAYOUT_BUTTONS[0];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
const savedLayoutId = this.keyValueStore.get("ai-persona-list-layout");
|
||||||
|
if (savedLayoutId) {
|
||||||
|
const found = LAYOUT_BUTTONS.find((b) => b.id === savedLayoutId);
|
||||||
|
if (found) {
|
||||||
|
this.currentLayout = found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get filteredPersonas() {
|
||||||
|
let personas = this.args.personas || [];
|
||||||
|
|
||||||
|
// Filter by feature if not "all"
|
||||||
|
if (this.featureFilter !== "all") {
|
||||||
|
personas = personas.filter((persona) =>
|
||||||
|
(persona.features || []).some(
|
||||||
|
(feature) => feature.module_name === this.featureFilter
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter by search term if present
|
||||||
|
if (this.filterValue) {
|
||||||
|
const term = this.filterValue.toLowerCase();
|
||||||
|
personas = personas.filter((persona) => {
|
||||||
|
const textMatches =
|
||||||
|
persona.name?.toLowerCase().includes(term) ||
|
||||||
|
persona.description?.toLowerCase().includes(term);
|
||||||
|
|
||||||
|
const featureMatches = (persona.features || []).some((feature) =>
|
||||||
|
feature.module_name?.toLowerCase().includes(term)
|
||||||
|
);
|
||||||
|
|
||||||
|
const llmMatches = persona.default_llm?.display_name
|
||||||
|
?.toLowerCase()
|
||||||
|
.includes(term);
|
||||||
|
|
||||||
|
return textMatches || featureMatches || llmMatches;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return personas;
|
||||||
|
}
|
||||||
|
|
||||||
|
get featureFilterOptions() {
|
||||||
|
let features = [];
|
||||||
|
(this.args.personas || []).forEach((persona) => {
|
||||||
|
(persona.features || []).forEach((feature) => {
|
||||||
|
if (feature?.module_name && !features.includes(feature.module_name)) {
|
||||||
|
features.push(feature.module_name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
features.sort();
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
value: "all",
|
||||||
|
label: i18n("discourse_ai.ai_persona.filters.all_features"),
|
||||||
|
},
|
||||||
|
...features.map((name) => ({
|
||||||
|
value: name,
|
||||||
|
label: i18n(`discourse_ai.features.${name}.name`),
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async toggleEnabled(persona) {
|
async toggleEnabled(persona) {
|
||||||
@ -30,12 +124,47 @@ export default class AiPersonaListEditor extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
onNameFilterChange(event) {
|
||||||
|
this.filterValue = event.target?.value || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
onFeatureFilterChange(value) {
|
||||||
|
this.featureFilter = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
resetAndFocus() {
|
||||||
|
this.filterValue = "";
|
||||||
|
this.featureFilter = "all";
|
||||||
|
document.querySelector(".admin-filter__input").focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
onRegisterApi(api) {
|
||||||
|
this.dMenu = api;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
onLayoutSelect(layoutId) {
|
||||||
|
const found = LAYOUT_BUTTONS.find((b) => b.id === layoutId);
|
||||||
|
if (found) {
|
||||||
|
this.currentLayout = found;
|
||||||
|
this.keyValueStore.set({
|
||||||
|
key: "ai-persona-list-layout",
|
||||||
|
value: layoutId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.dMenu.close();
|
||||||
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DBreadcrumbsItem
|
<DBreadcrumbsItem
|
||||||
@path="/admin/plugins/{{this.adminPluginNavManager.currentPlugin.name}}/ai-personas"
|
@path="/admin/plugins/{{this.adminPluginNavManager.currentPlugin.name}}/ai-personas"
|
||||||
@label={{i18n "discourse_ai.ai_persona.short_title"}}
|
@label={{i18n "discourse_ai.ai_persona.short_title"}}
|
||||||
/>
|
/>
|
||||||
<section class="ai-persona-list-editor__current admin-detail pull-left">
|
<section class="ai-persona-list-editor__current admin-detail">
|
||||||
{{#if @currentPersona}}
|
{{#if @currentPersona}}
|
||||||
<AiPersonaEditor @model={{@currentPersona}} @personas={{@personas}} />
|
<AiPersonaEditor @model={{@currentPersona}} @personas={{@personas}} />
|
||||||
{{else}}
|
{{else}}
|
||||||
@ -57,40 +186,139 @@ export default class AiPersonaListEditor extends Component {
|
|||||||
</DPageSubheader>
|
</DPageSubheader>
|
||||||
|
|
||||||
{{#if @personas}}
|
{{#if @personas}}
|
||||||
<table class="content-list ai-persona-list-editor d-admin-table">
|
<div class="ai-persona-list-editor__controls">
|
||||||
|
<FilterInput
|
||||||
|
placeholder={{i18n "discourse_ai.ai_persona.filters.text"}}
|
||||||
|
@filterAction={{this.onNameFilterChange}}
|
||||||
|
@value={{this.filterValue}}
|
||||||
|
class="admin-filter__input"
|
||||||
|
@icons={{hash left="magnifying-glass"}}
|
||||||
|
/>
|
||||||
|
<DSelect
|
||||||
|
@value={{this.featureFilter}}
|
||||||
|
@includeNone={{false}}
|
||||||
|
@onChange={{this.onFeatureFilterChange}}
|
||||||
|
as |select|
|
||||||
|
>
|
||||||
|
{{#each this.featureFilterOptions as |option|}}
|
||||||
|
<select.Option @value={{option.value}}>
|
||||||
|
{{option.label}}
|
||||||
|
</select.Option>
|
||||||
|
{{/each}}
|
||||||
|
</DSelect>
|
||||||
|
{{#if this.capabilities.viewport.md}}
|
||||||
|
<DMenu
|
||||||
|
@modalForMobile={{true}}
|
||||||
|
@autofocus={{true}}
|
||||||
|
@identifier="persona-list-layout"
|
||||||
|
@onRegisterApi={{this.onRegisterApi}}
|
||||||
|
@triggerClass="btn-default btn-icon"
|
||||||
|
>
|
||||||
|
<:trigger>
|
||||||
|
{{icon this.currentLayout.icon}}
|
||||||
|
</:trigger>
|
||||||
|
<:content>
|
||||||
|
<DropdownMenu as |dropdown|>
|
||||||
|
{{#each LAYOUT_BUTTONS as |button|}}
|
||||||
|
<dropdown.item>
|
||||||
|
<DButton
|
||||||
|
@label={{button.label}}
|
||||||
|
@icon={{button.icon}}
|
||||||
|
class="btn-transparent"
|
||||||
|
@action={{fn this.onLayoutSelect button.id}}
|
||||||
|
/>
|
||||||
|
</dropdown.item>
|
||||||
|
{{/each}}
|
||||||
|
</DropdownMenu>
|
||||||
|
</:content>
|
||||||
|
</DMenu>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<AdminConfigAreaEmptyList
|
||||||
|
@ctaLabel="discourse_ai.ai_persona.new"
|
||||||
|
@ctaRoute="adminPlugins.show.discourse-ai-personas.new"
|
||||||
|
@ctaClass="ai-persona-list-editor__empty-new-button"
|
||||||
|
@emptyLabel="discourse_ai.ai_persona.no_personas"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.filteredPersonas}}
|
||||||
|
<table
|
||||||
|
class={{concatClass
|
||||||
|
"content-list ai-persona-list-editor d-admin-table"
|
||||||
|
(concat "--layout-" this.currentLayout.id)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{i18n "discourse_ai.ai_persona.name"}}</th>
|
<th>{{i18n "discourse_ai.ai_persona.name"}}</th>
|
||||||
<th>{{i18n "discourse_ai.ai_persona.list.enabled"}}</th>
|
<th>{{i18n "discourse_ai.llms.short_title"}}</th>
|
||||||
<th></th>
|
<th>{{i18n "discourse_ai.features.short_title"}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#each @personas as |persona|}}
|
{{#each this.filteredPersonas as |persona|}}
|
||||||
<tr
|
<tr
|
||||||
data-persona-id={{persona.id}}
|
data-persona-id={{persona.id}}
|
||||||
class={{concatClass
|
class={{concatClass
|
||||||
"ai-persona-list__row d-admin-row__content"
|
"ai-persona-list__row d-admin-row__content"
|
||||||
(if persona.priority "priority")
|
(if persona.priority "--priority")
|
||||||
|
(if persona.enabled "--enabled")
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<td class="d-admin-row__overview">
|
<td class="d-admin-row__overview">
|
||||||
<div class="ai-persona-list__name-with-description">
|
<div class="ai-persona-list__name-with-description">
|
||||||
<div class="ai-persona-list__name">
|
<h3 class="ai-persona-list__name">
|
||||||
<strong>
|
{{#if persona.user}}
|
||||||
|
{{avatar persona.user imageSize="tiny"}}
|
||||||
|
{{/if}}
|
||||||
{{persona.name}}
|
{{persona.name}}
|
||||||
</strong>
|
</h3>
|
||||||
</div>
|
|
||||||
<div class="ai-persona-list__description">
|
<div class="ai-persona-list__description">
|
||||||
{{persona.description}}
|
{{persona.description}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="d-admin-row__detail">
|
<td class="d-admin-row__llms">
|
||||||
<DToggleSwitch
|
{{#if persona.default_llm}}
|
||||||
@state={{persona.enabled}}
|
<span class="--card-label">
|
||||||
{{on "click" (fn this.toggleEnabled persona)}}
|
{{i18n "discourse_ai.ai_persona.llms_list"}}
|
||||||
|
</span>
|
||||||
|
<DButton
|
||||||
|
class="btn-flat btn-small ai-persona-list__row-item-feature"
|
||||||
|
@translatedLabel={{persona.default_llm.display_name}}
|
||||||
|
@route="adminPlugins.show.discourse-ai-llms.edit"
|
||||||
|
@routeModels={{persona.default_llm.id}}
|
||||||
/>
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</td>
|
||||||
|
<td class="d-admin-row__features">
|
||||||
|
{{#if persona.features.length}}
|
||||||
|
<span class="--card-label">
|
||||||
|
{{i18n
|
||||||
|
"discourse_ai.ai_persona.features_list"
|
||||||
|
count=persona.features.length
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
{{#each persona.features as |feature index|}}
|
||||||
|
<span class="d-admin-row__row-feature-list">
|
||||||
|
{{#if (gt index 0)}}, {{/if}}
|
||||||
|
<DButton
|
||||||
|
class="btn-flat btn-small ai-persona-list__row-item-feature"
|
||||||
|
@translatedLabel={{i18n
|
||||||
|
(concat
|
||||||
|
"discourse_ai.features."
|
||||||
|
feature.module_name
|
||||||
|
".name"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
@route="adminPlugins.show.discourse-ai-features.edit"
|
||||||
|
@routeModels={{feature.id}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
<td class="d-admin-row__controls">
|
<td class="d-admin-row__controls">
|
||||||
<LinkTo
|
<LinkTo
|
||||||
@ -104,12 +332,17 @@ export default class AiPersonaListEditor extends Component {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{else}}
|
{{else}}
|
||||||
<AdminConfigAreaEmptyList
|
<div class="ai-persona-list-editor__no-results">
|
||||||
@ctaLabel="discourse_ai.ai_persona.new"
|
|
||||||
@ctaRoute="adminPlugins.show.discourse-ai-personas.new"
|
<h3>{{i18n "discourse_ai.ai_persona.filters.no_results"}}</h3>
|
||||||
@ctaClass="ai-persona-list-editor__empty-new-button"
|
|
||||||
@emptyLabel="discourse_ai.ai_persona.no_personas"
|
<DButton
|
||||||
|
@icon="arrow-rotate-left"
|
||||||
|
@label="discourse_ai.ai_persona.filters.reset"
|
||||||
|
@action={{this.resetAndFocus}}
|
||||||
|
class="btn-default"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</section>
|
</section>
|
||||||
|
@ -1,8 +1,28 @@
|
|||||||
|
@use "lib/viewport";
|
||||||
|
|
||||||
.admin-contents .ai-persona-list-editor {
|
.admin-contents .ai-persona-list-editor {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-persona-list-editor {
|
.ai-persona-list-editor {
|
||||||
|
@include viewport.until(md) {
|
||||||
|
td {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&.d-admin-row__llms,
|
||||||
|
&.d-admin-row__features {
|
||||||
|
padding-block: 0;
|
||||||
|
|
||||||
|
.--card-label {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: var(--font-down-1);
|
||||||
|
color: var(--primary-high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -21,6 +41,163 @@
|
|||||||
li.disabled {
|
li.disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__controls {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-2);
|
||||||
|
margin-bottom: var(--space-4);
|
||||||
|
|
||||||
|
.filter-input-container {
|
||||||
|
flex: 4 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-select {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__no-results {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: var(--space-6);
|
||||||
|
gap: var(--space-2);
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--layout-table {
|
||||||
|
.--card-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.--layout-card {
|
||||||
|
tbody {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(18em, 1fr));
|
||||||
|
gap: var(--space-4);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-admin-row__content {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr auto auto;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
border: 1px solid var(--primary-low);
|
||||||
|
padding: var(--space-2) var(--space-4) var(--space-4);
|
||||||
|
border-radius: var(--d-border-radius);
|
||||||
|
|
||||||
|
.d-admin-row__overview,
|
||||||
|
.ai-persona-list__name-with-description {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-persona-list__name {
|
||||||
|
grid-row: 1;
|
||||||
|
grid-column: 1;
|
||||||
|
font-size: var(--font-up-1);
|
||||||
|
display: inline;
|
||||||
|
align-self: center;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
height: 1.25em;
|
||||||
|
position: relative;
|
||||||
|
bottom: 0.15em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-persona-list__description {
|
||||||
|
grid-row: 2;
|
||||||
|
grid-column: 1;
|
||||||
|
margin: var(--space-2) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-admin-row__controls {
|
||||||
|
grid-row: 1;
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-admin-row__features {
|
||||||
|
grid-row: 4;
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin-top: var(--space-0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-admin-row__llms {
|
||||||
|
grid-row: 3;
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin-top: var(--space-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.--card-label {
|
||||||
|
color: var(--primary-high);
|
||||||
|
font-size: var(--font-down-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-persona-list {
|
||||||
|
&__row-item-feature {
|
||||||
|
padding: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
color: var(--primary-high);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-1);
|
||||||
|
font-size: var(--font-up-0);
|
||||||
|
color: var(--primary);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: var(--line-height-medium);
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: auto;
|
||||||
|
height: 1.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__row {
|
||||||
|
&:hover {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__overview {
|
||||||
|
padding-left: var(--space-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-admin-row__row-feature-list {
|
||||||
|
color: var(--primary-medium);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-persona-tool-option-editor {
|
.ai-persona-tool-option-editor {
|
||||||
|
@ -211,10 +211,13 @@ en:
|
|||||||
custom_prompt: "Custom prompt"
|
custom_prompt: "Custom prompt"
|
||||||
image_caption: "Caption images"
|
image_caption: "Caption images"
|
||||||
|
|
||||||
|
|
||||||
modals:
|
modals:
|
||||||
select_option: "Select an option..."
|
select_option: "Select an option..."
|
||||||
|
|
||||||
|
layout:
|
||||||
|
table: "Table"
|
||||||
|
card: "Card"
|
||||||
|
|
||||||
spam:
|
spam:
|
||||||
short_title: "Spam"
|
short_title: "Spam"
|
||||||
title: "Configure spam handling"
|
title: "Configure spam handling"
|
||||||
@ -379,6 +382,18 @@ en:
|
|||||||
title: "AI bot options"
|
title: "AI bot options"
|
||||||
save_first: "More AI bot options will become available once you save the persona."
|
save_first: "More AI bot options will become available once you save the persona."
|
||||||
|
|
||||||
|
filters:
|
||||||
|
text: "Find a persona"
|
||||||
|
reset: "Reset"
|
||||||
|
no_results: "No personas found matching your filters."
|
||||||
|
all_features: "Any feature"
|
||||||
|
|
||||||
|
features_list:
|
||||||
|
one: "Feature:"
|
||||||
|
other: "Features:"
|
||||||
|
|
||||||
|
llms_list: "LLM:"
|
||||||
|
|
||||||
rag:
|
rag:
|
||||||
title: "RAG"
|
title: "RAG"
|
||||||
options:
|
options:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user