@@ -3,26 +3,36 @@ import { tracked } from "@glimmer/tracking";
33import { fn , hash } from " @ember/helper" ;
44import { on } from " @ember/modifier" ;
55import { action } from " @ember/object" ;
6+ import didInsert from " @ember/render-modifiers/modifiers/did-insert" ;
7+ import { service } from " @ember/service" ;
68import { modifier } from " ember-modifier" ;
79import { and } from " truth-helpers" ;
810import DButton from " discourse/components/d-button" ;
911import HorizontalOverflowNav from " discourse/components/horizontal-overflow-nav" ;
1012import PostList from " discourse/components/post-list" ;
1113import dIcon from " discourse/helpers/d-icon" ;
14+ import replaceEmoji from " discourse/helpers/replace-emoji" ;
1215import { ajax } from " discourse/lib/ajax" ;
1316import { popupAjaxError } from " discourse/lib/ajax-error" ;
17+ import { getAbsoluteURL } from " discourse/lib/get-url" ;
18+ import discourseLater from " discourse/lib/later" ;
19+ import { clipboardCopy } from " discourse/lib/utilities" ;
1420import Post from " discourse/models/post" ;
1521import closeOnClickOutside from " discourse/modifiers/close-on-click-outside" ;
1622import { i18n } from " discourse-i18n" ;
23+ import DTooltip from " float-kit/components/d-tooltip" ;
1724import DoughnutChart from " discourse/plugins/discourse-ai/discourse/components/doughnut-chart" ;
1825
1926export default class AdminReportSentimentAnalysis extends Component {
27+ @service router;
28+
2029 @tracked selectedChart = null ;
21- @tracked posts = null ;
30+ @tracked posts = [] ;
2231 @tracked hasMorePosts = false ;
2332 @tracked nextOffset = 0 ;
2433 @tracked showingSelectedChart = false ;
2534 @tracked activeFilter = " all" ;
35+ @tracked shareIcon = " link" ;
2636
2737 setActiveFilter = modifier ((element ) => {
2838 this .clearActiveFilters (element);
@@ -71,32 +81,6 @@ export default class AdminReportSentimentAnalysis extends Component {
7181 }
7282 }
7383
74- doughnutTitle (data ) {
75- const MAX_TITLE_LENGTH = 18 ;
76- const title = data? .title || " " ;
77- const score = data? .total_score ? ` (${ data .total_score } )` : " " ;
78-
79- if (title .length + score .length > MAX_TITLE_LENGTH ) {
80- return (
81- title .substring (0 , MAX_TITLE_LENGTH - score .length ) + " ..." + score
82- );
83- }
84-
85- return title + score;
86- }
87-
88- async postRequest () {
89- return await ajax (" /discourse-ai/sentiment/posts" , {
90- data: {
91- group_by: this .currentGroupFilter ,
92- group_value: this .selectedChart ? .title ,
93- start_date: this .args .model .start_date ,
94- end_date: this .args .model .end_date ,
95- offset: this .nextOffset ,
96- },
97- });
98- }
99-
10084 get colors () {
10185 return [" #2ecc71" , " #95a5a6" , " #e74c3c" ];
10286 }
@@ -133,10 +117,11 @@ export default class AdminReportSentimentAnalysis extends Component {
133117 }
134118
135119 return this .posts .filter ((post ) => {
120+ post .topic_title = replaceEmoji (post .topic_title );
121+
136122 if (this .activeFilter === " all" ) {
137123 return true ;
138124 }
139-
140125 return post .sentiment === this .activeFilter ;
141126 });
142127 }
@@ -186,13 +171,57 @@ export default class AdminReportSentimentAnalysis extends Component {
186171 ];
187172 }
188173
174+ async postRequest () {
175+ return await ajax (" /discourse-ai/sentiment/posts" , {
176+ data: {
177+ group_by: this .currentGroupFilter ,
178+ group_value: this .selectedChart ? .title ,
179+ start_date: this .args .model .start_date ,
180+ end_date: this .args .model .end_date ,
181+ offset: this .nextOffset ,
182+ },
183+ });
184+ }
185+
186+ @action
187+ async openToChart () {
188+ const queryParams = this .router .currentRoute .queryParams ;
189+ if (queryParams .selectedChart ) {
190+ this .selectedChart = this .transformedData .find (
191+ (data ) => data .title === queryParams .selectedChart
192+ );
193+
194+ if (! this .selectedChart ) {
195+ return ;
196+ }
197+ this .showingSelectedChart = true ;
198+
199+ try {
200+ const response = await this .postRequest ();
201+ this .posts = response .posts .map ((post ) => Post .create (post));
202+ this .hasMorePosts = response .has_more ;
203+ this .nextOffset = response .next_offset ;
204+ } catch (e) {
205+ popupAjaxError (e);
206+ }
207+ }
208+ }
209+
189210 @action
190211 async showDetails (data ) {
191212 if (this .selectedChart === data) {
192213 // Don't do anything if the same chart is clicked again
193214 return ;
194215 }
195216
217+ const currentQueryParams = this .router .currentRoute .queryParams ;
218+ this .router .transitionTo (this .router .currentRoute .name , {
219+ queryParams: {
220+ ... currentQueryParams,
221+ selectedChart: data .title ,
222+ },
223+ });
224+
196225 this .selectedChart = data;
197226 this .showingSelectedChart = true ;
198227
@@ -217,7 +246,10 @@ export default class AdminReportSentimentAnalysis extends Component {
217246
218247 this .hasMorePosts = response .has_more ;
219248 this .nextOffset = response .next_offset ;
220- return response .posts .map ((post ) => Post .create (post));
249+
250+ const mappedPosts = response .posts .map ((post ) => Post .create (post));
251+ this .posts .pushObjects (mappedPosts);
252+ return mappedPosts;
221253 } catch (e) {
222254 popupAjaxError (e);
223255 }
@@ -228,9 +260,35 @@ export default class AdminReportSentimentAnalysis extends Component {
228260 this .showingSelectedChart = false ;
229261 this .selectedChart = null ;
230262 this .activeFilter = " all" ;
263+ this .posts = [];
264+
265+ const currentQueryParams = this .router .currentRoute .queryParams ;
266+ this .router .transitionTo (this .router .currentRoute .name , {
267+ queryParams: {
268+ ... currentQueryParams,
269+ selectedChart: null ,
270+ },
271+ });
272+ }
273+
274+ @action
275+ shareChart () {
276+ const url = this .router .currentURL ;
277+ if (! url) {
278+ return ;
279+ }
280+
281+ clipboardCopy (getAbsoluteURL (url));
282+ this .shareIcon = " check" ;
283+
284+ discourseLater (() => {
285+ this .shareIcon = " link" ;
286+ }, 2000 );
231287 }
232288
233289 <template >
290+ <span {{didInsert this . openToChart}} ></span >
291+
234292 {{#unless this . showingSelectedChart }}
235293 <div class =" admin-report-sentiment-analysis" >
236294 {{#each this . transformedData as | data | }}
@@ -252,6 +310,7 @@ export default class AdminReportSentimentAnalysis extends Component {
252310 @ data ={{data.scores }}
253311 @ totalScore ={{data.total_score }}
254312 @ doughnutTitle ={{data.title }}
313+ @ displayLegend ={{ true }}
255314 />
256315 </div >
257316 {{/each }}
@@ -260,20 +319,33 @@ export default class AdminReportSentimentAnalysis extends Component {
260319
261320 {{#if ( and this . selectedChart this . showingSelectedChart) }}
262321 <div class =" admin-report-sentiment-analysis__selected-chart" >
263- <DButton
264- @ label =" back_button"
265- @ icon =" chevron-left"
266- class =" btn-flat"
267- @ action ={{this .backToAllCharts }}
268- />
322+ <div class =" admin-report-sentiment-analysis__selected-chart-actions" >
323+ <DButton
324+ @ label =" back_button"
325+ @ icon =" chevron-left"
326+ class =" btn-flat"
327+ @ action ={{this .backToAllCharts }}
328+ />
329+
330+ <DTooltip
331+ class =" share btn-flat"
332+ @ icon ={{this .shareIcon }}
333+ {{on " click" this . shareChart}}
334+ @ content ={{i18n
335+ " discourse_ai.sentiments.sentiment_analysis.share_chart"
336+ }}
337+ />
338+ </div >
269339
270340 <DoughnutChart
271341 @ labels ={{@ model.labels }}
272342 @ colors ={{this .colors }}
273343 @ data ={{this .selectedChart.scores }}
274344 @ totalScore ={{this .selectedChart.total_score }}
275345 @ doughnutTitle ={{this .selectedChart.title }}
346+ @ displayLegend ={{ true }}
276347 />
348+
277349 </div >
278350 <div class =" admin-report-sentiment-analysis-details" >
279351 <HorizontalOverflowNav
0 commit comments