2
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2025-10-03 17:21:20 +08:00

DEV: Reapply gjs-codemod in d-ai (#33758)

…and apply other mass-pr autofixes
This commit is contained in:
Jarek Radosz 2025-07-23 12:05:40 +02:00 committed by GitHub
parent fcd022b5b3
commit 16c0838575
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
105 changed files with 563 additions and 412 deletions

View file

@ -9,13 +9,4 @@ module.exports = {
"no-action": true, "no-action": true,
"require-strict-mode": true, "require-strict-mode": true,
}, },
overrides: [
...templateLint.overrides,
{
files: ["plugins/discourse-ai/**/*"],
rules: {
"require-strict-mode": false, // some AI plugin templates are not strict mode compatible
},
},
],
}; };

View file

@ -0,0 +1,11 @@
import RouteTemplate from "ember-route-template";
import AiEmbeddingsListEditor from "../../../../../discourse/components/ai-embeddings-list-editor";

export default RouteTemplate(
<template>
<AiEmbeddingsListEditor
@embeddings={{@controller.allEmbeddings}}
@currentEmbedding={{@controller.model}}
/>
</template>
);

View file

@ -1,4 +0,0 @@
<AiEmbeddingsListEditor
@embeddings={{this.allEmbeddings}}
@currentEmbedding={{this.model}}
/>

View file

@ -0,0 +1,8 @@
import RouteTemplate from "ember-route-template";
import AiEmbeddingsListEditor from "../../../../../discourse/components/ai-embeddings-list-editor";

export default RouteTemplate(
<template>
<AiEmbeddingsListEditor @embeddings={{@controller.model}} />
</template>
);

View file

@ -1 +0,0 @@
<AiEmbeddingsListEditor @embeddings={{this.model}} />

View file

@ -0,0 +1,11 @@
import RouteTemplate from "ember-route-template";
import AiEmbeddingsListEditor from "../../../../../discourse/components/ai-embeddings-list-editor";

export default RouteTemplate(
<template>
<AiEmbeddingsListEditor
@embeddings={{@controller.allEmbeddings}}
@currentEmbedding={{@controller.model}}
/>
</template>
);

View file

@ -1,4 +0,0 @@
<AiEmbeddingsListEditor
@embeddings={{this.allEmbeddings}}
@currentEmbedding={{this.model}}
/>

View file

@ -0,0 +1,6 @@
import RouteTemplate from "ember-route-template";
import AiFeatures from "../../../../../discourse/components/ai-features";

export default RouteTemplate(
<template><AiFeatures @features={{@controller.model}} /></template>
);

View file

@ -0,0 +1,11 @@
import RouteTemplate from "ember-route-template";
import AiLlmsListEditor from "../../../../../discourse/components/ai-llms-list-editor";

export default RouteTemplate(
<template>
<AiLlmsListEditor
@llms={{@controller.allLlms}}
@currentLlm={{@controller.model}}
/>
</template>
);

View file

@ -1 +0,0 @@
<AiLlmsListEditor @llms={{this.allLlms}} @currentLlm={{this.model}} />

View file

@ -0,0 +1,6 @@
import RouteTemplate from "ember-route-template";
import AiLlmsListEditor from "../../../../../discourse/components/ai-llms-list-editor";

export default RouteTemplate(
<template><AiLlmsListEditor @llms={{@controller.model}} /></template>
);

View file

@ -0,0 +1,12 @@
import RouteTemplate from "ember-route-template";
import AiLlmsListEditor from "../../../../../discourse/components/ai-llms-list-editor";

export default RouteTemplate(
<template>
<AiLlmsListEditor
@llms={{@controller.allLlms}}
@currentLlm={{@controller.model}}
@llmTemplate={{@controller.llmTemplate}}
/>
</template>
);

View file

@ -1,5 +0,0 @@
<AiLlmsListEditor
@llms={{this.allLlms}}
@currentLlm={{this.model}}
@llmTemplate={{this.llmTemplate}}
/>

View file

@ -0,0 +1,11 @@
import RouteTemplate from "ember-route-template";
import AiPersonaListEditor from "../../../../../discourse/components/ai-persona-list-editor";

export default RouteTemplate(
<template>
<AiPersonaListEditor
@personas={{@controller.allPersonas}}
@currentPersona={{@controller.model}}
/>
</template>
);

View file

@ -1,4 +0,0 @@
<AiPersonaListEditor
@personas={{this.allPersonas}}
@currentPersona={{this.model}}
/>

View file

@ -0,0 +1,6 @@
import RouteTemplate from "ember-route-template";
import AiPersonaListEditor from "../../../../../discourse/components/ai-persona-list-editor";

export default RouteTemplate(
<template><AiPersonaListEditor @personas={{@controller.model}} /></template>
);

View file

@ -0,0 +1,11 @@
import RouteTemplate from "ember-route-template";
import AiPersonaListEditor from "../../../../../discourse/components/ai-persona-list-editor";

export default RouteTemplate(
<template>
<AiPersonaListEditor
@personas={{@controller.allPersonas}}
@currentPersona={{@controller.model}}
/>
</template>
);

View file

@ -1,4 +0,0 @@
<AiPersonaListEditor
@personas={{this.allPersonas}}
@currentPersona={{this.model}}
/>

View file

@ -0,0 +1,6 @@
import RouteTemplate from "ember-route-template";
import AiSpam from "../../../../discourse/components/ai-spam";

export default RouteTemplate(
<template><AiSpam @model={{@controller.model}} /></template>
);

View file

@ -0,0 +1,16 @@
import RouteTemplate from "ember-route-template";
import AiToolEditor from "../../../../../discourse/components/ai-tool-editor";

export default RouteTemplate(
<template>
<section class="ai-persona-tool-editor__current admin-detail pull-left">
<AiToolEditor
@tools={{@controller.allTools}}
@model={{@controller.model}}
@presets={{@controller.presets}}
@llms={{@controller.llms}}
@settings={{@controller.settings}}
/>
</section>
</template>
);

View file

@ -1,9 +0,0 @@
<section class="ai-persona-tool-editor__current admin-detail pull-left">
<AiToolEditor
@tools={{this.allTools}}
@model={{this.model}}
@presets={{this.presets}}
@llms={{this.llms}}
@settings={{this.settings}}
/>
</section>

View file

@ -0,0 +1,6 @@
import RouteTemplate from "ember-route-template";
import AiToolListEditor from "../../../../../discourse/components/ai-tool-list-editor";

export default RouteTemplate(
<template><AiToolListEditor @tools={{@controller.model}} /></template>
);

View file

@ -0,0 +1,17 @@
import RouteTemplate from "ember-route-template";
import AiToolEditor from "../../../../../discourse/components/ai-tool-editor";

