Version 5.0.13
This commit is contained in:
1 parent
b89858b2ff
commit
5efe744c5f
1407 files changed
+69690
-30177
No files matched your search
@@ -21,7 +21,9 @@ use IPS\Db;
|
||||
use IPS\Helpers\Chart;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Date;
|
||||
use IPS\Helpers\Form\Select;
|
||||
use IPS\Helpers\Form\Text;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Http\Url;
|
||||
use IPS\IPS;
|
||||
use IPS\Member;
|
||||
@@ -30,12 +32,19 @@ use IPS\Request;
|
||||
use IPS\Session;
|
||||
use IPS\Theme;
|
||||
use Throwable;
|
||||
use UnderflowException;
|
||||
use function array_merge;
|
||||
use function defined;
|
||||
use function explode;
|
||||
use function file_get_contents;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_numeric;
|
||||
use function is_string;
|
||||
use function iterator_to_array;
|
||||
use function json_encode;
|
||||
use function mb_substr;
|
||||
use function var_export;
|
||||
use const IPS\TEMP_DIRECTORY;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
@@ -183,6 +192,13 @@ abstract class Dynamic extends Chart
|
||||
* @brief Prefix passed to tables
|
||||
*/
|
||||
public string $tableLangPrefix = '';
|
||||
|
||||
/**
|
||||
* When downloading chart collections from the saved reports page, this indicates the type that the chart should load as by default
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public static null|string $mergedChartType = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -200,12 +216,38 @@ abstract class Dynamic extends Chart
|
||||
*/
|
||||
public function __construct( Url $url, string $title='', array $options=array(), string $defaultType='AreaChart', string $defaultTimescale='monthly', array $defaultTimes=array( 'start' => 0, 'end' => 0 ), string $identifier='', DateTime $minimumDate=null )
|
||||
{
|
||||
|
||||
if ( isset( static::$mergedChartType ) )
|
||||
{
|
||||
$defaultType = static::$mergedChartType;
|
||||
}
|
||||
|
||||
/* If we are deleting a chart, just do that now and redirect */
|
||||
if( isset( Request::i()->deleteChart ) )
|
||||
{
|
||||
Session::i()->csrfCheck();
|
||||
Db::i()->delete( 'core_saved_charts', array( 'chart_id=? and chart_member=?', Request::i()->deleteChart, Member::loggedIn()->member_id ) );
|
||||
Output::i()->redirect( Request::i()->url()->stripQueryString( array( 'deleteChart', 'chartId', 'csrfKey' ) ), 'chart_deleted' );
|
||||
$where = array( 'chart_id=? and (chart_member IS NULL OR chart_member=0 OR chart_member=?)', Request::i()->deleteChart, Member::loggedIn()->member_id );
|
||||
try
|
||||
{
|
||||
$reportID = Db::i()->select( "chart_report_id", "core_saved_charts", $where )->first();
|
||||
}
|
||||
catch ( UnderflowException )
|
||||
{
|
||||
$reportID = null;
|
||||
}
|
||||
Db::i()->delete( 'core_saved_charts', $where );
|
||||
$url = Request::i()->url()->stripQueryString( array( 'deleteChart', 'chartId', 'csrfKey', 'wasConfirmed' ) );
|
||||
if ( isset( $reportID ) )
|
||||
{
|
||||
$url = $url->setQueryString( "report_id", $reportID );
|
||||
}
|
||||
|
||||
if ( Request::i()->do === 'getChart' )
|
||||
{
|
||||
$url = $url->stripQueryString([ 'do' ]);
|
||||
}
|
||||
|
||||
Output::i()->redirect( $url, 'chart_deleted' );
|
||||
}
|
||||
|
||||
if ( !isset( $options['chartArea'] ) )
|
||||
@@ -351,7 +393,7 @@ abstract class Dynamic extends Chart
|
||||
}
|
||||
|
||||
/* If we have requested a saved chart, load its filters */
|
||||
if( isset( Request::i()->chartId ) AND Request::i()->chartId != '_default' AND !isset( Request::i()->filters ) )
|
||||
if( isset( Request::i()->chartId ) AND is_numeric( Request::i()->chartId ) AND !isset( Request::i()->filters ) )
|
||||
{
|
||||
foreach( $this->loadAvailableChartTabs() as $chart )
|
||||
{
|
||||
@@ -414,7 +456,7 @@ abstract class Dynamic extends Chart
|
||||
try
|
||||
{
|
||||
/* Generate a form so we can save our filters as a new saved chart */
|
||||
$this->form = new Form;
|
||||
$this->form = new Form( 'form_' . $this->identifier );
|
||||
$this->form->class = 'ipsForm--vertical ipsForm--chart-custom-filters';
|
||||
|
||||
if ( $this->customFiltersForm )
|
||||
@@ -429,18 +471,18 @@ abstract class Dynamic extends Chart
|
||||
}
|
||||
|
||||
/* If we have a sub selector from a node form, add on the identifier and pass off to the form to show the ajax */
|
||||
if ( Request::i()->_nodeSelectName )
|
||||
if ( isset( Request::i()->_nodeSelectName ) and Request::i()->_nodeSelectName )
|
||||
{
|
||||
Request::i()->_nodeSelectName = $this->identifier . Request::i()->_nodeSelectName;
|
||||
return (string) $this->getCustomFiltersForm();
|
||||
}
|
||||
|
||||
/* We have an existing chart ID */
|
||||
if( isset( Request::i()->chartId ) AND Request::i()->chartId != '_default' )
|
||||
if( isset( Request::i()->chartId ) AND is_numeric( Request::i()->chartId ) )
|
||||
{
|
||||
$title = '';
|
||||
|
||||
foreach( $this->loadAvailableChartTabs() as $chart )
|
||||
foreach( $this->loadSavedCharts() as $chart )
|
||||
{
|
||||
if( $chart['chart_id'] == Request::i()->chartId )
|
||||
{
|
||||
@@ -451,7 +493,7 @@ abstract class Dynamic extends Chart
|
||||
|
||||
$custom = array();
|
||||
$chartFilters = ( isset( Request::i()->chartFilters ) and Request::i()->chartFilters ) ? Request::i()->chartFilters : array();
|
||||
$this->timescale = ( isset( Request::i()->timescale ) and Request::i()->timescale[ $this->identifier ] ) ? Request::i()->timescale[ $this->identifier ] : $chart['chart_timescale'] ?? 'monthly';
|
||||
$this->timescale = ( isset( Request::i()->timescale ) and in_array( Request::i()->timescale[ $this->identifier ], ['hourly', 'daily', 'monthly', 'weekly'] ) ) ? Request::i()->timescale[ $this->identifier ] : $chart['chart_timescale'] ?? 'monthly';
|
||||
|
||||
|
||||
foreach( Request::i() as $key => $value )
|
||||
@@ -483,7 +525,45 @@ abstract class Dynamic extends Chart
|
||||
/* We are not viewing a saved chart */
|
||||
else
|
||||
{
|
||||
$this->form->add( new Text( 'custom_chart_title', NULL, TRUE ) );
|
||||
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'admin_stats.js', 'core' ) );
|
||||
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'system/statistics.css', 'core', 'admin' ) );
|
||||
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'system/reports.css', 'core', 'admin' ) );
|
||||
|
||||
$reports = iterator_to_array( Db::i()->select( "*", "core_reports", order: "report_title ASC" ) );
|
||||
$reportOptions = [];
|
||||
$defaultOption = false;
|
||||
foreach( $reports as $row )
|
||||
{
|
||||
$defaultOption = $defaultOption ?: "report_" . $row["id"];
|
||||
$reportOptions["report_" . $row['id']] = $row['report_title'];
|
||||
}
|
||||
|
||||
$noTabs = (bool) $this->extension?->noTabs;
|
||||
$this->form->add( new YesNo( "statsreports_show_all_members", $noTabs, false, ['disabled' => $noTabs] ) );
|
||||
$globalTogglesOn = ['statsreports_report_select'];
|
||||
if ( empty( $reports ) )
|
||||
{
|
||||
$globalTogglesOn[] = "statsreports_report_new_title";
|
||||
}
|
||||
|
||||
$this->form->add( new YesNo( "statsreports_include_in_report", false, false, [ "togglesOn" => $globalTogglesOn ] ) );
|
||||
|
||||
// if there are saved reports, allow user to select one of them
|
||||
if ( !empty( $reportOptions ) )
|
||||
{
|
||||
// todo an autocomplete field is probably a better UX when there could be dozens of reports saved
|
||||
$this->form->add( new Select( "statsreports_report", $defaultOption, false, [
|
||||
"unlimited" => false,
|
||||
"unlimitedLang" => "statsreports_report_new",
|
||||
"unlimitedToggles" => [
|
||||
'statsreports_report_new_title'
|
||||
],
|
||||
"options" => $reportOptions,
|
||||
], id: 'statsreports_report_select' ) );
|
||||
}
|
||||
|
||||
$this->form->add( new Text( "statsreports_report_new_title", $this->title, null, id: "statsreports_report_new_title" ) );
|
||||
$this->form->add( new Text( 'custom_chart_title', $this->title, true ) );
|
||||
|
||||
if( $values = $this->form->values() )
|
||||
{
|
||||
@@ -498,14 +578,37 @@ abstract class Dynamic extends Chart
|
||||
|
||||
$chartFilters = ( isset( Request::i()->chartFilters ) and Request::i()->chartFilters ) ? Request::i()->chartFilters : array();
|
||||
|
||||
/* Store the new chart */
|
||||
$id = Db::i()->insert( 'core_saved_charts', array(
|
||||
'chart_member' => Member::loggedIn()->member_id,
|
||||
'chart_controller' => Request::i()->app . '_' . Request::i()->module . '_' . Request::i()->controller . ( Request::i()->tab ? '_' . Request::i()->tab : '' ),
|
||||
// is it saved to a report?
|
||||
$reportID = null;
|
||||
if ( @$values['statsreports_include_in_report'] )
|
||||
{
|
||||
if ( isset( $values['statsreports_report'] ) and $values['statsreports_report'] )
|
||||
{
|
||||
$reportID = (int) explode( '_', $values['statsreports_report'], 2 )[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = $values['statsreports_report_new_title'];
|
||||
$reportID = Db::i()->insert( "core_reports", [ "report_title" => $title] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $noTabs )
|
||||
{
|
||||
$values['statsreports_show_all_members'] = true;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'chart_member' => @$values['statsreports_show_all_members'] ? 0 : Member::loggedIn()->member_id, // we make the member "0" when the show to all members option is enabled
|
||||
'chart_controller' => $this->getController(),
|
||||
'chart_configuration' => json_encode( array_merge( $chartFilters, $custom ) ),
|
||||
'chart_timescale' => Request::i()->timescale ?? $this->timescale ?? 'monthly',
|
||||
'chart_title' => $values['custom_chart_title'],
|
||||
) );
|
||||
'chart_report_id' => $reportID
|
||||
);
|
||||
|
||||
/* Store the new chart */
|
||||
$id = Db::i()->insert( 'core_saved_charts', $data );
|
||||
|
||||
/* Set some input parameters */
|
||||
$this->url = $this->url->setQueryString( 'chartId', $id );
|
||||
@@ -526,6 +629,7 @@ abstract class Dynamic extends Chart
|
||||
|
||||
/* And then return the output we need */
|
||||
Output::i()->json( array(
|
||||
'reportURL' => ($data['chart_member'] and !$data['chart_report_id']) ? null : Url::internal( "app=core&module=overview&controller=mycharts&highlight={$id}" . ( $data['chart_report_id'] ? "&report_id={$data['chart_report_id']}" : "" ) ),
|
||||
'tabHref' => $this->url->stripQueryString( 'filters' ),
|
||||
'chartId' => $id,
|
||||
'tabId' => md5( $this->url->acpQueryString() ),
|
||||
@@ -576,6 +680,21 @@ abstract class Dynamic extends Chart
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "controller" to use when saving this chart
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getController() : string
|
||||
{
|
||||
if ( is_string( $this->extension?->controller ) )
|
||||
{
|
||||
return $this->extension->controller;
|
||||
}
|
||||
|
||||
return Request::i()->app . '_' . Request::i()->module . '_' . Request::i()->controller . ( Request::i()->tab ? '_' . Request::i()->tab : '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Show filter tabs
|
||||
*/
|
||||
@@ -586,6 +705,8 @@ abstract class Dynamic extends Chart
|
||||
*/
|
||||
protected ?array $availableChartTabs = NULL;
|
||||
|
||||
protected ?array $savedCharts = null;
|
||||
|
||||
/**
|
||||
* @Brief Extension
|
||||
*/
|
||||
@@ -617,19 +738,35 @@ abstract class Dynamic extends Chart
|
||||
{
|
||||
if ( $this->availableChartTabs === null )
|
||||
{
|
||||
if ( $this->extension !== null )
|
||||
if ( $this->extension?->noTabs )
|
||||
{
|
||||
$this->availableChartTabs = iterator_to_array( Db::i()->select( '*', 'core_saved_charts', ['chart_member=? AND chart_controller=?', Member::loggedIn()->member_id, $this->extension->controller] ) );
|
||||
$this->availableChartTabs = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->availableChartTabs = iterator_to_array( Db::i()->select( '*', 'core_saved_charts', ['chart_member=? AND chart_controller=?', Member::loggedIn()->member_id, Request::i()->app . '_' . Request::i()->module . '_' . Request::i()->controller . ( Request::i()->tab ? '_' . Request::i()->tab : '' )] ) );
|
||||
$this->availableChartTabs = iterator_to_array( Db::i()->select( '*', 'core_saved_charts', ['chart_member=? AND chart_controller=? AND chart_report_id IS NULL', Member::loggedIn()->member_id, $this->getController()] ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->availableChartTabs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load and return available chart tabs
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
protected function loadSavedCharts() : ?array
|
||||
{
|
||||
if ( $this->savedCharts === null )
|
||||
{
|
||||
$this->savedCharts = iterator_to_array( Db::i()->select( '*', 'core_saved_charts', ['(chart_member=? OR chart_member=0 OR chart_member IS NULL) AND chart_controller=?', Member::loggedIn()->member_id, $this->getController()] ) );
|
||||
}
|
||||
|
||||
return $this->savedCharts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set extension
|
||||
*
|
||||
@@ -672,6 +809,12 @@ abstract class Dynamic extends Chart
|
||||
*/
|
||||
protected function initData(): array
|
||||
{
|
||||
/* The JS can set this to "undefined" so let's make sure it's a valid value */
|
||||
if ( !in_array( $this->timescale, ["none", "hourly", "daily", "monthly", "weekly"] ) )
|
||||
{
|
||||
$this->timescale = "monthly";
|
||||
}
|
||||
|
||||
/* Init data */
|
||||
$data = array();
|
||||
if ( $this->start AND $this->timescale !== 'none' )
|
||||
|
||||
Reference in new issue
Block a user