2022-12-20 13:09:37 -05:00
import Component from "@glimmer/component" ;
2020-09-04 07:23:11 -04:00
import I18n from "I18n" ;
2018-10-10 07:56:23 -04:00
import { ajax } from "discourse/lib/ajax" ;
2020-07-06 15:25:19 -04:00
import getURL from "discourse-common/lib/get-url" ;
2018-10-10 07:56:23 -04:00
import Badge from "discourse/models/badge" ;
2022-05-13 13:33:38 -04:00
import { capitalize } from "@ember/string" ;
2022-06-17 08:18:36 -04:00
import { schedule } from "@ember/runloop" ;
2022-12-20 13:09:37 -05:00
import { action } from "@ember/object" ;
import { tracked } from "@glimmer/tracking" ;
import { inject as service } from "@ember/service" ;
import { findRawTemplate } from "discourse-common/lib/raw-templates" ;
2015-06-30 18:12:12 -04:00
2022-12-20 13:09:37 -05:00
export default class QueryResult extends Component {
@ service site ;
@ tracked chartDisplayed = false ;
2015-06-30 18:12:12 -04:00
2022-12-20 13:09:37 -05:00
get colRender ( ) {
return this . args . content . colrender || { } ;
}
2015-08-25 23:48:19 -04:00
2022-12-20 13:09:37 -05:00
get rows ( ) {
return this . args . content . rows ;
}
2018-09-16 12:28:16 -04:00
2022-12-20 13:09:37 -05:00
get columns ( ) {
return this . args . content . columns ;
}
2015-06-30 18:12:12 -04:00
2022-12-20 13:09:37 -05:00
get params ( ) {
return this . args . content . params ;
}
2015-06-30 18:12:12 -04:00
2022-12-20 13:09:37 -05:00
get explainText ( ) {
return this . args . content . explain ;
}
get chartDatasetName ( ) {
return this . columnNames [ 1 ] ;
}
2015-06-30 18:12:12 -04:00
2022-12-20 13:09:37 -05:00
get columnNames ( ) {
if ( ! this . columns ) {
2015-07-01 00:21:14 -04:00
return [ ] ;
2015-06-30 18:12:12 -04:00
}
2022-12-20 13:09:37 -05:00
return this . columns . map ( ( colName ) => {
2015-08-25 23:48:19 -04:00
if ( colName . endsWith ( "_id" ) ) {
return colName . slice ( 0 , - 3 ) ;
2015-06-30 18:12:12 -04:00
}
2018-10-10 07:56:23 -04:00
const dIdx = colName . indexOf ( "$" ) ;
2015-08-25 23:48:19 -04:00
if ( dIdx >= 0 ) {
return colName . substring ( dIdx + 1 ) ;
}
return colName ;
} ) ;
2022-12-20 13:09:37 -05:00
}
2015-09-14 19:00:39 -04:00
2022-12-20 13:09:37 -05:00
get columnTemplates ( ) {
if ( ! this . columns ) {
2015-08-25 23:48:19 -04:00
return [ ] ;
}
2022-12-20 13:09:37 -05:00
return this . columns . map ( ( _ , idx ) => {
2015-08-25 23:48:19 -04:00
let viewName = "text" ;
2022-12-20 13:09:37 -05:00
if ( this . colRender [ idx ] ) {
viewName = this . colRender [ idx ] ;
2015-08-25 23:48:19 -04:00
}
2016-12-27 11:47:50 -05:00
2021-02-24 13:49:26 -05:00
const template = findRawTemplate ( ` javascripts/explorer/ ${ viewName } ` ) ;
2018-10-10 07:56:23 -04:00
return { name : viewName , template } ;
2015-06-30 18:12:12 -04:00
} ) ;
2022-12-20 13:09:37 -05:00
}
get chartValues ( ) {
// return an array with the second value of this.row
return this . rows . mapBy ( 1 ) ;
}
get colCount ( ) {
return this . columns . length ;
}
get resultCount ( ) {
const count = this . args . content . result _count ;
if ( count === this . args . content . default _limit ) {
return I18n . t ( "explorer.max_result_count" , { count } ) ;
} else {
return I18n . t ( "explorer.result_count" , { count } ) ;
}
}
get duration ( ) {
return I18n . t ( "explorer.run_time" , {
value : I18n . toNumber ( this . args . content . duration , { precision : 1 } ) ,
} ) ;
}
get parameterAry ( ) {
let arr = [ ] ;
for ( let key in this . params ) {
if ( this . params . hasOwnProperty ( key ) ) {
arr . push ( { key , value : this . params [ key ] } ) ;
}
}
return arr ;
}
get transformedUserTable ( ) {
return transformedRelTable ( this . args . content . relations . user ) ;
}
get transformedBadgeTable ( ) {
return transformedRelTable ( this . args . content . relations . badge , Badge ) ;
}
get transformedPostTable ( ) {
return transformedRelTable ( this . args . content . relations . post ) ;
}
get transformedTopicTable ( ) {
return transformedRelTable ( this . args . content . relations . topic ) ;
}
get transformedGroupTable ( ) {
return transformedRelTable ( this . site . groups ) ;
}
get canShowChart ( ) {
const hasTwoColumns = this . colCount === 2 ;
2021-02-18 06:06:22 -05:00
const secondColumnContainsNumber =
2022-12-20 17:55:11 -05:00
this . resultCount [ 0 ] > 0 && typeof this . rows [ 0 ] [ 1 ] === "number" ;
2022-12-20 13:09:37 -05:00
const secondColumnContainsId = this . colRender [ 1 ] ;
2021-02-18 06:06:22 -05:00
return (
hasTwoColumns && secondColumnContainsNumber && ! secondColumnContainsId
) ;
2022-12-20 13:09:37 -05:00
}
2021-02-18 06:06:22 -05:00
2022-12-20 13:09:37 -05:00
get chartLabels ( ) {
2021-02-18 06:06:22 -05:00
const labelSelectors = {
user : ( user ) => user . username ,
badge : ( badge ) => badge . name ,
topic : ( topic ) => topic . title ,
group : ( group ) => group . name ,
category : ( category ) => category . name ,
} ;
2022-12-20 13:09:37 -05:00
const relationName = this . colRender [ 0 ] ;
2021-02-18 06:06:22 -05:00
if ( relationName ) {
2022-05-13 13:33:38 -04:00
const lookupFunc = this [ ` lookup ${ capitalize ( relationName ) } ` ] ;
2021-02-18 06:06:22 -05:00
const labelSelector = labelSelectors [ relationName ] ;
if ( lookupFunc && labelSelector ) {
2022-12-20 13:09:37 -05:00
return this . rows . map ( ( r ) => {
2021-02-18 06:06:22 -05:00
const relation = lookupFunc . call ( this , r [ 0 ] ) ;
const label = labelSelector ( relation ) ;
return this . _cutChartLabel ( label ) ;
} ) ;
}
}
2022-12-20 13:09:37 -05:00
return this . rows . map ( ( r ) => this . _cutChartLabel ( r [ 0 ] ) ) ;
}
2021-02-18 06:06:22 -05:00
2015-08-26 00:36:39 -04:00
lookupUser ( id ) {
2019-07-16 06:46:32 -04:00
return this . transformedUserTable [ id ] ;
2022-12-20 13:09:37 -05:00
}
2015-08-26 00:36:39 -04:00
lookupBadge ( id ) {
2019-07-16 06:46:32 -04:00
return this . transformedBadgeTable [ id ] ;
2022-12-20 13:09:37 -05:00
}
2015-08-26 00:36:39 -04:00
lookupPost ( id ) {
2019-07-16 06:46:32 -04:00
return this . transformedPostTable [ id ] ;
2022-12-20 13:09:37 -05:00
}
2015-08-26 00:36:39 -04:00
lookupTopic ( id ) {
2019-07-16 06:46:32 -04:00
return this . transformedTopicTable [ id ] ;
2022-12-20 13:09:37 -05:00
}
2015-09-21 17:43:23 -04:00
lookupGroup ( id ) {
2019-07-16 06:46:32 -04:00
return this . transformedGroupTable [ id ] ;
2022-12-20 13:09:37 -05:00
}
2015-08-26 00:36:39 -04:00
lookupCategory ( id ) {
2022-12-15 09:26:40 -05:00
return this . site . categoriesById [ id ] ;
2022-12-20 13:09:37 -05:00
}
2015-08-25 23:48:19 -04:00
2022-12-20 13:09:37 -05:00
_cutChartLabel ( label ) {
const labelString = label . toString ( ) ;
if ( labelString . length > 25 ) {
return ` ${ labelString . substring ( 0 , 25 ) } ... ` ;
} else {
return labelString ;
}
}
@ action
downloadResultJson ( ) {
this . _downloadResult ( "json" ) ;
}
@ action
downloadResultCsv ( ) {
this . _downloadResult ( "csv" ) ;
}
@ action
showChart ( ) {
this . chartDisplayed = true ;
}
@ action
hideChart ( ) {
this . chartDisplayed = false ;
}
_download _url ( ) {
2022-12-30 11:26:14 -05:00
return this . args . group
? ` /g/ ${ this . args . group . name } /reports/ `
2019-09-11 10:09:41 -04:00
: "/admin/plugins/explorer/queries/" ;
2022-12-20 13:09:37 -05:00
}
2019-09-11 10:09:41 -04:00
2022-12-20 13:09:37 -05:00
_downloadResult ( format ) {
2015-08-03 18:07:29 -04:00
// Create a frame to submit the form in (?)
// to avoid leaving an about:blank behind
let windowName = randomIdShort ( ) ;
2018-10-10 07:56:23 -04:00
const newWindowContents =
"<style>body{font-size:36px;display:flex;justify-content:center;align-items:center;}</style><body>Click anywhere to close this window once the download finishes.<script>window.onclick=function(){window.close()};</script>" ;
2015-08-03 18:07:29 -04:00
2018-10-10 07:56:23 -04:00
window . open ( "data:text/html;base64," + btoa ( newWindowContents ) , windowName ) ;
2015-08-03 18:07:29 -04:00
let form = document . createElement ( "form" ) ;
2018-10-10 07:56:23 -04:00
form . setAttribute ( "id" , "query-download-result" ) ;
form . setAttribute ( "method" , "post" ) ;
form . setAttribute (
"action" ,
2020-07-06 15:25:19 -04:00
getURL (
2022-12-20 13:09:37 -05:00
this . _download _url ( ) +
2022-12-29 15:47:18 -05:00
this . args . query . id +
2018-10-10 07:56:23 -04:00
"/run." +
format +
"?download=1"
)
) ;
form . setAttribute ( "target" , windowName ) ;
form . setAttribute ( "style" , "display:none;" ) ;
2015-08-03 18:07:29 -04:00
2015-09-14 18:34:57 -04:00
function addInput ( name , value ) {
2015-08-03 18:07:29 -04:00
let field ;
2018-10-10 07:56:23 -04:00
field = document . createElement ( "input" ) ;
field . setAttribute ( "name" , name ) ;
field . setAttribute ( "value" , value ) ;
2015-08-03 18:07:29 -04:00
form . appendChild ( field ) ;
}
2015-07-09 15:02:47 -04:00
2019-07-16 06:46:32 -04:00
addInput ( "params" , JSON . stringify ( this . params ) ) ;
2022-12-20 13:09:37 -05:00
addInput ( "explain" , this . explainText ) ;
2018-10-10 07:56:23 -04:00
addInput ( "limit" , "1000000" ) ;
2015-07-09 15:02:47 -04:00
2020-09-04 07:23:11 -04:00
ajax ( "/session/csrf.json" ) . then ( ( csrf ) => {
2018-10-10 07:56:23 -04:00
addInput ( "authenticity_token" , csrf . csrf ) ;
2015-07-09 15:02:47 -04:00
2015-08-03 18:07:29 -04:00
document . body . appendChild ( form ) ;
form . submit ( ) ;
2022-06-17 08:18:36 -04:00
schedule ( "afterRender" , ( ) => document . body . removeChild ( form ) ) ;
2015-08-03 18:07:29 -04:00
} ) ;
2022-12-20 13:09:37 -05:00
}
}
2015-08-03 18:07:29 -04:00
2022-12-20 13:09:37 -05:00
function randomIdShort ( ) {
return "xxxxxxxx" . replace ( /[xy]/g , ( ) => {
/*eslint-disable*/
return ( ( Math . random ( ) * 16 ) | 0 ) . toString ( 16 ) ;
/*eslint-enable*/
} ) ;
}
function transformedRelTable ( table , modelClass ) {
const result = { } ;
table . forEach ( ( item ) => {
if ( modelClass ) {
result [ item . id ] = modelClass . create ( item ) ;
2021-02-18 06:06:22 -05:00
} else {
2022-12-20 13:09:37 -05:00
result [ item . id ] = item ;
2021-02-18 06:06:22 -05:00
}
2022-12-20 13:09:37 -05:00
} ) ;
return result ;
}