export default RouteTemplate(
<template>
<section class="ai-persona-tool-editor__current admin-detail pull-left">
<AiToolEditor
@tools={{@controller.allTools}}
@model={{@controller.model}}
@presets={{@controller.presets}}
@llms={{@controller.llms}}
@settings={{@controller.settings}}
@selectedPreset={{@controller.selectedPreset}}
/>
</section>
</template>
);

View file

@ -1,10 +0,0 @@
<section class="ai-persona-tool-editor__current admin-detail pull-left">
<AiToolEditor
@tools={{this.allTools}}
@model={{this.model}}
@presets={{this.presets}}
@llms={{this.llms}}
@settings={{this.settings}}
@selectedPreset={{this.selectedPreset}}
/>
</section>

View file

@ -0,0 +1,6 @@
import RouteTemplate from "ember-route-template";
import AiUsage from "../../../../discourse/components/ai-usage";

export default RouteTemplate(
<template><AiUsage @model={{@controller.model}} /></template>
);

View file

@ -0,0 +1,89 @@
import Component from "@ember/component";
import { attributeBindings, classNames } from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import number from "discourse/helpers/number";
import getURL from "discourse/lib/get-url";

@classNames("admin-report-counters")
@attributeBindings("model.description:title")
export default class AdminReportEmotion extends Component {
get todayLink() {
let date = moment().format("YYYY-MM-DD");
return this._filterURL(date);
}

get yesterdayLink() {
let date = moment().subtract(1, "day").format("YYYY-MM-DD");
return this._filterURL(date);
}

get lastSevenDaysLink() {
let date = moment().subtract(1, "week").format("YYYY-MM-DD");
return this._filterURL(date);
}

get lastThirtyDaysLink() {
let date = moment().subtract(1, "month").format("YYYY-MM-DD");
return this._filterURL(date);
}

_baseFilter() {
return "/filter?q=activity-after%3A";
}

_model() {
return "%20order%3A" + this.model.type;
}

_filterURL(date) {
return getURL(`${this._baseFilter()}${date}${this._model()}`);
}

<template>
<div class="cell title">
{{#if this.model.icon}}
{{icon this.model.icon}}
{{/if}}
{{this.model.title}}
</div>

<div class="cell value today-count">
<a href={{this.todayLink}}>
{{number this.model.todayCount}}
</a>
</div>

<div
class="cell value yesterday-count {{this.model.yesterdayTrend}}"
title={{this.model.yesterdayCountTitle}}
>
<a href={{this.yesterdayLink}}>
{{number this.model.yesterdayCount}}
</a>
{{icon this.model.yesterdayTrendIcon}}
</div>

<div
class="cell value sevendays-count {{this.model.sevenDaysTrend}}"
title={{this.model.sevenDaysCountTitle}}
>
<a href={{this.lastSevenDaysLink}}>
{{number this.model.lastSevenDaysCount}}
</a>
{{icon this.model.sevenDaysTrendIcon}}
</div>

<div
class="cell value thirty-days-count {{this.model.thirtyDaysTrend}}"
title={{this.model.thirtyDaysCountTitle}}
>

<a href={{this.lastThirtyDaysLink}}>
{{number this.model.lastThirtyDaysCount}}
</a>
{{#if this.model.canDisplayTrendIcon}}
{{icon this.model.thirtyDaysTrendIcon}}
{{/if}}
</div>
</template>
}

View file

@ -1,45 +0,0 @@
<div class="cell title">
{{#if this.model.icon}}
{{d-icon this.model.icon}}
{{/if}}
{{this.model.title}}
</div>

<div class="cell value today-count">
<a href={{this.todayLink}}>
{{number this.model.todayCount}}
</a>
</div>

<div
class="cell value yesterday-count {{this.model.yesterdayTrend}}"
title={{this.model.yesterdayCountTitle}}
>
<a href={{this.yesterdayLink}}>
{{number this.model.yesterdayCount}}
</a>
{{d-icon this.model.yesterdayTrendIcon}}
</div>

<div
class="cell value sevendays-count {{this.model.sevenDaysTrend}}"
title={{this.model.sevenDaysCountTitle}}
>
<a href={{this.lastSevenDaysLink}}>
{{number this.model.lastSevenDaysCount}}
</a>
{{d-icon this.model.sevenDaysTrendIcon}}
</div>

<div
class="cell value thirty-days-count {{this.model.thirtyDaysTrend}}"
title={{this.model.thirtyDaysCountTitle}}
>

<a href={{this.lastThirtyDaysLink}}>
{{number this.model.lastThirtyDaysCount}}
</a>
{{#if this.model.canDisplayTrendIcon}}
{{d-icon this.model.thirtyDaysTrendIcon}}
{{/if}}
</div>

View file

@ -1,39 +0,0 @@
import Component from "@ember/component";
import { attributeBindings, classNames } from "@ember-decorators/component";
import getURL from "discourse/lib/get-url";

@classNames("admin-report-counters")
@attributeBindings("model.description:title")
export default class AdminReportEmotion extends Component {
get todayLink() {
let date = moment().format("YYYY-MM-DD");
return this._filterURL(date);
}

get yesterdayLink() {
let date = moment().subtract(1, "day").format("YYYY-MM-DD");
return this._filterURL(date);
}

get lastSevenDaysLink() {
let date = moment().subtract(1, "week").format("YYYY-MM-DD");
return this._filterURL(date);
}

get lastThirtyDaysLink() {
let date = moment().subtract(1, "month").format("YYYY-MM-DD");
return this._filterURL(date);
}

_baseFilter() {
return "/filter?q=activity-after%3A";
}

_model() {
return "%20order%3A" + this.model.type;
}

_filterURL(date) {
return getURL(`${this._baseFilter()}${date}${this._model()}`);
}
}

View file

@ -12,7 +12,7 @@ import HorizontalOverflowNav from "discourse/components/horizontal-overflow-nav"
import PostList from "discourse/components/post-list"; import PostList from "discourse/components/post-list";
import bodyClass from "discourse/helpers/body-class"; import bodyClass from "discourse/helpers/body-class";
import categoryBadge from "discourse/helpers/category-badge"; import categoryBadge from "discourse/helpers/category-badge";
import dIcon from "discourse/helpers/d-icon"; import icon from "discourse/helpers/d-icon";
import replaceEmoji from "discourse/helpers/replace-emoji"; import replaceEmoji from "discourse/helpers/replace-emoji";
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";
@ -440,7 +440,7 @@ export default class AdminReportSentimentAnalysis extends Component {
class="admin-report-sentiment-analysis-details__post-score" class="admin-report-sentiment-analysis-details__post-score"
data-sentiment-score={{sentiment.id}} data-sentiment-score={{sentiment.id}}
> >
{{dIcon sentiment.icon}} {{icon sentiment.icon}}
{{sentiment.text}} {{sentiment.text}}
</span> </span>
{{/let}} {{/let}}

View file

@ -10,7 +10,7 @@ import DPageSubheader from "discourse/components/d-page-subheader";
import DStatTiles from "discourse/components/d-stat-tiles"; import DStatTiles from "discourse/components/d-stat-tiles";
import DToggleSwitch from "discourse/components/d-toggle-switch"; import DToggleSwitch from "discourse/components/d-toggle-switch";
import DTooltip from "discourse/components/d-tooltip"; import DTooltip from "discourse/components/d-tooltip";
import dIcon from "discourse/helpers/d-icon"; import icon from "discourse/helpers/d-icon";
import withEventValue from "discourse/helpers/with-event-value"; import withEventValue from "discourse/helpers/with-event-value";
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";
@ -218,7 +218,7 @@ export default class AiSpam extends Component {
<div class="ai-spam__errors"> <div class="ai-spam__errors">
{{#each this.errors as |e|}} {{#each this.errors as |e|}}
<div class="alert alert-error"> <div class="alert alert-error">
{{dIcon "triangle-exclamation"}} {{icon "triangle-exclamation"}}
<p>{{e.message}}</p> <p>{{e.message}}</p>
<DButton <DButton
@action={{e.button.action}} @action={{e.button.action}}

View file

@ -11,7 +11,7 @@ import CookText from "discourse/components/cook-text";
import DButton from "discourse/components/d-button"; import DButton from "discourse/components/d-button";
import DModal from "discourse/components/d-modal"; import DModal from "discourse/components/d-modal";
import concatClass from "discourse/helpers/concat-class"; import concatClass from "discourse/helpers/concat-class";
import dIcon from "discourse/helpers/d-icon"; import icon from "discourse/helpers/d-icon";
import htmlClass from "discourse/helpers/html-class"; import htmlClass from "discourse/helpers/html-class";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { bind } from "discourse/lib/decorators"; import { bind } from "discourse/lib/decorators";
@ -210,7 +210,7 @@ export default class AiSummaryModal extends Component {
{{i18n "summary.summarized_on" date=this.summarizedOn}} {{i18n "summary.summarized_on" date=this.summarizedOn}}
<DTooltip @placements={{array "top-end"}}> <DTooltip @placements={{array "top-end"}}>
<:trigger> <:trigger>
{{dIcon "circle-info"}} {{icon "circle-info"}}
</:trigger> </:trigger>
<:content> <:content>
{{i18n "summary.model_used" model=this.summarizedBy}} {{i18n "summary.model_used" model=this.summarizedBy}}

View file

@ -0,0 +1,20 @@
import { i18n } from "discourse-i18n";

const ModelAccuracies = <template>
{{#if @accuracies}}
<table class="reviewable-scores">
<tbody>
{{#each-in @accuracies as |model acc|}}
<tr>
<td colspan="4">{{i18n "discourse_ai.reviewables.model_used"}}</td>
<td colspan="3">{{model}}</td>
<td colspan="4">{{i18n "discourse_ai.reviewables.accuracy"}}</td>
<td colspan="3">{{acc}}%</td>
</tr>
{{/each-in}}
</tbody>
</table>
{{/if}}
</template>;

export default ModelAccuracies;

View file

@ -1,14 +0,0 @@
{{#if @accuracies}}
<table class="reviewable-scores">
<tbody>
{{#each-in @accuracies as |model acc|}}
<tr>
<td colspan="4">{{i18n "discourse_ai.reviewables.model_used"}}</td>
<td colspan="3">{{model}}</td>
<td colspan="4">{{i18n "discourse_ai.reviewables.accuracy"}}</td>
<td colspan="3">{{acc}}%</td>
</tr>
{{/each-in}}
</tbody>
</table>
{{/if}}

View file

@ -0,0 +1,60 @@
import Component from "@glimmer/component";
import { array } from "@ember/helper";
import { LinkTo } from "@ember/routing";
import { or } from "truth-helpers";
import ReviewableCreatedBy from "discourse/components/reviewable-created-by";
import ReviewablePostHeader from "discourse/components/reviewable-post-header";
import htmlSafe from "discourse/helpers/html-safe";
import ChatChannelTitle from "discourse/plugins/chat/discourse/components/chat-channel-title";
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
import ModelAccuracies from "./model-accuracies";

export default class ReviewableAiChatMessage extends Component {
get chatChannel() {
if (!this.args.reviewable.chat_channel) {
return;
}
return ChatChannel.create(this.args.reviewable.chat_channel);
}

<template>
{{#if this.chatChannel}}
<div class="flagged-post-header">
<LinkTo
@route="chat.channel.near-message"
@models={{array
this.chatChannel.slugifiedTitle
this.chatChannel.id
@reviewable.target_id
}}
>
<ChatChannelTitle @channel={{this.chatChannel}} />
</LinkTo>
</div>
{{/if}}

<div class="post-contents-wrapper">
<ReviewableCreatedBy
@user={{@reviewable.target_created_by}}
@tagName=""
/>
<div class="post-contents">
<ReviewablePostHeader
@reviewable={{@reviewable}}
@createdBy={{@reviewable.target_created_by}}
@tagName=""
/>

<div class="post-body">
{{htmlSafe
(or @reviewable.payload.message_cooked @reviewable.cooked)
}}
</div>

{{yield}}

<ModelAccuracies @accuracies={{@reviewable.payload.accuracies}} />
</div>
</div>
</template>
}

View file

@ -1,33 +0,0 @@
{{#if this.chatChannel}}
<div class="flagged-post-header">
<LinkTo
@route="chat.channel.near-message"
@models={{array
this.chatChannel.slugifiedTitle
this.chatChannel.id
@reviewable.target_id
}}
>
<ChatChannelTitle @channel={{this.chatChannel}} />
</LinkTo>
</div>
{{/if}}

<div class="post-contents-wrapper">
<ReviewableCreatedBy @user={{@reviewable.target_created_by}} @tagName="" />
<div class="post-contents">
<ReviewablePostHeader
@reviewable={{@reviewable}}
@createdBy={{@reviewable.target_created_by}}
@tagName=""
/>

<div class="post-body">
{{html-safe (or @reviewable.payload.message_cooked @reviewable.cooked)}}
</div>

{{yield}}

<ModelAccuracies @accuracies={{@reviewable.payload.accuracies}} />
</div>
</div>

View file

@ -1,11 +0,0 @@
import Component from "@glimmer/component";
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";

export default class ReviewableAiChatMessage extends Component {
get chatChannel() {
if (!this.args.reviewable.chat_channel) {
return;
}
return ChatChannel.create(this.args.reviewable.chat_channel);
}
}

View file

@ -0,0 +1,38 @@
import ReviewableCreatedBy from "discourse/components/reviewable-created-by";
import ReviewablePostEdits from "discourse/components/reviewable-post-edits";
import ReviewablePostHeader from "discourse/components/reviewable-post-header";
import ReviewableTopicLink from "discourse/components/reviewable-topic-link";
import htmlSafe from "discourse/helpers/html-safe";
import { i18n } from "discourse-i18n";
import ModelAccuracies from "./model-accuracies";

const ReviewableAiPost = <template>
<div class="flagged-post-header">
<ReviewableTopicLink @reviewable={{@reviewable}} @tagName="" />
<ReviewablePostEdits @reviewable={{@reviewable}} @tagName="" />
</div>

<div class="post-contents-wrapper">
<ReviewableCreatedBy @user={{@reviewable.target_created_by}} @tagName="" />
<div class="post-contents">
<ReviewablePostHeader
@reviewable={{@reviewable}}
@createdBy={{@reviewable.target_created_by}}
@tagName=""
/>
<div class="post-body">
{{#if @reviewable.blank_post}}
<p>{{i18n "review.deleted_post"}}</p>
{{else}}
{{htmlSafe @reviewable.cooked}}
{{/if}}
</div>

{{yield}}

<ModelAccuracies @accuracies={{@reviewable.payload.accuracies}} />
</div>
</div>
</template>;

export default ReviewableAiPost;

View file

@ -1,26 +0,0 @@
<div class="flagged-post-header">
<ReviewableTopicLink @reviewable={{@reviewable}} @tagName="" />
<ReviewablePostEdits @reviewable={{@reviewable}} @tagName="" />
</div>

<div class="post-contents-wrapper">
<ReviewableCreatedBy @user={{@reviewable.target_created_by}} @tagName="" />
<div class="post-contents">
<ReviewablePostHeader
@reviewable={{@reviewable}}
@createdBy={{@reviewable.target_created_by}}
@tagName=""
/>
<div class="post-body">
{{#if @reviewable.blank_post}}
<p>{{i18n "review.deleted_post"}}</p>
{{else}}
{{html-safe @reviewable.cooked}}
{{/if}}
</div>

{{yield}}

<ModelAccuracies @accuracies={{@reviewable.payload.accuracies}} />
</div>
</div>

View file

@ -3,8 +3,8 @@ import { LinkTo } from "@ember/routing";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";


export default class AISentimentDashboard extends Component { export default class AISentimentDashboard extends Component {
static shouldRender(_outletArgs, helper) { static shouldRender(args, context) {
return helper.siteSettings.ai_sentiment_enabled; return context.siteSettings.ai_sentiment_enabled;
} }


<template> <template>

View file

@ -4,11 +4,11 @@ import AiCategorySuggester from "../../components/suggestion-menus/ai-category-s
import { showComposerAiHelper } from "../../lib/show-ai-helper"; import { showComposerAiHelper } from "../../lib/show-ai-helper";


export default class AiCategorySuggestion extends Component { export default class AiCategorySuggestion extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showComposerAiHelper( return showComposerAiHelper(
outletArgs?.composer, args?.composer,
helper.siteSettings, context.siteSettings,
helper.currentUser, context.currentUser,
"suggestions" "suggestions"
); );
} }

View file

@ -3,11 +3,11 @@ import AiTagSuggester from "../../components/suggestion-menus/ai-tag-suggester";
import { showComposerAiHelper } from "../../lib/show-ai-helper"; import { showComposerAiHelper } from "../../lib/show-ai-helper";


export default class AiTagSuggestion extends Component { export default class AiTagSuggestion extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showComposerAiHelper( return showComposerAiHelper(
outletArgs?.composer, args?.composer,
helper.siteSettings, context.siteSettings,
helper.currentUser, context.currentUser,
"suggestions" "suggestions"
); );
} }

View file

@ -3,11 +3,11 @@ import AiTitleSuggester from "../../components/suggestion-menus/ai-title-suggest
import { showComposerAiHelper } from "../../lib/show-ai-helper"; import { showComposerAiHelper } from "../../lib/show-ai-helper";


export default class AiTitleSuggestion extends Component { export default class AiTitleSuggestion extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showComposerAiHelper( return showComposerAiHelper(
outletArgs?.composer, args?.composer,
helper.siteSettings, context.siteSettings,
helper.currentUser, context.currentUser,
"suggestions" "suggestions"
); );
} }

View file

@ -1,6 +1,7 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { computed } from "@ember/object"; import { computed } from "@ember/object";
import { service } from "@ember/service"; import { service } from "@ember/service";
import bodyClass from "discourse/helpers/body-class";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";


export default class extends Component { export default class extends Component {
@ -42,4 +43,15 @@ export default class extends Component {
} }
return false; return false;
} }

<template>
{{#if this.isAiBotChat}}
{{bodyClass this.aiBotClasses}}
{{#if this.renderChatWarning}}
<div class="ai-bot-chat-warning">{{i18n
"discourse_ai.ai_bot.pm_warning"
}}</div>
{{/if}}
{{/if}}
</template>
} }

View file

@ -1,8 +0,0 @@
{{#if this.isAiBotChat}}
{{body-class this.aiBotClasses}}
{{#if this.renderChatWarning}}
<div class="ai-bot-chat-warning">{{i18n
"discourse_ai.ai_bot.pm_warning"
}}</div>
{{/if}}
{{/if}}

View file

@ -19,10 +19,10 @@ function isBotMessage(composer, currentUser) {
} }


export default class BotSelector extends Component { export default class BotSelector extends Component {
static shouldRender(args, container) { static shouldRender(args, context) {
return ( return (
container?.currentUser?.ai_enabled_personas && context?.currentUser?.ai_enabled_personas &&
isBotMessage(args.model, container.currentUser) isBotMessage(args.model, context.currentUser)
); );
} }



View file

@ -3,11 +3,11 @@ import AiCategorySuggester from "../../components/suggestion-menus/ai-category-s
import { showComposerAiHelper } from "../../lib/show-ai-helper"; import { showComposerAiHelper } from "../../lib/show-ai-helper";


export default class AiCategorySuggestion extends Component { export default class AiCategorySuggestion extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showComposerAiHelper( return showComposerAiHelper(
outletArgs?.composer, args?.composer,
helper.siteSettings, context.siteSettings,
helper.currentUser, context.currentUser,
"suggestions" "suggestions"
); );
} }

View file

@ -3,11 +3,11 @@ import AiTagSuggester from "../../components/suggestion-menus/ai-tag-suggester";
import { showComposerAiHelper } from "../../lib/show-ai-helper"; import { showComposerAiHelper } from "../../lib/show-ai-helper";


export default class AiCategorySuggestion extends Component { export default class AiCategorySuggestion extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showComposerAiHelper( return showComposerAiHelper(
outletArgs?.composer, args?.composer,
helper.siteSettings, context.siteSettings,
helper.currentUser, context.currentUser,
"suggestions" "suggestions"
); );
} }

View file

@ -3,11 +3,11 @@ import AiTitleSuggester from "../../components/suggestion-menus/ai-title-suggest
import { showComposerAiHelper } from "../../lib/show-ai-helper"; import { showComposerAiHelper } from "../../lib/show-ai-helper";


export default class AiTitleSuggestion extends Component { export default class AiTitleSuggestion extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showComposerAiHelper( return showComposerAiHelper(
outletArgs?.composer, args?.composer,
helper.siteSettings, context.siteSettings,
helper.currentUser, context.currentUser,
"suggestions" "suggestions"
); );
} }

View file

@ -8,8 +8,8 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
import { showPostAIHelper } from "../../lib/show-ai-helper"; import { showPostAIHelper } from "../../lib/show-ai-helper";


export default class AiEditSuggestionButton extends Component { export default class AiEditSuggestionButton extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showPostAIHelper(outletArgs, helper); return showPostAIHelper(args, context);
} }


@service currentUser; @service currentUser;

View file

@ -7,7 +7,7 @@ import AiSearchDiscoveries from "../../components/ai-search-discoveries";
import AiSearchDiscoveriesTooltip from "../../components/ai-search-discoveries-tooltip"; import AiSearchDiscoveriesTooltip from "../../components/ai-search-discoveries-tooltip";


export default class AiFullPageDiscobotDiscoveries extends Component { export default class AiFullPageDiscobotDiscoveries extends Component {
static shouldRender(_args, { siteSettings, currentUser }) { static shouldRender(args, { siteSettings, currentUser }) {
return ( return (
siteSettings.ai_bot_discover_persona && siteSettings.ai_bot_discover_persona &&
currentUser?.can_use_ai_bot_discover_persona && currentUser?.can_use_ai_bot_discover_persona &&

View file

@ -2,7 +2,7 @@ import Component from "@glimmer/component";
import AiFullPageSearch from "../../components/ai-full-page-search"; import AiFullPageSearch from "../../components/ai-full-page-search";


export default class AiFullPageSearchConnector extends Component { export default class AiFullPageSearchConnector extends Component {
static shouldRender(_args, { siteSettings }) { static shouldRender(args, { siteSettings }) {
return siteSettings.ai_embeddings_semantic_search_enabled; return siteSettings.ai_embeddings_semantic_search_enabled;
} }



View file

@ -8,8 +8,8 @@ import AiPostHelperMenu from "../../components/ai-post-helper-menu";
import { showPostAIHelper } from "../../lib/show-ai-helper"; import { showPostAIHelper } from "../../lib/show-ai-helper";


export default class AiPostHelperTrigger extends Component { export default class AiPostHelperTrigger extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showPostAIHelper(outletArgs, helper); return showPostAIHelper(args, context);
} }


@service menu; @service menu;

View file

@ -8,7 +8,7 @@ import { isValidSearchTerm, translateResults } from "discourse/lib/search";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";


export default class AiQuickSemanticSearch extends Component { export default class AiQuickSemanticSearch extends Component {
static shouldRender(_args, { siteSettings }) { static shouldRender(args, { siteSettings }) {
return siteSettings.ai_embeddings_semantic_quick_search_enabled; return siteSettings.ai_embeddings_semantic_quick_search_enabled;
} }



View file

@ -4,8 +4,8 @@ import AiSplitTopicSuggester from "../../components/ai-split-topic-suggester";
import { showPostAIHelper } from "../../lib/show-ai-helper"; import { showPostAIHelper } from "../../lib/show-ai-helper";


export default class AiCategorySuggestion extends Component { export default class AiCategorySuggestion extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showPostAIHelper(outletArgs, helper); return showPostAIHelper(args, context);
} }


@service siteSettings; @service siteSettings;

View file

@ -4,8 +4,8 @@ import AiSplitTopicSuggester from "../../components/ai-split-topic-suggester";
import { showPostAIHelper } from "../../lib/show-ai-helper"; import { showPostAIHelper } from "../../lib/show-ai-helper";


export default class AiTagSuggestion extends Component { export default class AiTagSuggestion extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showPostAIHelper(outletArgs, helper); return showPostAIHelper(args, context);
} }


@service siteSettings; @service siteSettings;

View file

@ -3,8 +3,8 @@ import AiSplitTopicSuggester from "../../components/ai-split-topic-suggester";
import { showPostAIHelper } from "../../lib/show-ai-helper"; import { showPostAIHelper } from "../../lib/show-ai-helper";


export default class AiTitleSuggestion extends Component { export default class AiTitleSuggestion extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return showPostAIHelper(outletArgs, helper); return showPostAIHelper(args, context);
} }


<template> <template>

View file

@ -2,8 +2,8 @@ import Component from "@glimmer/component";
import AiTopicGist from "../../components/ai-topic-gist"; import AiTopicGist from "../../components/ai-topic-gist";


export default class AiTopicGistPlacement extends Component { export default class AiTopicGistPlacement extends Component {
static shouldRender(_outletArgs, helper) { static shouldRender(args, context) {
const settings = helper.siteSettings; const settings = context.siteSettings;
return settings.discourse_ai_enabled && settings.ai_summarization_enabled; return settings.discourse_ai_enabled && settings.ai_summarization_enabled;
} }



View file

@ -1,17 +1,17 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { LinkTo } from "@ember/routing"; import { LinkTo } from "@ember/routing";
import dIcon from "discourse/helpers/d-icon"; import icon from "discourse/helpers/d-icon";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";


export default class AutoImageCaptionSetting extends Component { export default class AutoImageCaptionSetting extends Component {
static shouldRender(outletArgs, helper) { static shouldRender(args, context) {
return helper.siteSettings.discourse_ai_enabled; return context.siteSettings.discourse_ai_enabled;
} }


<template> <template>
<li class="user-nav__preferences-ai"> <li class="user-nav__preferences-ai">
<LinkTo @route="preferences.ai"> <LinkTo @route="preferences.ai">
{{dIcon "discourse-sparkles"}} {{icon "discourse-sparkles"}}
<span>{{i18n "discourse_ai.title"}}</span> <span>{{i18n "discourse_ai.title"}}</span>
</LinkTo> </LinkTo>
</li> </li>

View file

@ -1,5 +1,5 @@
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
import AdminReportEmotion from "discourse/plugins/discourse-ai/discourse/components/admin-report-emotion"; import AdminReportEmotion from "../components/admin-report-emotion";


export default { export default {
name: "discourse-ai-admin-reports", name: "discourse-ai-admin-reports",

View file

@ -1,5 +1,5 @@
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
import AiArtifact from "../discourse/components/ai-artifact"; import AiArtifact from "../components/ai-artifact";


function initializeAiArtifacts(api) { function initializeAiArtifacts(api) {
api.decorateCookedElement( api.decorateCookedElement(

View file

@ -2,17 +2,17 @@ import { hbs } from "ember-cli-htmlbars";
import { withSilencedDeprecations } from "discourse/lib/deprecated"; import { withSilencedDeprecations } from "discourse/lib/deprecated";
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
import { registerWidgetShim } from "discourse/widgets/render-glimmer"; import { registerWidgetShim } from "discourse/widgets/render-glimmer";
import AiBotHeaderIcon from "../discourse/components/ai-bot-header-icon"; import AiBotHeaderIcon from "../components/ai-bot-header-icon";
import AiPersonaFlair from "../discourse/components/post/ai-persona-flair"; import AiPersonaFlair from "../components/post/ai-persona-flair";
import AiCancelStreamingButton from "../discourse/components/post-menu/ai-cancel-streaming-button"; import AiCancelStreamingButton from "../components/post-menu/ai-cancel-streaming-button";
import AiDebugButton from "../discourse/components/post-menu/ai-debug-button"; import AiDebugButton from "../components/post-menu/ai-debug-button";
import AiShareButton from "../discourse/components/post-menu/ai-share-button"; import AiShareButton from "../components/post-menu/ai-share-button";
import { import {
getBotType, getBotType,
isGPTBot, isGPTBot,
showShareConversationModal, showShareConversationModal,
} from "../discourse/lib/ai-bot-helper"; } from "../lib/ai-bot-helper";
import { streamPostText } from "../discourse/lib/ai-streamer/progress-handlers"; import { streamPostText } from "../lib/ai-streamer/progress-handlers";


let allowDebug = false; let allowDebug = false;


View file

@ -1,5 +1,5 @@
import { apiInitializer } from "discourse/lib/api"; import { apiInitializer } from "discourse/lib/api";
import ChatModalChannelSummary from "../discourse/components/modal/chat-modal-channel-summary"; import ChatModalChannelSummary from "../components/modal/chat-modal-channel-summary";


export default apiInitializer("1.34.0", (api) => { export default apiInitializer("1.34.0", (api) => {
const siteSettings = api.container.lookup("service:site-settings"); const siteSettings = api.container.lookup("service:site-settings");

View file

@ -1,6 +1,6 @@
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
import AiBotSidebarNewConversation from "../discourse/components/ai-bot-sidebar-new-conversation"; import AiBotSidebarNewConversation from "../components/ai-bot-sidebar-new-conversation";
import { AI_CONVERSATIONS_PANEL } from "../discourse/services/ai-conversations-sidebar-manager"; import { AI_CONVERSATIONS_PANEL } from "../services/ai-conversations-sidebar-manager";


export default { export default {
name: "ai-conversations-sidebar", name: "ai-conversations-sidebar",

View file

@ -1,8 +1,8 @@
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";
import AiComposerHelperMenu from "../discourse/components/ai-composer-helper-menu"; import AiComposerHelperMenu from "../components/ai-composer-helper-menu";
import ModalDiffModal from "../discourse/components/modal/diff-modal"; import ModalDiffModal from "../components/modal/diff-modal";
import { showComposerAiHelper } from "../discourse/lib/show-ai-helper"; import { showComposerAiHelper } from "../lib/show-ai-helper";


function initializeAiHelperTrigger(api) { function initializeAiHelperTrigger(api) {
api.onToolbarCreate((toolbar) => { api.onToolbarCreate((toolbar) => {
@ -21,6 +21,7 @@ function initializeAiHelperTrigger(api) {
return composerContent; return composerContent;
} }
}; };

toolbar.addButton({ toolbar.addButton({
id: "ai-helper-trigger", id: "ai-helper-trigger",
group: "extras", group: "extras",

View file

@ -17,10 +17,10 @@ export function showComposerAiHelper(
return enableHelper && enableAssistant && enableFeature; return enableHelper && enableAssistant && enableFeature;
} }


export function showPostAIHelper(outletArgs, helper) { export function showPostAIHelper(outletArgs, context) {
return ( return (
_helperEnabled(helper.siteSettings) && _helperEnabled(context.siteSettings) &&
helper.currentUser?.can_use_assistant_in_post context.currentUser?.can_use_assistant_in_post
); );
} }



View file

@ -8,7 +8,7 @@ import discourseDebounce from "discourse/lib/debounce";
import { autoUpdatingRelativeAge } from "discourse/lib/formatter"; import { autoUpdatingRelativeAge } from "discourse/lib/formatter";
import { ADMIN_PANEL, MAIN_PANEL } from "discourse/lib/sidebar/panels"; import { ADMIN_PANEL, MAIN_PANEL } from "discourse/lib/sidebar/panels";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";
import AiBotSidebarEmptyState from "../../discourse/components/ai-bot-sidebar-empty-state"; import AiBotSidebarEmptyState from "../components/ai-bot-sidebar-empty-state";


export const AI_CONVERSATIONS_PANEL = "ai-conversations"; export const AI_CONVERSATIONS_PANEL = "ai-conversations";
const SCROLL_BUFFER = 100; const SCROLL_BUFFER = 100;

View file

@ -0,0 +1,87 @@
import { LinkTo } from "@ember/routing";
import RouteTemplate from "ember-route-template";
import icon from "discourse/helpers/d-icon";
import { i18n } from "discourse-i18n";
import AdminReport from "admin/components/admin-report";
import DashboardPeriodSelector from "admin/components/dashboard-period-selector";
import DTooltip from "float-kit/components/d-tooltip";

export default RouteTemplate(
<template>
<div class="sentiment section">
<div class="period-section">
<div class="section-title">
<h2 id="sentiment-heading">
{{i18n "discourse_ai.sentiments.dashboard.title"}}
</h2>

<DashboardPeriodSelector
@period={{@controller.period}}
@setPeriod={{@controller.setPeriod}}
@startDate={{@controller.startDate}}
@endDate={{@controller.endDate}}
@setCustomDateRange={{@controller.setCustomDateRange}}
/>
</div>
</div>

<div class="section-body">
<div class="charts">
<AdminReport
@dataSourceName="overall_sentiment"
@filters={{@controller.filters}}
@showHeader={{true}}
/>
<div class="admin-report activity-metrics">
<div class="header">
<ul class="breadcrumb">
<li class="item report">
<LinkTo @route="adminReports" class="report-url">
{{i18n "admin.dashboard.emotion.title"}}
</LinkTo>
<DTooltip @interactive="true">
<:trigger>
{{icon "circle-question"}}
</:trigger>
<:content>
<span>{{i18n
"admin.dashboard.emotion.description"
}}</span>
</:content>
</DTooltip>
</li>
</ul>
</div>
<div class="report-body">
<div class="counters-list">
<div class="counters-header">
<div class="counters-cell"></div>
<div class="counters-cell">{{i18n
"admin.dashboard.reports.today"
}}</div>
<div class="counters-cell">{{i18n
"admin.dashboard.reports.yesterday"
}}</div>
<div class="counters-cell">{{i18n
"admin.dashboard.reports.last_7_days"
}}</div>
<div class="counters-cell">{{i18n
"admin.dashboard.reports.last_30_days"
}}</div>
</div>
{{#each @controller.emotions as |metric|}}
<AdminReport
@showHeader={{false}}
@filters={{@controller.emotionFilters}}
@forcedModes="emotion"
@dataSourceName="emotion_{{metric}}"
/>
{{/each}}
</div>
</div>
</div>
</div>
</div>
</div>
</template>
);

View file

@ -1,73 +0,0 @@
<div class="sentiment section">
<div class="period-section">
<div class="section-title">
<h2 id="sentiment-heading">
{{i18n "discourse_ai.sentiments.dashboard.title"}}
</h2>

<DashboardPeriodSelector
@period={{this.period}}
@setPeriod={{this.setPeriod}}
@startDate={{this.startDate}}
@endDate={{this.endDate}}
@setCustomDateRange={{this.setCustomDateRange}}
/>
</div>
</div>

<div class="section-body">
<div class="charts">
<AdminReport
@dataSourceName="overall_sentiment"
@filters={{this.filters}}
@showHeader={{true}}
/>
<div class="admin-report activity-metrics">
<div class="header">
<ul class="breadcrumb">
<li class="item report">
<LinkTo @route="adminReports" class="report-url">
{{i18n "admin.dashboard.emotion.title"}}
</LinkTo>
<DTooltip @interactive="true">
<:trigger>
{{d-icon "circle-question"}}
</:trigger>
<:content>
<span>{{i18n "admin.dashboard.emotion.description"}}</span>
</:content>
</DTooltip>
</li>
</ul>
</div>
<div class="report-body">
<div class="counters-list">
<div class="counters-header">
<div class="counters-cell"></div>
<div class="counters-cell">{{i18n
"admin.dashboard.reports.today"
}}</div>
<div class="counters-cell">{{i18n
"admin.dashboard.reports.yesterday"
}}</div>
<div class="counters-cell">{{i18n
"admin.dashboard.reports.last_7_days"
}}</div>
<div class="counters-cell">{{i18n
"admin.dashboard.reports.last_30_days"
}}</div>
</div>
{{#each this.emotions as |metric|}}
<AdminReport
@showHeader={{false}}
@filters={{this.emotionFilters}}
@forcedModes="emotion"
@dataSourceName="emotion_{{metric}}"
/>
{{/each}}
</div>
</div>
</div>
</div>
</div>
</div>

View file

@ -210,7 +210,7 @@ body.has-ai-conversations-sidebar {
line-height: var(--line-height-medium); line-height: var(--line-height-medium);


// optical centering for layout balance // optical centering for layout balance
@media screen and (min-height: 600px) { @media screen and (height >= 600px) {
margin-top: -6em; margin-top: -6em;
} }
} }

View file

@ -30,7 +30,7 @@
content: ""; content: "";
position: absolute; position: absolute;
display: block; display: block;
background: linear-gradient(rgba(255, 255, 255, 0), var(--secondary)); background: linear-gradient(rgb(255, 255, 255, 0), var(--secondary));
height: 50%; height: 50%;
width: 100%; width: 100%;
bottom: 0; bottom: 0;
@ -118,7 +118,7 @@
padding-top: 0.5em; padding-top: 0.5em;
} }


@include breakpoint("medium", min-width) { @include viewport.from(lg) {
.search-menu .menu-panel:has(.ai-search-discoveries__discoveries-title) { .search-menu .menu-panel:has(.ai-search-discoveries__discoveries-title) {
width: 80vw; width: 80vw;
max-width: 900px; max-width: 900px;

View file

@ -651,7 +651,7 @@


.desktop-view & { .desktop-view & {
// a little extra space for extra narrow desktop view // a little extra space for extra narrow desktop view
@media screen and (max-width: 675px) { @media screen and (width <= 675px) {
span { span {
display: none; display: none;
} }

View file

@ -35,7 +35,7 @@
padding: 0.5em; padding: 0.5em;
border-radius: var(--d-border-radius); border-radius: var(--d-border-radius);
border: 1px solid var(--primary-low); border: 1px solid var(--primary-low);
box-shadow: 0 0 4px rgba(0, 0, 0, 0.125); box-shadow: 0 0 4px rgb(0, 0, 0, 0.125);
overflow: auto; overflow: auto;
overscroll-behavior: contain; overscroll-behavior: contain;
} }

View file

@ -1,3 +1,5 @@
@use "lib/viewport";

.ai-llms-list-editor { .ai-llms-list-editor {
&__header { &__header {
display: flex; display: flex;
@ -52,7 +54,7 @@
background: inherit; background: inherit;
} }


@include breakpoint("tablet", min-width) { @include viewport.from(md) {
th, th,
td { td {
&:first-child { &:first-child {
@ -84,7 +86,7 @@
gap: 0; gap: 0;
margin-bottom: 2em; margin-bottom: 2em;


@include breakpoint("mobile-extra-large", min-width) { @include viewport.from(sm) {
margin-bottom: 3em; margin-bottom: 3em;
} }
} }
@ -95,7 +97,7 @@
line-height: var(--line-height-large); line-height: var(--line-height-large);
align-self: start; align-self: start;


@include breakpoint("mobile-extra-large", min-width) { @include viewport.from(sm) {
max-width: 17em; max-width: 17em;
} }
} }
@ -135,7 +137,7 @@
font-size: var(--font-down-1); font-size: var(--font-down-1);
} }


@include breakpoint("tablet") { @include viewport.until(md) {
.ai-llm-list__description { .ai-llm-list__description {
max-width: 80%; max-width: 80%;
} }

View file

@ -1,7 +1,7 @@
.ai-usage { .ai-usage {
--chart-response-color: rgba(75, 192, 192, 0.8); --chart-response-color: rgb(75, 192, 192, 0.8);
--chart-request-color: rgba(153, 102, 255, 0.8); --chart-request-color: rgb(153, 102, 255, 0.8);
--chart-cached-color: rgba(153, 102, 255, 0.4); --chart-cached-color: rgb(153, 102, 255, 0.4);
padding: 1em; padding: 1em;


&__filters-dates { &__filters-dates {
@ -89,7 +89,7 @@
gap: 2em; gap: 2em;
margin-top: 2em; margin-top: 2em;


@media (max-width: 768px) { @media (width <= 768px) {
grid-template-columns: none; grid-template-columns: none;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View file

@ -1,3 +1,5 @@
@use "lib/viewport";

.dashboard.dashboard-sentiment { .dashboard.dashboard-sentiment {
.charts { .charts {
display: grid; display: grid;
@ -152,7 +154,7 @@
border-bottom: 1px solid var(--primary-low); border-bottom: 1px solid var(--primary-low);
margin-bottom: 1rem; margin-bottom: 1rem;


@include breakpoint("mobile-extra-large") { @include viewport.until(sm) {
.d-button-label { .d-button-label {
display: none; display: none;
} }
@ -194,17 +196,17 @@


&[data-sentiment-score="positive"] { &[data-sentiment-score="positive"] {
color: rgb(var(--d-sentiment-report-positive-rgb)); color: rgb(var(--d-sentiment-report-positive-rgb));
background: rgba(var(--d-sentiment-report-positive-rgb), 0.1); background: rgb(var(--d-sentiment-report-positive-rgb), 0.1);
} }


&[data-sentiment-score="neutral"] { &[data-sentiment-score="neutral"] {
color: rgb(var(--d-sentiment-report-neutral-rgb)); color: rgb(var(--d-sentiment-report-neutral-rgb));
background: rgba(var(--d-sentiment-report-neutral-rgb), 0.1); background: rgb(var(--d-sentiment-report-neutral-rgb), 0.1);
} }


&[data-sentiment-score="negative"] { &[data-sentiment-score="negative"] {
color: rgb(var(--d-sentiment-report-negative-rgb)); color: rgb(var(--d-sentiment-report-negative-rgb));
background: rgba(var(--d-sentiment-report-negative-rgb), 0.1); background: rgb(var(--d-sentiment-report-negative-rgb), 0.1);
} }
} }



View file

@ -1,3 +1,5 @@
@use "lib/viewport";

.topic-map { .topic-map {
// Hide the Top Replies label if summarization is enabled // Hide the Top Replies label if summarization is enabled
&:has(.topic-map__additional-contents .ai-summarization-button) { &:has(.topic-map__additional-contents .ai-summarization-button) {
@ -71,7 +73,7 @@
grid-template-areas: "summarized regenerate" " outdated regenerate"; grid-template-areas: "summarized regenerate" " outdated regenerate";
grid-template-columns: 1fr auto; grid-template-columns: 1fr auto;


@include breakpoint(mobile-large) { @include viewport.until(sm) {
gap: 0.25em 0.5em; gap: 0.25em 0.5em;
grid-template-areas: "summarized summarized" "regenerate outdated"; grid-template-areas: "summarized summarized" "regenerate outdated";
} }

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true


RSpec.describe "Admin AI features configuration", type: :system, js: true do RSpec.describe "Admin AI features configuration", type: :system do
fab!(:admin) fab!(:admin)
fab!(:llm_model) fab!(:llm_model)
fab!(:summarization_persona) { Fabricate(:ai_persona) } fab!(:summarization_persona) { Fabricate(:ai_persona) }

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true


RSpec.describe "Admin AI persona configuration", type: :system, js: true do RSpec.describe "Admin AI persona configuration", type: :system do
fab!(:admin) fab!(:admin)
let(:page_header) { PageObjects::Components::DPageHeader.new } let(:page_header) { PageObjects::Components::DPageHeader.new }
let(:form) { PageObjects::Components::FormKit.new("form") } let(:form) { PageObjects::Components::FormKit.new("form") }

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true


RSpec.describe "AI Artifact Key-Value API", type: :system, js: true do RSpec.describe "AI Artifact Key-Value API", type: :system do
fab!(:user) fab!(:user)
fab!(:private_message_topic) { Fabricate(:private_message_topic, user: user) } fab!(:private_message_topic) { Fabricate(:private_message_topic, user: user) }
fab!(:private_message_post) { Fabricate(:post, topic: private_message_topic, user: user) } fab!(:private_message_post) { Fabricate(:post, topic: private_message_topic, user: user) }

View file

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
RSpec.describe "AI chat channel summarization", type: :system, js: true do RSpec.describe "AI chat channel summarization", type: :system do
fab!(:user) fab!(:user)
fab!(:group) { Fabricate(:group, visibility_level: Group.visibility_levels[:staff]) } fab!(:group) { Fabricate(:group, visibility_level: Group.visibility_levels[:staff]) }



View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true


RSpec.describe "AI personas", type: :system, js: true do RSpec.describe "AI personas", type: :system do
fab!(:admin) fab!(:admin)
fab!(:gpt_4) { Fabricate(:llm_model, name: "gpt-4") } fab!(:gpt_4) { Fabricate(:llm_model, name: "gpt-4") }



View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true


RSpec.describe "AI Composer helper", type: :system, js: true do RSpec.describe "AI Composer helper", type: :system do
fab!(:user) { Fabricate(:admin, refresh_auto_groups: true) } fab!(:user) { Fabricate(:admin, refresh_auto_groups: true) }
fab!(:non_member_group) { Fabricate(:group) } fab!(:non_member_group) { Fabricate(:group) }
fab!(:embedding_definition) fab!(:embedding_definition)

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true


RSpec.describe "AI image caption", type: :system, js: true do RSpec.describe "AI image caption", type: :system do
fab!(:user) { Fabricate(:admin, refresh_auto_groups: true) } fab!(:user) { Fabricate(:admin, refresh_auto_groups: true) }
fab!(:non_member_group) { Fabricate(:group) } fab!(:non_member_group) { Fabricate(:group) }
let(:user_preferences_ai_page) { PageObjects::Pages::UserPreferencesAi.new } let(:user_preferences_ai_page) { PageObjects::Pages::UserPreferencesAi.new }

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true


RSpec.describe "AI Post helper", type: :system, js: true do RSpec.describe "AI Post helper", type: :system do
fab!(:user) { Fabricate(:admin) } fab!(:user) { Fabricate(:admin) }
fab!(:non_member_group) { Fabricate(:group) } fab!(:non_member_group) { Fabricate(:group) }
fab!(:topic) fab!(:topic)

View file

@ -2,7 +2,7 @@


include SystemHelpers include SystemHelpers


RSpec.describe "AI Composer Proofreading Features", type: :system, js: true do RSpec.describe "AI Composer Proofreading Features", type: :system do
fab!(:admin) { Fabricate(:admin, refresh_auto_groups: true) } fab!(:admin) { Fabricate(:admin, refresh_auto_groups: true) }


before do before do

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true


RSpec.describe "AI Post helper", type: :system, js: true do RSpec.describe "AI Post helper", type: :system do
fab!(:user) { Fabricate(:admin) } fab!(:user) { Fabricate(:admin) }
fab!(:non_member_group) { Fabricate(:group) } fab!(:non_member_group) { Fabricate(:group) }
fab!(:topic) fab!(:topic)

Some files were not shown because too many files have changed in this diff Show more