diff --git a/README.md b/README.md index 4b914c0a..a1be54bf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Speedtest Tracker -[![Docker pulls](https://img.shields.io/docker/pulls/henrywhitaker3/speedtest-tracker?style=flat-square)](https://hub.docker.com/r/henrywhitaker3/speedtest-tracker) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/henrywhitaker3/Speedtest-Tracker/Stable?label=master&logo=github&style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/henrywhitaker3/Speedtest-Tracker/Dev?label=dev&logo=github&style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [![last_commit](https://img.shields.io/github/last-commit/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) [![issues](https://img.shields.io/github/issues/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/issues) [![commit_freq](https://img.shields.io/github/commit-activity/m/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) ![version](https://img.shields.io/badge/version-v1.10.1-success?style=flat-square) [![license](https://img.shields.io/github/license/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/blob/master/LICENSE) +[![Docker pulls](https://img.shields.io/docker/pulls/henrywhitaker3/speedtest-tracker?style=flat-square)](https://hub.docker.com/r/henrywhitaker3/speedtest-tracker) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/henrywhitaker3/Speedtest-Tracker/Stable?label=master&logo=github&style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/henrywhitaker3/Speedtest-Tracker/Dev?label=dev&logo=github&style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [![last_commit](https://img.shields.io/github/last-commit/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) [![issues](https://img.shields.io/github/issues/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/issues) [![commit_freq](https://img.shields.io/github/commit-activity/m/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) ![version](https://img.shields.io/badge/version-v1.10.3-success?style=flat-square) [![license](https://img.shields.io/github/license/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/blob/master/LICENSE) This program runs a speedtest check every hour and graphs the results. The back-end is written in [Laravel](https://laravel.com/) and the front-end uses [React](https://reactjs.org/). It uses [Ookla's Speedtest cli](https://www.speedtest.net/apps/cli) to get the data and uses [Chart.js](https://www.chartjs.org/) to plot the results. diff --git a/conf/site/README.md b/conf/site/README.md index 187eba98..42ae6759 100644 --- a/conf/site/README.md +++ b/conf/site/README.md @@ -1,6 +1,6 @@ # Speedtest Tracker -[![Docker pulls](https://img.shields.io/docker/pulls/henrywhitaker3/speedtest-tracker?style=flat-square)](https://hub.docker.com/r/henrywhitaker3/speedtest-tracker) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/henrywhitaker3/Speedtest-Tracker/Stable?label=master&logo=github&style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/henrywhitaker3/Speedtest-Tracker/Dev?label=dev&logo=github&style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [![last_commit](https://img.shields.io/github/last-commit/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) [![issues](https://img.shields.io/github/issues/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/issues) [![commit_freq](https://img.shields.io/github/commit-activity/m/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) ![version](https://img.shields.io/badge/version-v1.10.1-success?style=flat-square) [![license](https://img.shields.io/github/license/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/blob/master/LICENSE) +[![Docker pulls](https://img.shields.io/docker/pulls/henrywhitaker3/speedtest-tracker?style=flat-square)](https://hub.docker.com/r/henrywhitaker3/speedtest-tracker) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/henrywhitaker3/Speedtest-Tracker/Stable?label=master&logo=github&style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/henrywhitaker3/Speedtest-Tracker/Dev?label=dev&logo=github&style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [![last_commit](https://img.shields.io/github/last-commit/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) [![issues](https://img.shields.io/github/issues/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/issues) [![commit_freq](https://img.shields.io/github/commit-activity/m/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) ![version](https://img.shields.io/badge/version-v1.10.3-success?style=flat-square) [![license](https://img.shields.io/github/license/henrywhitaker3/Speedtest-Tracker?style=flat-square)](https://github.com/henrywhitaker3/Speedtest-Tracker/blob/master/LICENSE) This program runs a speedtest check every hour and graphs the results. The back-end is written in [Laravel](https://laravel.com/) and the front-end uses [React](https://reactjs.org/). It uses the [Ookla's speedtest cli](https://www.speedtest.net/apps/cli) package to get the data and uses [Chart.js](https://www.chartjs.org/) to plot the results. diff --git a/conf/site/app/Console/Kernel.php b/conf/site/app/Console/Kernel.php index 825fa4ee..44157a7a 100644 --- a/conf/site/app/Console/Kernel.php +++ b/conf/site/app/Console/Kernel.php @@ -28,7 +28,9 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - $schedule->job(new SpeedtestJob(true, config('integrations')))->cron(SettingsHelper::get('schedule')['value']); + if ((bool)SettingsHelper::get('schedule_enabled')->value) { + $schedule->job(new SpeedtestJob(true, config('integrations')))->cron(SettingsHelper::get('schedule')['value']); + } $schedule->command('speedtest:overview')->cron('0 ' . SettingsHelper::get('speedtest_overview_time')->value . ' * * *'); $schedule->command('speedtest:clear-sessions')->everyMinute(); } @@ -40,7 +42,7 @@ class Kernel extends ConsoleKernel */ protected function commands() { - $this->load(__DIR__.'/Commands'); + $this->load(__DIR__ . '/Commands'); require base_path('routes/console.php'); } diff --git a/conf/site/app/Helpers/SettingsHelper.php b/conf/site/app/Helpers/SettingsHelper.php index 7e1ff0e1..8acffb36 100644 --- a/conf/site/app/Helpers/SettingsHelper.php +++ b/conf/site/app/Helpers/SettingsHelper.php @@ -91,6 +91,11 @@ class SettingsHelper */ public static function settingIsEditable(string $key) { + // Manual override for app_name + if ($key === 'app_name') { + return true; + } + $results = []; // Try exact key @@ -139,6 +144,7 @@ class SettingsHelper { return [ 'base' => SettingsHelper::getBase(), + 'name' => SettingsHelper::get('app_name')->value, 'widgets' => [ 'show_average' => (bool)SettingsHelper::get('show_average')->value, 'show_max' => (bool)SettingsHelper::get('show_max')->value, diff --git a/conf/site/app/Http/Controllers/SettingsController.php b/conf/site/app/Http/Controllers/SettingsController.php index aec8c39b..4d7202d6 100644 --- a/conf/site/app/Http/Controllers/SettingsController.php +++ b/conf/site/app/Http/Controllers/SettingsController.php @@ -15,9 +15,9 @@ class SettingsController extends Controller { public function __construct() { - if((bool)SettingsHelper::get('auth')->value === true) { + if ((bool)SettingsHelper::get('auth')->value === true) { $this->middleware('auth:api') - ->except([ 'config' ]); + ->except(['config']); } } @@ -51,21 +51,21 @@ class SettingsController extends Controller public function store(Request $request) { $rule = [ - 'name' => [ 'required', 'string', 'min:1' ], + 'name' => ['required', 'string', 'min:1'], ]; - if($request->name == 'schedule') { - $rule['value'] = [ 'required', new Cron ]; + if ($request->name == 'schedule') { + $rule['value'] = ['required', new Cron]; } $validator = Validator::make($request->all(), $rule); - if($validator->fails()) { + if ($validator->fails()) { return response()->json([ 'method' => 'Store a setting', 'error' => $validator->errors() ], 422); } - if(!isset($request->value)) { + if (!isset($request->value)) { $request->value = ''; } @@ -86,12 +86,12 @@ class SettingsController extends Controller public function bulkStore(Request $request) { $rule = [ - 'data' => [ 'array', 'required' ], - 'data.*.name' => [ 'string', 'required' ], + 'data' => ['array', 'required'], + 'data.*.name' => ['string', 'required'], ]; $validator = Validator::make($request->all(), $rule); - if($validator->fails()) { + if ($validator->fails()) { return response()->json([ 'method' => 'Bulk store a setting', 'error' => $validator->errors() @@ -99,14 +99,14 @@ class SettingsController extends Controller } $settings = []; - foreach($request->data as $d) { - if(!isset($d['value']) || $d['value'] == null) { - $d['value'] = ''; + foreach ($request->data as $d) { + if (!isset($d['value']) || $d['value'] == null) { + $d['value'] = ''; } - if($d['name'] == 'speedtest_overview_time') { - $ok = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23' ]; - if(!in_array($d['value'], $ok)) { + if ($d['name'] == 'speedtest_overview_time') { + $ok = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']; + if (!in_array($d['value'], $ok)) { return response()->json([ 'method' => 'Bulk store a setting', 'error' => 'Invalid speedtest_overview_time value' @@ -116,9 +116,9 @@ class SettingsController extends Controller $setting = SettingsHelper::get($d['name']); - if($setting == false) { + if ($setting == false) { $setting = SettingsHelper::set($d['name'], $d['value']); - } else if(SettingsHelper::settingIsEditable($setting->name)) { + } else if (SettingsHelper::settingIsEditable($setting->name)) { $setting = SettingsHelper::set($d['name'], $d['value']); } else { continue; diff --git a/conf/site/app/Jobs/SpeedtestJob.php b/conf/site/app/Jobs/SpeedtestJob.php index bbf43f8e..749aa20b 100644 --- a/conf/site/app/Jobs/SpeedtestJob.php +++ b/conf/site/app/Jobs/SpeedtestJob.php @@ -52,19 +52,19 @@ class SpeedtestJob implements ShouldQueue */ public function handle() { - if($this->config['healthchecks_enabled'] === true) { + if ($this->config['healthchecks_enabled'] === true) { $this->healthcheck('start'); } $output = SpeedtestHelper::output(); $speedtest = SpeedtestHelper::runSpeedtest($output, $this->scheduled); - if($speedtest == false) { - if($this->config['healthchecks_enabled'] === true) { + if ($speedtest == false) { + if ($this->config['healthchecks_enabled'] === true) { $this->healthcheck('fail'); } event(new SpeedtestFailedEvent()); } else { - if($this->config['healthchecks_enabled'] === true) { + if ($this->config['healthchecks_enabled'] === true) { $this->healthcheck('success'); } @@ -82,19 +82,19 @@ class SpeedtestJob implements ShouldQueue private function healthcheck(String $method) { try { - $hc = new Healthchecks(SettingsHelper::get('healthchecks_uuid')->value); - if($method === 'start') { + $hc = new Healthchecks(SettingsHelper::get('healthchecks_uuid')->value, SettingsHelper::get('healthchecks_server_url')->value); + if ($method === 'start') { $hc->start(); } - if($method === 'success') { + if ($method === 'success') { $hc->success(); } - if($method === 'fail') { + if ($method === 'fail') { $hc->fail(); } - } catch(Exception $e) { + } catch (Exception $e) { Log::error($e->getMessage()); } } diff --git a/conf/site/app/Providers/IntegrationsServiceProvider.php b/conf/site/app/Providers/IntegrationsServiceProvider.php index 94a91825..7c66f1b9 100644 --- a/conf/site/app/Providers/IntegrationsServiceProvider.php +++ b/conf/site/app/Providers/IntegrationsServiceProvider.php @@ -44,7 +44,7 @@ class IntegrationsServiceProvider extends ServiceProvider SettingsHelper::loadIntegrationConfig(); App::bind('healthcheck', function () use ($setting) { - return new Healthchecks($setting->value); + return new Healthchecks($setting->value, SettingsHelper::get('healthchecks_server_url')->value); }); } catch (InvalidUuidStringException $e) { Log::error('Invalid healthchecks UUID'); diff --git a/conf/site/changelog.json b/conf/site/changelog.json index abb384cb..72c4d323 100644 --- a/conf/site/changelog.json +++ b/conf/site/changelog.json @@ -1,4 +1,16 @@ { + "1.10.3": [ + { + "description": "Moved stuff into pages.", + "link": "" + } + ], + "1.10.2": [ + { + "description": "Added option to disable scheduled tests.", + "link": "" + } + ], "1.10.1": [ { "description": "Fixed integrations config being empty causing healthchecks to not run on scheduled tests.", diff --git a/conf/site/composer.lock b/conf/site/composer.lock index 04032c59..6a4ba6b0 100644 --- a/conf/site/composer.lock +++ b/conf/site/composer.lock @@ -8,20 +8,20 @@ "packages": [ { "name": "asm89/stack-cors", - "version": "v2.0.1", + "version": "v2.0.2", "source": { "type": "git", "url": "https://github.com/asm89/stack-cors.git", - "reference": "23f469e81c65e2fb7fc7bce371fbdc363fe32adf" + "reference": "8d8f88b3b3830916be94292c1fbce84433efb1aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/asm89/stack-cors/zipball/23f469e81c65e2fb7fc7bce371fbdc363fe32adf", - "reference": "23f469e81c65e2fb7fc7bce371fbdc363fe32adf", + "url": "https://api.github.com/repos/asm89/stack-cors/zipball/8d8f88b3b3830916be94292c1fbce84433efb1aa", + "reference": "8d8f88b3b3830916be94292c1fbce84433efb1aa", "shasum": "" }, "require": { - "php": "^7.0", + "php": "^7.0|^8.0", "symfony/http-foundation": "~2.7|~3.0|~4.0|~5.0", "symfony/http-kernel": "~2.7|~3.0|~4.0|~5.0" }, @@ -56,7 +56,7 @@ "cors", "stack" ], - "time": "2020-05-31T07:17:05+00:00" + "time": "2020-10-29T16:03:21+00:00" }, { "name": "brick/math", @@ -241,33 +241,32 @@ }, { "name": "doctrine/dbal", - "version": "2.10.4", + "version": "2.12.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "47433196b6390d14409a33885ee42b6208160643" + "reference": "adce7a954a1c2f14f85e94aed90c8489af204086" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/47433196b6390d14409a33885ee42b6208160643", - "reference": "47433196b6390d14409a33885ee42b6208160643", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/adce7a954a1c2f14f85e94aed90c8489af204086", + "reference": "adce7a954a1c2f14f85e94aed90c8489af204086", "shasum": "" }, "require": { "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0", "ext-pdo": "*", - "php": "^7.2" + "php": "^7.3 || ^8" }, "require-dev": { "doctrine/coding-standard": "^8.1", "jetbrains/phpstorm-stubs": "^2019.1", - "nikic/php-parser": "^4.4", "phpstan/phpstan": "^0.12.40", - "phpunit/phpunit": "^8.5.5", + "phpunit/phpunit": "^9.4", "psalm/plugin-phpunit": "^0.10.0", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", - "vimeo/psalm": "^3.14.2" + "vimeo/psalm": "^3.17.2" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -278,8 +277,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.10.x-dev", - "dev-develop": "3.0.x-dev" + "dev-master": "4.0.x-dev" } }, "autoload": { @@ -346,7 +344,7 @@ "type": "tidelift" } ], - "time": "2020-09-12T21:20:41+00:00" + "time": "2020-11-14T20:26:58+00:00" }, { "name": "doctrine/event-manager", @@ -513,20 +511,6 @@ "uppercase", "words" ], - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", - "type": "tidelift" - } - ], "time": "2020-05-29T15:13:26+00:00" }, { @@ -589,20 +573,6 @@ "parser", "php" ], - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", - "type": "tidelift" - } - ], "time": "2020-05-25T17:44:05+00:00" }, { @@ -1822,16 +1792,16 @@ }, { "name": "monolog/monolog", - "version": "2.1.1", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5" + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f9eee5cec93dfb313a38b6b288741e84e53f02d5", - "reference": "f9eee5cec93dfb313a38b6b288741e84e53f02d5", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", "shasum": "" }, "require": { @@ -1844,16 +1814,17 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^6.0", + "elasticsearch/elasticsearch": "^7", "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", - "php-parallel-lint/php-parallel-lint": "^1.0", "phpspec/prophecy": "^1.6.1", + "phpstan/phpstan": "^0.12.59", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", - "ruflin/elastica": ">=0.90 <3.0", + "ruflin/elastica": ">=0.90 <7.0.1", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { @@ -1873,7 +1844,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-main": "2.x-dev" } }, "autoload": { @@ -1889,11 +1860,11 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ "log", "logging", @@ -1909,7 +1880,7 @@ "type": "tidelift" } ], - "time": "2020-07-23T08:41:23+00:00" + "time": "2020-12-14T13:15:25+00:00" }, { "name": "namshi/jose", @@ -1976,16 +1947,16 @@ }, { "name": "nesbot/carbon", - "version": "2.42.0", + "version": "2.43.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "d0463779663437392fe42ff339ebc0213bd55498" + "reference": "d32c57d8389113742f4a88725a170236470012e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d0463779663437392fe42ff339ebc0213bd55498", - "reference": "d0463779663437392fe42ff339ebc0213bd55498", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d32c57d8389113742f4a88725a170236470012e2", + "reference": "d32c57d8389113742f4a88725a170236470012e2", "shasum": "" }, "require": { @@ -2061,20 +2032,20 @@ "type": "tidelift" } ], - "time": "2020-11-28T14:25:28+00:00" + "time": "2020-12-17T20:55:32+00:00" }, { "name": "nikic/php-parser", - "version": "v4.10.2", + "version": "v4.10.3", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "658f1be311a230e0907f5dfe0213742aff0596de" + "reference": "dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/658f1be311a230e0907f5dfe0213742aff0596de", - "reference": "658f1be311a230e0907f5dfe0213742aff0596de", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984", + "reference": "dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984", "shasum": "" }, "require": { @@ -2113,7 +2084,7 @@ "parser", "php" ], - "time": "2020-09-26T10:30:38+00:00" + "time": "2020-12-03T17:45:45+00:00" }, { "name": "opis/closure", @@ -2532,16 +2503,16 @@ }, { "name": "psy/psysh", - "version": "v0.10.4", + "version": "v0.10.5", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "a8aec1b2981ab66882a01cce36a49b6317dc3560" + "reference": "7c710551d4a2653afa259c544508dc18a9098956" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/a8aec1b2981ab66882a01cce36a49b6317dc3560", - "reference": "a8aec1b2981ab66882a01cce36a49b6317dc3560", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/7c710551d4a2653afa259c544508dc18a9098956", + "reference": "7c710551d4a2653afa259c544508dc18a9098956", "shasum": "" }, "require": { @@ -2600,20 +2571,20 @@ "interactive", "shell" ], - "time": "2020-05-03T19:32:03+00:00" + "time": "2020-12-04T02:51:30+00:00" }, { "name": "rakit/validation", - "version": "v1.3.2", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/rakit/validation.git", - "reference": "126306ccabeadec24b6fa310605c71be67dee188" + "reference": "ff003a35cdf5030a5f2482299f4c93f344a35b29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rakit/validation/zipball/126306ccabeadec24b6fa310605c71be67dee188", - "reference": "126306ccabeadec24b6fa310605c71be67dee188", + "url": "https://api.github.com/repos/rakit/validation/zipball/ff003a35cdf5030a5f2482299f4c93f344a35b29", + "reference": "ff003a35cdf5030a5f2482299f4c93f344a35b29", "shasum": "" }, "require": { @@ -2642,7 +2613,7 @@ } ], "description": "PHP Laravel like standalone validation library", - "time": "2020-08-09T01:18:04+00:00" + "time": "2020-08-27T05:07:01+00:00" }, { "name": "ralouphie/getallheaders", @@ -2842,32 +2813,31 @@ }, { "name": "swiftmailer/swiftmailer", - "version": "v6.2.3", + "version": "v6.2.4", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9" + "reference": "56f0ab23f54c4ccbb0d5dcc67ff8552e0c98d59e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/149cfdf118b169f7840bbe3ef0d4bc795d1780c9", - "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/56f0ab23f54c4ccbb0d5dcc67ff8552e0c98d59e", + "reference": "56f0ab23f54c4ccbb0d5dcc67ff8552e0c98d59e", "shasum": "" }, "require": { - "egulias/email-validator": "~2.0", + "egulias/email-validator": "^2.0", "php": ">=7.0.0", "symfony/polyfill-iconv": "^1.0", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, "require-dev": { - "mockery/mockery": "~0.9.1", - "symfony/phpunit-bridge": "^3.4.19|^4.1.8" + "mockery/mockery": "^1.0", + "symfony/phpunit-bridge": "^4.4|^5.0" }, "suggest": { - "ext-intl": "Needed to support internationalized email addresses", - "true/punycode": "Needed to support internationalized email addresses, if ext-intl is not installed" + "ext-intl": "Needed to support internationalized email addresses" }, "type": "library", "extra": { @@ -2900,20 +2870,30 @@ "mail", "mailer" ], - "time": "2019-11-12T09:31:26+00:00" + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/swiftmailer/swiftmailer", + "type": "tidelift" + } + ], + "time": "2020-12-08T18:02:06+00:00" }, { "name": "symfony/console", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "3e0564fb08d44a98bd5f1960204c958e57bd586b" + "reference": "47c02526c532fb381374dab26df05e7313978976" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/3e0564fb08d44a98bd5f1960204c958e57bd586b", - "reference": "3e0564fb08d44a98bd5f1960204c958e57bd586b", + "url": "https://api.github.com/repos/symfony/console/zipball/47c02526c532fb381374dab26df05e7313978976", + "reference": "47c02526c532fb381374dab26df05e7313978976", "shasum": "" }, "require": { @@ -2994,20 +2974,20 @@ "type": "tidelift" } ], - "time": "2020-11-28T11:24:18+00:00" + "time": "2020-12-18T08:03:05+00:00" }, { "name": "symfony/css-selector", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "b8d8eb06b0942e84a69e7acebc3e9c1e6e6e7256" + "reference": "f789e7ead4c79e04ca9a6d6162fc629c89bd8054" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/b8d8eb06b0942e84a69e7acebc3e9c1e6e6e7256", - "reference": "b8d8eb06b0942e84a69e7acebc3e9c1e6e6e7256", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/f789e7ead4c79e04ca9a6d6162fc629c89bd8054", + "reference": "f789e7ead4c79e04ca9a6d6162fc629c89bd8054", "shasum": "" }, "require": { @@ -3056,7 +3036,7 @@ "type": "tidelift" } ], - "time": "2020-10-28T21:31:18+00:00" + "time": "2020-12-08T17:02:38+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3124,16 +3104,16 @@ }, { "name": "symfony/error-handler", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "289008c5be039e39908d33ae0a8ac99be1210bba" + "reference": "59b190ce16ddf32771a22087b60f6dafd3407147" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/289008c5be039e39908d33ae0a8ac99be1210bba", - "reference": "289008c5be039e39908d33ae0a8ac99be1210bba", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/59b190ce16ddf32771a22087b60f6dafd3407147", + "reference": "59b190ce16ddf32771a22087b60f6dafd3407147", "shasum": "" }, "require": { @@ -3186,20 +3166,20 @@ "type": "tidelift" } ], - "time": "2020-10-28T21:46:03+00:00" + "time": "2020-12-09T18:54:12+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "aa13a09811e6d2ad43f8fb336bebdb7691d85d3c" + "reference": "1c93f7a1dff592c252574c79a8635a8a80856042" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/aa13a09811e6d2ad43f8fb336bebdb7691d85d3c", - "reference": "aa13a09811e6d2ad43f8fb336bebdb7691d85d3c", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1c93f7a1dff592c252574c79a8635a8a80856042", + "reference": "1c93f7a1dff592c252574c79a8635a8a80856042", "shasum": "" }, "require": { @@ -3268,7 +3248,7 @@ "type": "tidelift" } ], - "time": "2020-11-01T16:14:45+00:00" + "time": "2020-12-18T08:03:05+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -3348,16 +3328,16 @@ }, { "name": "symfony/finder", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "fd8305521692f27eae3263895d1ef1571c71a78d" + "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/fd8305521692f27eae3263895d1ef1571c71a78d", - "reference": "fd8305521692f27eae3263895d1ef1571c71a78d", + "url": "https://api.github.com/repos/symfony/finder/zipball/0b9231a5922fd7287ba5b411893c0ecd2733e5ba", + "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba", "shasum": "" }, "require": { @@ -3402,7 +3382,7 @@ "type": "tidelift" } ], - "time": "2020-11-18T09:42:36+00:00" + "time": "2020-12-08T17:02:38+00:00" }, { "name": "symfony/http-client-contracts", @@ -3482,16 +3462,16 @@ }, { "name": "symfony/http-foundation", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "e4576271ee99123aa59a40564c7b5405f0ebd1e6" + "reference": "a1f6218b29897ab52acba58cfa905b83625bef8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e4576271ee99123aa59a40564c7b5405f0ebd1e6", - "reference": "e4576271ee99123aa59a40564c7b5405f0ebd1e6", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a1f6218b29897ab52acba58cfa905b83625bef8d", + "reference": "a1f6218b29897ab52acba58cfa905b83625bef8d", "shasum": "" }, "require": { @@ -3548,20 +3528,20 @@ "type": "tidelift" } ], - "time": "2020-11-27T06:13:25+00:00" + "time": "2020-12-18T10:00:10+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "38907e5ccb2d9d371191a946734afc83c7a03160" + "reference": "1feb619286d819180f7b8bc0dc44f516d9c62647" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/38907e5ccb2d9d371191a946734afc83c7a03160", - "reference": "38907e5ccb2d9d371191a946734afc83c7a03160", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1feb619286d819180f7b8bc0dc44f516d9c62647", + "reference": "1feb619286d819180f7b8bc0dc44f516d9c62647", "shasum": "" }, "require": { @@ -3657,20 +3637,20 @@ "type": "tidelift" } ], - "time": "2020-11-30T05:54:18+00:00" + "time": "2020-12-18T13:49:39+00:00" }, { "name": "symfony/mime", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "05f667e8fa029568964fd3bec6bc17765b853cc5" + "reference": "de97005aef7426ba008c46ba840fc301df577ada" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/05f667e8fa029568964fd3bec6bc17765b853cc5", - "reference": "05f667e8fa029568964fd3bec6bc17765b853cc5", + "url": "https://api.github.com/repos/symfony/mime/zipball/de97005aef7426ba008c46ba840fc301df577ada", + "reference": "de97005aef7426ba008c46ba840fc301df577ada", "shasum": "" }, "require": { @@ -3734,7 +3714,7 @@ "type": "tidelift" } ], - "time": "2020-10-30T14:55:39+00:00" + "time": "2020-12-09T18:54:12+00:00" }, { "name": "symfony/polyfill-ctype", @@ -4505,16 +4485,16 @@ }, { "name": "symfony/process", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "240e74140d4d956265048f3025c0aecbbc302d54" + "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/240e74140d4d956265048f3025c0aecbbc302d54", - "reference": "240e74140d4d956265048f3025c0aecbbc302d54", + "url": "https://api.github.com/repos/symfony/process/zipball/bd8815b8b6705298beaa384f04fabd459c10bedd", + "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd", "shasum": "" }, "require": { @@ -4560,20 +4540,20 @@ "type": "tidelift" } ], - "time": "2020-11-02T15:47:15+00:00" + "time": "2020-12-08T17:03:37+00:00" }, { "name": "symfony/routing", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "130ac5175ad2fd417978baebd8062e2e6b2bc28b" + "reference": "934ac2720dcc878a47a45c986b483a7ee7193620" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/130ac5175ad2fd417978baebd8062e2e6b2bc28b", - "reference": "130ac5175ad2fd417978baebd8062e2e6b2bc28b", + "url": "https://api.github.com/repos/symfony/routing/zipball/934ac2720dcc878a47a45c986b483a7ee7193620", + "reference": "934ac2720dcc878a47a45c986b483a7ee7193620", "shasum": "" }, "require": { @@ -4647,7 +4627,7 @@ "type": "tidelift" } ], - "time": "2020-11-27T00:39:34+00:00" + "time": "2020-12-08T17:03:37+00:00" }, { "name": "symfony/service-contracts", @@ -4727,16 +4707,16 @@ }, { "name": "symfony/string", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "40e975edadd4e32cd16f3753b3bad65d9ac48242" + "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/40e975edadd4e32cd16f3753b3bad65d9ac48242", - "reference": "40e975edadd4e32cd16f3753b3bad65d9ac48242", + "url": "https://api.github.com/repos/symfony/string/zipball/5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", + "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", "shasum": "" }, "require": { @@ -4803,20 +4783,20 @@ "type": "tidelift" } ], - "time": "2020-10-24T12:08:07+00:00" + "time": "2020-12-05T07:33:16+00:00" }, { "name": "symfony/translation", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "52f486a707510884450df461b5a6429dd7a67379" + "reference": "a04209ba0d1391c828e5b2373181dac63c52ee70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/52f486a707510884450df461b5a6429dd7a67379", - "reference": "52f486a707510884450df461b5a6429dd7a67379", + "url": "https://api.github.com/repos/symfony/translation/zipball/a04209ba0d1391c828e5b2373181dac63c52ee70", + "reference": "a04209ba0d1391c828e5b2373181dac63c52ee70", "shasum": "" }, "require": { @@ -4893,7 +4873,7 @@ "type": "tidelift" } ], - "time": "2020-11-28T11:24:18+00:00" + "time": "2020-12-08T17:03:37+00:00" }, { "name": "symfony/translation-contracts", @@ -4972,16 +4952,16 @@ }, { "name": "symfony/var-dumper", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "173a79c462b1c81e1fa26129f71e41333d846b26" + "reference": "13e7e882eaa55863faa7c4ad7c60f12f1a8b5089" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/173a79c462b1c81e1fa26129f71e41333d846b26", - "reference": "173a79c462b1c81e1fa26129f71e41333d846b26", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/13e7e882eaa55863faa7c4ad7c60f12f1a8b5089", + "reference": "13e7e882eaa55863faa7c4ad7c60f12f1a8b5089", "shasum": "" }, "require": { @@ -5053,7 +5033,7 @@ "type": "tidelift" } ], - "time": "2020-11-27T00:39:34+00:00" + "time": "2020-12-16T17:02:19+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -5898,22 +5878,22 @@ }, { "name": "facade/flare-client-php", - "version": "1.3.6", + "version": "1.3.7", "source": { "type": "git", "url": "https://github.com/facade/flare-client-php.git", - "reference": "451fadf38e9f635e7f8e1f5b3cf5c9eb82f11799" + "reference": "fd688d3c06658f2b3b5f7bb19f051ee4ddf02492" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/451fadf38e9f635e7f8e1f5b3cf5c9eb82f11799", - "reference": "451fadf38e9f635e7f8e1f5b3cf5c9eb82f11799", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/fd688d3c06658f2b3b5f7bb19f051ee4ddf02492", + "reference": "fd688d3c06658f2b3b5f7bb19f051ee4ddf02492", "shasum": "" }, "require": { "facade/ignition-contracts": "~1.0", "illuminate/pipeline": "^5.5|^6.0|^7.0|^8.0", - "php": "^7.1", + "php": "^7.1|^8.0", "symfony/http-foundation": "^3.3|^4.1|^5.0", "symfony/mime": "^3.4|^4.0|^5.1", "symfony/var-dumper": "^3.4|^4.0|^5.0" @@ -5955,32 +5935,31 @@ "type": "github" } ], - "time": "2020-09-18T06:35:11+00:00" + "time": "2020-10-21T16:02:39+00:00" }, { "name": "facade/ignition", - "version": "2.4.1", + "version": "2.5.3", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "9fc6c3d3de5271a1b94cff19dce2c9295abf0ffa" + "reference": "d8dc4f90ed469f9f9313b976fb078c20585d5c99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/9fc6c3d3de5271a1b94cff19dce2c9295abf0ffa", - "reference": "9fc6c3d3de5271a1b94cff19dce2c9295abf0ffa", + "url": "https://api.github.com/repos/facade/ignition/zipball/d8dc4f90ed469f9f9313b976fb078c20585d5c99", + "reference": "d8dc4f90ed469f9f9313b976fb078c20585d5c99", "shasum": "" }, "require": { "ext-json": "*", "ext-mbstring": "*", - "facade/flare-client-php": "^1.0", - "facade/ignition-contracts": "^1.0", + "facade/flare-client-php": "^1.3.7", + "facade/ignition-contracts": "^1.0.2", "filp/whoops": "^2.4", "illuminate/support": "^7.0|^8.0", "monolog/monolog": "^2.0", - "php": "^7.2.5", - "scrivo/highlight.php": "^9.15", + "php": "^7.2.5|^8.0", "symfony/console": "^5.0", "symfony/var-dumper": "^5.0" }, @@ -6027,29 +6006,29 @@ "laravel", "page" ], - "time": "2020-10-14T08:59:59+00:00" + "time": "2020-12-09T20:25:45+00:00" }, { "name": "facade/ignition-contracts", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/facade/ignition-contracts.git", - "reference": "aeab1ce8b68b188a43e81758e750151ad7da796b" + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/aeab1ce8b68b188a43e81758e750151ad7da796b", - "reference": "aeab1ce8b68b188a43e81758e750151ad7da796b", + "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.3|^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "phpunit/phpunit": "^7.5|^8.0", - "vimeo/psalm": "^3.12" + "friendsofphp/php-cs-fixer": "^v2.15.8", + "phpunit/phpunit": "^9.3.11", + "vimeo/psalm": "^3.17.1" }, "type": "library", "autoload": { @@ -6076,20 +6055,20 @@ "flare", "ignition" ], - "time": "2020-07-14T10:10:28+00:00" + "time": "2020-10-16T08:27:54+00:00" }, { "name": "filp/whoops", - "version": "2.9.0", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "2ec31f3adc54c71a59c5e3c2143d7a0e2f8899f8" + "reference": "307fb34a5ab697461ec4c9db865b20ff2fd40771" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/2ec31f3adc54c71a59c5e3c2143d7a0e2f8899f8", - "reference": "2ec31f3adc54c71a59c5e3c2143d7a0e2f8899f8", + "url": "https://api.github.com/repos/filp/whoops/zipball/307fb34a5ab697461ec4c9db865b20ff2fd40771", + "reference": "307fb34a5ab697461ec4c9db865b20ff2fd40771", "shasum": "" }, "require": { @@ -6137,20 +6116,20 @@ "throwable", "whoops" ], - "time": "2020-10-20T12:00:00+00:00" + "time": "2020-11-01T12:00:00+00:00" }, { "name": "fzaninotto/faker", - "version": "v1.9.1", + "version": "v1.9.2", "source": { "type": "git", "url": "https://github.com/fzaninotto/Faker.git", - "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f" + "reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/fc10d778e4b84d5bd315dad194661e091d307c6f", - "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/848d8125239d7dbf8ab25cb7f054f1a630e68c2e", + "reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e", "shasum": "" }, "require": { @@ -6188,7 +6167,7 @@ "fixtures" ], "abandoned": true, - "time": "2019-12-12T13:22:17+00:00" + "time": "2020-12-11T09:56:16+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -6305,30 +6284,33 @@ }, { "name": "mockery/mockery", - "version": "1.3.3", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "60fa2f67f6e4d3634bb4a45ff3171fa52215800d" + "reference": "20cab678faed06fac225193be281ea0fddb43b93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/60fa2f67f6e4d3634bb4a45ff3171fa52215800d", - "reference": "60fa2f67f6e4d3634bb4a45ff3171fa52215800d", + "url": "https://api.github.com/repos/mockery/mockery/zipball/20cab678faed06fac225193be281ea0fddb43b93", + "reference": "20cab678faed06fac225193be281ea0fddb43b93", "shasum": "" }, "require": { "hamcrest/hamcrest-php": "^2.0.1", "lib-pcre": ">=7.0", - "php": ">=5.6.0" + "php": "^7.3 || ^8.0" + }, + "conflict": { + "phpunit/phpunit": "<8.0" }, "require-dev": { - "phpunit/phpunit": "^5.7.10|^6.5|^7.5|^8.5|^9.3" + "phpunit/phpunit": "^8.5 || ^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { @@ -6366,7 +6348,7 @@ "test double", "testing" ], - "time": "2020-08-11T18:10:21+00:00" + "time": "2020-08-11T18:10:13+00:00" }, { "name": "myclabs/deep-copy", @@ -6657,16 +6639,16 @@ }, { "name": "phar-io/version", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae" + "reference": "e4782611070e50613683d2b9a57730e9a3ba5451" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/726c026815142e4f8677b7cb7f2249c9ffb7ecae", - "reference": "726c026815142e4f8677b7cb7f2249c9ffb7ecae", + "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451", + "reference": "e4782611070e50613683d2b9a57730e9a3ba5451", "shasum": "" }, "require": { @@ -6700,7 +6682,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2020-11-30T09:21:21+00:00" + "time": "2020-12-13T23:18:30+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -6850,16 +6832,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.12.1", + "version": "1.12.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d" + "reference": "245710e971a030f42e08f4912863805570f23d39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/8ce87516be71aae9b956f81906aaf0338e0d8a2d", - "reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", + "reference": "245710e971a030f42e08f4912863805570f23d39", "shasum": "" }, "require": { @@ -6871,7 +6853,7 @@ }, "require-dev": { "phpspec/phpspec": "^6.0", - "phpunit/phpunit": "^8.0 || ^9.0 <9.3" + "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { @@ -6909,20 +6891,20 @@ "spy", "stub" ], - "time": "2020-09-29T09:10:42+00:00" + "time": "2020-12-19T10:15:11+00:00" }, { "name": "phpstan/phpstan", - "version": "0.12.59", + "version": "0.12.63", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "cf4107257c8ca2ad967efdd6a00f12b21acbb779" + "reference": "c97ec4754bd53099a06c24847bd2870b99966b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cf4107257c8ca2ad967efdd6a00f12b21acbb779", - "reference": "cf4107257c8ca2ad967efdd6a00f12b21acbb779", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c97ec4754bd53099a06c24847bd2870b99966b6a", + "reference": "c97ec4754bd53099a06c24847bd2870b99966b6a", "shasum": "" }, "require": { @@ -6965,20 +6947,20 @@ "type": "tidelift" } ], - "time": "2020-12-07T14:46:03+00:00" + "time": "2020-12-15T16:37:16+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "7.0.13", + "version": "7.0.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ad0dcd7b184e76f7198a1fe07685bfbec3ae911a" + "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ad0dcd7b184e76f7198a1fe07685bfbec3ae911a", - "reference": "ad0dcd7b184e76f7198a1fe07685bfbec3ae911a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bb7c9a210c72e4709cdde67f8b7362f672f2225c", + "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c", "shasum": "" }, "require": { @@ -6987,7 +6969,7 @@ "php": ">=7.2", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.1.1", + "phpunit/php-token-stream": "^3.1.1 || ^4.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", @@ -7034,7 +7016,7 @@ "type": "github" } ], - "time": "2020-11-30T08:35:22+00:00" + "time": "2020-12-02T13:39:03+00:00" }, { "name": "phpunit/php-file-iterator", @@ -7190,29 +7172,29 @@ }, { "name": "phpunit/php-token-stream", - "version": "3.1.2", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "472b687829041c24b25f475e14c2f38a09edf1c2" + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/472b687829041c24b25f475e14c2f38a09edf1c2", - "reference": "472b687829041c24b25f475e14c2f38a09edf1c2", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=7.1" + "php": "^7.3 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -7242,7 +7224,7 @@ } ], "abandoned": true, - "time": "2020-11-30T08:38:46+00:00" + "time": "2020-08-04T08:28:15+00:00" }, { "name": "phpunit/phpunit", @@ -7383,81 +7365,6 @@ ], "time": "2020-05-12T15:16:56+00:00" }, - { - "name": "scrivo/highlight.php", - "version": "v9.18.1.2", - "source": { - "type": "git", - "url": "https://github.com/scrivo/highlight.php.git", - "reference": "efb6e445494a9458aa59b0af5edfa4bdcc6809d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/efb6e445494a9458aa59b0af5edfa4bdcc6809d9", - "reference": "efb6e445494a9458aa59b0af5edfa4bdcc6809d9", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "php": ">=5.4" - }, - "require-dev": { - "phpunit/phpunit": "^4.8|^5.7", - "sabberworm/php-css-parser": "^8.3", - "symfony/finder": "^2.8|^3.4", - "symfony/var-dumper": "^2.8|^3.4" - }, - "suggest": { - "ext-dom": "Needed to make use of the features in the utilities namespace" - }, - "type": "library", - "autoload": { - "psr-0": { - "Highlight\\": "", - "HighlightUtilities\\": "" - }, - "files": [ - "HighlightUtilities/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Geert Bergman", - "homepage": "http://www.scrivo.org/", - "role": "Project Author" - }, - { - "name": "Vladimir Jimenez", - "homepage": "https://allejo.io", - "role": "Maintainer" - }, - { - "name": "Martin Folkers", - "homepage": "https://twobrain.io", - "role": "Contributor" - } - ], - "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", - "keywords": [ - "code", - "highlight", - "highlight.js", - "highlight.php", - "syntax" - ], - "funding": [ - { - "url": "https://github.com/allejo", - "type": "github" - } - ], - "time": "2020-08-27T03:24:44+00:00" - }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.2", @@ -8244,16 +8151,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.2.0", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "bb92ba7f38b037e531908590a858a04d85c0e238" + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/bb92ba7f38b037e531908590a858a04d85c0e238", - "reference": "bb92ba7f38b037e531908590a858a04d85c0e238", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/fa8f8cab6b65e2d99a118e082935344c5ba8c60d", + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d", "shasum": "" }, "require": { @@ -8299,7 +8206,7 @@ "type": "tidelift" } ], - "time": "2020-11-12T09:58:18+00:00" + "time": "2020-11-30T17:05:38+00:00" }, { "name": "theseer/tokenizer", diff --git a/conf/site/config/speedtest.php b/conf/site/config/speedtest.php index 695ff179..283b6c74 100644 --- a/conf/site/config/speedtest.php +++ b/conf/site/config/speedtest.php @@ -7,7 +7,7 @@ return [ |-------------------------------------------------------------------------- */ - 'version' => '1.10.1', + 'version' => '1.10.3', /* |-------------------------------------------------------------------------- diff --git a/conf/site/database/migrations/2020_12_19_211232_add_schedule_enabled_setting.php b/conf/site/database/migrations/2020_12_19_211232_add_schedule_enabled_setting.php new file mode 100644 index 00000000..db78f3b7 --- /dev/null +++ b/conf/site/database/migrations/2020_12_19_211232_add_schedule_enabled_setting.php @@ -0,0 +1,38 @@ + 'schedule_enabled', + 'value' => true, + 'description' => 'Enable/disable the schedule worker' + ]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Setting::whereIn('name', [ + 'schedule_enabled', + ])->delete(); + } +} diff --git a/conf/site/database/migrations/2020_12_19_234248_add_app_name_setting.php b/conf/site/database/migrations/2020_12_19_234248_add_app_name_setting.php new file mode 100644 index 00000000..e640c617 --- /dev/null +++ b/conf/site/database/migrations/2020_12_19_234248_add_app_name_setting.php @@ -0,0 +1,38 @@ + 'app_name', + 'value' => 'Speedtest Tracker', + 'description' => 'Set a custom app name' + ]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Setting::whereIn('name', [ + 'app_name', + ])->delete(); + } +} diff --git a/conf/site/database/migrations/2020_12_20_001345_add_custom_healthchecks_setting.php b/conf/site/database/migrations/2020_12_20_001345_add_custom_healthchecks_setting.php new file mode 100644 index 00000000..bd552992 --- /dev/null +++ b/conf/site/database/migrations/2020_12_20_001345_add_custom_healthchecks_setting.php @@ -0,0 +1,38 @@ + 'healthchecks_server_url', + 'value' => 'https://hc-ping.com/', + 'description' => 'The URL of the healthchecks.io server. Change this to use a self-hosted server.' + ]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Setting::whereIn('name', [ + 'healthchecks_server_url', + ])->delete(); + } +} diff --git a/conf/site/package-lock.json b/conf/site/package-lock.json index 6f3fee85..fafb2d6c 100644 --- a/conf/site/package-lock.json +++ b/conf/site/package-lock.json @@ -3243,20 +3243,13 @@ "integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==" }, "csv-file-validator": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/csv-file-validator/-/csv-file-validator-1.8.0.tgz", - "integrity": "sha512-+/wdJxbe9zk1KJv7GC5aCVOVrg10W7xWIypILuQsJ3ocegF/YueTarb8Dqg1snEfkPmh2aCjbhVXnu1gM3RRIA==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/csv-file-validator/-/csv-file-validator-1.10.1.tgz", + "integrity": "sha512-jYFl3a/ptlJIEzLM28BlApn+JthmCz/3f/WLdt2fdCmMGb+eiP9QkulFhmepzFFrMi2Iel6m4OPXrHWpOFCHqg==", "requires": { - "famulus": "2.1.2", - "lodash": "4.17.15", - "papaparse": "^5.2.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - } + "famulus": "^2.2.0", + "lodash": "^4.17.20", + "papaparse": "^5.3.0" } }, "cyclist": { @@ -4184,11 +4177,11 @@ } }, "famulus": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/famulus/-/famulus-2.1.2.tgz", - "integrity": "sha512-UjfF9lOEP6IFLC/DTwUe5KbCYINbuYYJS+mivlnWyK8yqt/9WYHrJ4RihZ0pa9HVxQObu8IWroJOyyt8dXCVkw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/famulus/-/famulus-2.2.2.tgz", + "integrity": "sha512-tobqs8uC0OomrMN/cX7aUUj3OSJn5y2GCfcTleCrtIfjxUkl6kJFLovnyEWfD6M+cQ1ZXhE5BaTJzMoDibbodA==", "requires": { - "lodash": "^4.17.15" + "lodash": "^4.17.20" } }, "fast-deep-equal": { @@ -7078,9 +7071,9 @@ "dev": true }, "papaparse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.2.0.tgz", - "integrity": "sha512-ylq1wgUSnagU+MKQtNeVqrPhZuMYBvOSL00DHycFTCxownF95gpLAk1HiHdUW77N8yxRq1qHXLdlIPyBSG9NSA==" + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.0.tgz", + "integrity": "sha512-Lb7jN/4bTpiuGPrYy4tkKoUS8sTki8zacB5ke1p5zolhcSE4TlWgrlsxjrDTbG/dFVh07ck7X36hUf/b5V68pg==" }, "parallel-transform": { "version": "1.2.0", diff --git a/conf/site/package.json b/conf/site/package.json index 850da20e..74e858c5 100644 --- a/conf/site/package.json +++ b/conf/site/package.json @@ -27,7 +27,7 @@ "dependencies": { "@babel/plugin-proposal-class-properties": "^7.12.1", "chart.js": "^2.9.4", - "csv-file-validator": "^1.8.0", + "csv-file-validator": "^1.10.1", "js-cookie": "^2.2.1", "react-bootstrap": "^1.4.0", "react-chartjs-2": "^2.11.1", diff --git a/conf/site/resources/js/components/Authentication/Authentication.js b/conf/site/resources/js/components/Authentication/Authentication.js index b038ea28..d0dd92ab 100644 --- a/conf/site/resources/js/components/Authentication/Authentication.js +++ b/conf/site/resources/js/components/Authentication/Authentication.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; -import { Container, Row, Col, Collapse, Button, Modal } from 'react-bootstrap'; +import { Row, Col} from 'react-bootstrap'; import SessionsTable from './SessionsTable'; import ResetPassword from './ResetPassword'; @@ -44,34 +44,18 @@ export default class Authentication extends Component { if( (window.config.auth == true && window.authenticated == true)) { return ( - +
- -
-

Authentication

- {(showCollapse) ? - - : - - } -
+ +
- -
- - - - - - - - - - -
-
- + + + + + +
); } else { return ( diff --git a/conf/site/resources/js/components/Graphics/HistoryGraph.js b/conf/site/resources/js/components/Graphics/HistoryGraph.js index c0f227aa..4eb4e49f 100644 --- a/conf/site/resources/js/components/Graphics/HistoryGraph.js +++ b/conf/site/resources/js/components/Graphics/HistoryGraph.js @@ -37,6 +37,10 @@ export default class HistoryGraph extends Component { }); } + componentWillUnmount() { + clearInterval(this.state.interval); + } + getDLULPing = (days) => { var url = 'api/speedtest/time/' + days; diff --git a/conf/site/resources/js/components/Graphics/LatestResults.js b/conf/site/resources/js/components/Graphics/LatestResults.js index adc406bf..dd1bd5dc 100644 --- a/conf/site/resources/js/components/Graphics/LatestResults.js +++ b/conf/site/resources/js/components/Graphics/LatestResults.js @@ -26,6 +26,10 @@ export default class LatestResults extends Component { }); } + componentWillUnmount() { + clearInterval(this.state.interval); + } + getData = () => { var url = 'api/speedtest/latest'; diff --git a/conf/site/resources/js/components/Graphics/TestsTable.js b/conf/site/resources/js/components/Graphics/TestsTable.js index 43a98bb7..e330b0b9 100644 --- a/conf/site/resources/js/components/Graphics/TestsTable.js +++ b/conf/site/resources/js/components/Graphics/TestsTable.js @@ -26,6 +26,10 @@ export default class TestsTable extends Component { }); } + componentWillUnmount() { + clearInterval(this.state.interval); + } + getData = (page = this.state.page, refresh = true) => { var url = 'api/speedtest/?page=' + page; @@ -83,59 +87,48 @@ export default class TestsTable extends Component { if(data.length > 0) { return ( - - - -
-

All tests

- {(show) ? - - : - - } -
- {(show) && -
+
+ + + +
+

All tests

Auto refresh: {(refresh) ? 'On' : 'Off'}
- } - -
- -
+ + + + + + + + + + + + + + + + + {data.map((e,i) => { + return ( + + ); + })} + +
IDTimeDownload (Mbit/s)Upload (Mbit/s)Ping (ms)More
+ +
+ {page < lastPage && - - - - - - - - - - - - - - {data.map((e,i) => { - return ( - - ); - })} - -
IDTimeDownload (Mbit/s)Upload (Mbit/s)Ping (ms)More
+ +
- {page < lastPage && - - - - - - } -
-
-
+ } + +
); } else { return ( diff --git a/conf/site/resources/js/components/Home/HomePage.js b/conf/site/resources/js/components/Home/HomePage.js index c6b2048f..9c1a20b2 100644 --- a/conf/site/resources/js/components/Home/HomePage.js +++ b/conf/site/resources/js/components/Home/HomePage.js @@ -5,25 +5,22 @@ import LatestResults from '../Graphics/LatestResults'; import Footer from './Footer'; import DataRow from '../Data/DataRow'; import TestsTable from '../Graphics/TestsTable'; -import Settings from '../Settings/Settings'; import Login from '../Login'; import Authentication from '../Authentication/Authentication'; +import Navbar from '../Navbar'; export default class HomePage extends Component { render() { return (
+
{(window.config.auth == true && window.authenticated == false) && } - - - -
diff --git a/conf/site/resources/js/components/Login.js b/conf/site/resources/js/components/Login.js index 180ba766..97c60854 100644 --- a/conf/site/resources/js/components/Login.js +++ b/conf/site/resources/js/components/Login.js @@ -39,6 +39,9 @@ export default class Login extends Component { Cookies.set('auth', token, { expires: expires }) window.location.reload(true); }) + .catch((err) => { + toast.error('Something went wrong logging in.'); + }) } toggleShow = () => { diff --git a/conf/site/resources/js/components/Navbar.js b/conf/site/resources/js/components/Navbar.js index f84535bf..7bc2ce4b 100644 --- a/conf/site/resources/js/components/Navbar.js +++ b/conf/site/resources/js/components/Navbar.js @@ -1,19 +1,77 @@ import React, { Component } from 'react'; +import {Nav, Navbar as BootstrapNavbar, NavLink as BootstrapNavLink} from 'react-bootstrap'; import ReactDOM from 'react-dom'; +import { Link, NavLink } from 'react-router-dom'; export default class Navbar extends Component { constructor(props) { super(props) this.state = { - + brand: { + name: window.config.name, + url: window.config.base + }, } } + generatePagesArray() { + var pages = [ + { + name: 'Home', + url: window.config.base, + authRequired: false + }, + { + name: 'All Tests', + url: window.config.base + 'speedtests', + authRequired: false + }, + { + name: 'Settings', + url: window.config.base + 'settings', + authRequired: true + }, + ] + + return pages; + } + + generateLinks = () => { + var pages = this.generatePagesArray(); + + return pages.map(page => { + if( + page.authRequired === false || + ( + page.authRequired === true && + window.config.auth && + window.authenticated + ) || + ( + page.authRequired === true && + window.config.auth === false + ) + ) { + return {page.name}; + } + }); + } + render() { + var brand = this.state.brand; + var pages = this.generateLinks(); + return ( -
-
+ + {brand.name} + + + + + ); } } diff --git a/conf/site/resources/js/components/Settings/Setting.js b/conf/site/resources/js/components/Settings/Setting.js deleted file mode 100644 index 1db0fa5d..00000000 --- a/conf/site/resources/js/components/Settings/Setting.js +++ /dev/null @@ -1,77 +0,0 @@ -import React, { Component } from 'react'; -import ReactDOM from 'react-dom'; -import { Card, Form, Button } from 'react-bootstrap'; -import Axios from 'axios'; -import { toast } from 'react-toastify'; - -export default class Setting extends Component { - constructor(props) { - super(props) - - this.state = { - name: this.props.name, - value: this.props.value, - description: this.props.description, - } - } - - ucfirst(string) { - return string.charAt(0).toUpperCase() + string.slice(1); - } - - update = () => { - var url = 'api/settings?token=' + window.token; - var data = { - name: this.state.name, - value: this.state.value - }; - - Axios.post(url, data) - .then((resp) => { - toast.success(this.ucfirst(this.state.name) + ' updated'); - }) - .catch((err) => { - if(err.response.status == 422) { - var errors = err.response.data.error; - for(var key in errors) { - var error = errors[key]; - toast.error(error[0]) - } - } else { - toast.error('Something went wrong') - } - }) - } - - updateValue = (e) => { - this.setState({ - value: e.target.value - }); - } - - render() { - var name = this.state.name; - var value = this.state.value; - var description = this.state.description; - - return ( - - -
-

{this.ucfirst(name)}

-
- - {this.ucfirst(name)} - - - -
- - - ); - } -} - -if (document.getElementById('Setting')) { - ReactDOM.render(, document.getElementById('Setting')); -} diff --git a/conf/site/resources/js/components/Settings/SettingWithModal.js b/conf/site/resources/js/components/Settings/SettingWithModal.js deleted file mode 100644 index 43d66d51..00000000 --- a/conf/site/resources/js/components/Settings/SettingWithModal.js +++ /dev/null @@ -1,296 +0,0 @@ -import React, { Component } from 'react'; -import ReactDOM from 'react-dom'; -import { Card, Form, Button, Modal, Row, Col } from 'react-bootstrap'; -import Axios from 'axios'; -import { toast } from 'react-toastify'; -import SettingsModalCard from '../Settings/SettingsModalCard'; - -export default class SettingWithModal extends Component { - constructor(props) { - super(props) - - this.state = { - title: this.props.title, - description: this.props.description, - settings: this.props.settings, - show: false, - autoClose: this.props.autoClose - } - } - - ucfirst(string) { - return string.charAt(0).toUpperCase() + string.slice(1); - } - - update = () => { - var url = 'api/settings/bulk?token=' + window.token; - var data = []; - var settings = this.state.settings; - - settings.forEach(e => { - if(e.type !== 'button-get') { - var res = { - name: e.obj.name, - value: e.obj.value - }; - data.push(res); - } - }); - - data = { - data: data - }; - - Axios.post(url, data) - .then((resp) => { - toast.success(this.state.title + ' updated'); - if(this.state.autoClose) { - this.toggleShow(); - } - Axios.get('api/settings/config') - .then((resp) => { - window.config = resp.data; - }) - }) - .catch((err) => { - if(err.response.status == 422) { - toast.error('Your input was invalid'); - } else { - toast.error('Something went wrong') - } - }) - } - - updateValue = (e) => { - var name = e.target.id; - if(e.target.type == 'checkbox') { - var val = e.target.checked; - } else { - var val = e.target.value; - } - var settings = this.state.settings; - var i = 0; - settings.forEach(ele => { - if(ele.obj.name == name) { - ele.obj.value = val; - } - settings[i] = ele; - i++; - }); - this.setState({ - settings: settings - }); - } - - toggleShow = () => { - var show = this.state.show; - if(show) { - this.setState({ - show: false - }); - } else { - this.setState({ - show: true - }); - } - } - - render() { - var title = this.state.title; - var description = this.state.description; - var show = this.state.show; - var settings = this.state.settings; - - return ( - <> - - - - {title} - - - {settings.map((e,i) => { - var name = e.obj.name.split('_'); - name[0] = this.ucfirst(name[0]); - name = name.join(' '); - - if(e.obj.description == null || e.obj.description == '') { - var sm = { span: 12 }; - var md = { span: 12 }; - } else { - var sm = { span: 12 }; - var md = { span: 6 }; - } - - var readonly = false; - if(window.config.editable[e.obj.name] == false) { - readonly = true; - } - - if(e.type == 'info') { - return ( - - -

{e.obj.content}

- -
- ) - } else if(e.type == 'checkbox') { - return ( - - - - {readonly ? - <> - - This setting is defined as an env variable and is not editable. - - : - - } - - - {e.description == null && - -

{e.obj.description}

- - } -
- ); - } else if(e.type == 'number') { - return ( - - - - {name} - {readonly ? - <> - - This setting is defined as an env variable and is not editable. - - : - - } - - - {e.description == null && - -

{e.obj.description}

- - } -
- ); - } else if(e.type == 'text') { - return ( - - - - {name} - {readonly ? - <> - - This setting is defined as an env variable and is not editable. - - : - - } - - - {e.description == null && - -

- - } -
- ); - } else if(e.type == 'select') { - return ( - - - - {name} - {readonly ? - <> - - {e.options.map((e,i) => { - return ( - - ) - })} - - This setting is defined as an env variable and is not editable. - - : - - {e.options.map((e,i) => { - return ( - - ) - })} - - } - - - {e.description == null && - -

{e.obj.description}

- - } -
- ) - } else if(e.type == 'button-get') { - return ( - - -

{name}

- - - {e.description == null && - -

{e.obj.description}

- - } -
- ) - } else if(e.type == 'group') { - return ( -
- - -

{name}

- - {e.description == null && - -

{e.obj.description}

- - } -
- - - {e.children.map((ee,ii) => { - if(ee.type == 'button-get') { - return ( - - ) - } - })} - - -
- ) - } - })} - -
-
- - ); - } -} - -if (document.getElementById('Setting')) { - ReactDOM.render(, document.getElementById('Setting')); -} diff --git a/conf/site/resources/js/components/Settings/Settings.js b/conf/site/resources/js/components/Settings/Settings.js deleted file mode 100644 index 14699eb3..00000000 --- a/conf/site/resources/js/components/Settings/Settings.js +++ /dev/null @@ -1,323 +0,0 @@ -import React, { Component } from 'react'; -import ReactDOM from 'react-dom'; -import { Modal, Container, Row, Col, Collapse } from 'react-bootstrap'; -import Loader from '../Loader'; -import Axios from 'axios'; -import Setting from './Setting'; -import SettingWithModal from './SettingWithModal'; -import ResetSettings from './ResetSettings'; - -export default class Settings extends Component { - constructor(props) { - super(props) - - this.state = { - show: false, - loading: true, - data: [], - } - } - - componentDidMount = () => { - if( (window.config.auth == true && window.authenticated == true) || window.config.auth == false) { - this.getData(); - } - } - - toggleShow = () => { - if(this.state.show) { - var show = false; - } else { - var show = true; - } - - this.setState({ - show: show - }); - } - - getData = () => { - var url = 'api/settings/?token=' + window.token; - - Axios.get(url) - .then((resp) => { - this.setState({ - loading: false, - data: resp.data - }); - }) - .catch((err) => { - if(err.response) { - - } - }) - } - - buildSettingsCards = () => { - var e = this.state.data; - - return ( - - - - - - - - - - - - - - - - - - ) - } - - render() { - var show = this.state.show; - var loading = this.state.loading; - var data = this.state.data; - if(!loading) { - var cards = this.buildSettingsCards(); - } - if( (window.config.auth == true && window.authenticated == true) || window.config.auth == false) { - return ( -
- - - -
-

Settings

- {(show) ? - - : - - } -
- -
- -
- - - {loading ? - - : - cards - } - - -
-
-
- -
- ); - } else { - return( - <> - ) - } - } -} - -if (document.getElementById('Settings')) { - ReactDOM.render(, document.getElementById('Settings')); -} diff --git a/conf/site/resources/js/components/Settings/SettingsIndex.js b/conf/site/resources/js/components/Settings/SettingsIndex.js new file mode 100644 index 00000000..cf064aad --- /dev/null +++ b/conf/site/resources/js/components/Settings/SettingsIndex.js @@ -0,0 +1,282 @@ +import Axios from 'axios'; +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import Footer from '../Home/Footer'; +import Loader from '../Loader'; +import Navbar from '../Navbar'; +import SettingsTabs from './SettingsTabs'; + +export default class SettingsIndex extends Component { + constructor(props) { + super(props) + + this.state = { + data: null, + loading: true, + } + } + + getData = () => { + var url = 'api/settings/?token=' + window.token; + + Axios.get(url) + .then((resp) => { + this.setState({ + data: this.sortSettings(resp.data), + loading: false, + }); + }) + .catch((err) => { + // + }) + } + + sortSettings = (data) => { + return { + General: [ + { + obj: data.app_name, + type: 'text', + }, + { + obj: data.schedule_enabled, + type: 'text', + }, + { + obj: data.schedule, + type: 'text', + }, + { + obj: data.server, + type: 'text', + }, + { + obj: data.show_average, + type: 'checkbox', + }, + { + obj: data.show_max, + type: 'checkbox', + }, + { + obj: data.show_min, + type: 'checkbox', + } + ], + Graphs: [ + { + obj: data.download_upload_graph_enabled, + type: 'checkbox', + hideDescription: true + }, + { + obj: data.download_upload_graph_width, + type: 'select', + options: [ + { + name: 'Full-width', + 'value': 12 + }, + { + name: 'Half-width', + 'value': 6 + } + ], + }, + { + obj: data.ping_graph_enabled, + type: 'checkbox', + hideDescription: true + }, + { + obj: data.ping_graph_width, + type: 'select', + options: [ + { + name: 'Full-width', + 'value': 12 + }, + { + name: 'Half-width', + 'value': 6 + } + ], + }, + { + obj: data.failure_graph_enabled, + type: 'checkbox', + hideDescription: true + }, + { + obj: data.failure_graph_width, + type: 'select', + options: [ + { + name: 'Full-width', + 'value': 12 + }, + { + name: 'Half-width', + 'value': 6 + } + ], + }, + { + obj: data.show_failed_tests_on_graph, + type: 'checkbox', + }, + ], + Notifications: [ + { + obj: data.slack_webhook, + type: 'text' + }, + { + obj: data.telegram_bot_token, + type: 'text' + }, + { + obj: data.telegram_chat_id, + type: 'text' + }, + { + type: 'btn-get', + url: 'api/settings/test-notification?token=' + window.token, + btnType: 'primary', + obj: { + id: (Math.floor(Math.random() * 10000) + 1), + name: 'Test notifications', + description: 'After saving your updated notification settings, use this to check your settings are correct.' + } + }, + { + obj: data.speedtest_notifications, + type: 'checkbox' + }, + { + obj: data.speedtest_overview_notification, + type: 'checkbox' + }, + { + obj: data.speedtest_overview_time, + type: 'number', + min: 0, + max: 23, + }, + // Add handling for title stuff + { + obj: data.threshold_alert_percentage, + type: 'number', + min: 0, + max: 100 + }, + { + obj: data.threshold_alert_absolute_notifications, + type: 'checkbox' + }, + { + obj: data.threshold_alert_absolute_download, + type: 'number' + }, + { + obj: data.threshold_alert_absolute_upload, + type: 'number' + }, + { + obj: data.threshold_alert_absolute_ping, + type: 'number' + }, + ], + healthchecks: [ + { + obj: data.healthchecks_enabled, + type: 'checkbox' + }, + { + obj: data.healthchecks_server_url, + type: 'text' + }, + { + obj: data.healthchecks_uuid, + type: 'text' + }, + { + obj: { + id: (Math.floor(Math.random() * 10000) + 1), + name: "Test healthchecks.io integration", + description: "" + }, + }, + { + obj: { + id: (Math.floor(Math.random() * 10000) + 1), + name: "Start", + description: "" + }, + type: 'btn-get', + url: 'api/settings/test-healthchecks/start?token=' + window.token, + btnType: 'outline-success', + inline: true, + earlyReturn: true, + classes: 'mr-2' + }, + { + obj: { + id: (Math.floor(Math.random() * 10000) + 1), + name: "Success", + description: "" + }, + type: 'btn-get', + url: 'api/settings/test-healthchecks/success?token=' + window.token, + btnType: 'success', + text: 'Success', + inline: true, + earlyReturn: true, + classes: 'mr-2' + }, + { + obj: { + id: (Math.floor(Math.random() * 10000) + 1), + name: "Fail", + description: "" + }, + type: 'btn-get', + url: 'api/settings/test-healthchecks/fail?token=' + window.token, + btnType: 'danger', + text: 'Fail', + inline: true, + earlyReturn: true, + classes: 'mr-2' + }, + + ] + }; + } + + componentDidMount() { + this.getData(); + } + + render() { + var data = this.state.data; + var loading = this.state.loading; + + return ( +
+ +
+ {loading ? + + : + + } +
+
+
+ ); + } +} + +if (document.getElementById('settingsIndex')) { + ReactDOM.render(, document.getElementById('settingsIndex')); +} diff --git a/conf/site/resources/js/components/Settings/SettingsInput.js b/conf/site/resources/js/components/Settings/SettingsInput.js new file mode 100644 index 00000000..464edd3c --- /dev/null +++ b/conf/site/resources/js/components/Settings/SettingsInput.js @@ -0,0 +1,185 @@ +import React, { Component } from 'react'; +import { Form } from 'react-bootstrap'; +import ReactDOM from 'react-dom'; + +export default class SettingsInput extends Component { + constructor(props) { + super(props) + + this.state = { + type: this.props.type, + name: this.props.name, + displayName: (this.props.name) ? this.formatName(this.props.name) : '', + value: (this.props.value) ? this.props.value : '', + classes: this.props.classes, + id: this.props.id, + label: (this.props.label) ? this.props.label : false, + readonly: true, + description: (this.props.description) ? this.props.description : false, + options: this.props.options ? this.props.options : [], + hideDescription: this.props.hideDescription ? true : false, + min: this.props.min ? this.props.min : null, + max: this.props.max ? this.props.max : null, + url: this.props.url, + inline: this.props.inline ? 'd-inline-block' : 'd-block', + btnType: this.props.btnType, + earlyReturn: this.props.earlyReturn ? true : false, + } + } + + componentDidMount() { + this.setState({ + readonly: this.isReadOnly() + }); + } + + formatName(name) { + name = name.split('_').join(' '); + + return name.charAt(0).toUpperCase() + name.slice(1); + } + + handleInput = (evt) => { + var val = evt.target.value; + + if(this.state.type === 'checkbox') { + val = evt.target.checked; + } + + this.props.handler( + this.state.name, + val + ); + + this.setState({ + value: val + }); + } + + isReadOnly = () => { + if(window.config.editable[this.state.name] == false) { + return true; + } + + return false; + } + + generateNumberInput(disabled) { + return + } + + generateSelectInput(disabled) { + return ( + + {this.state.options.map((option,i) => { + return + })} + + ); + } + + generateCheckboxInput(disabled) { + return + } + + generateTextInput(disabled) { + return + } + + generateButtonGetInput() { + var url = this.state.url; + + return ( + + ); + } + + generateInput = () => { + var disabled = (this.state.readonly) ? true : false; + var input = null; + + if(this.state.type === 'number') { + input = this.generateNumberInput(disabled); + } + + if(this.state.type === 'select') { + input = this.generateSelectInput(disabled); + } + + if(this.state.type === 'checkbox') { + input = this.generateCheckboxInput(disabled); + } + + if(this.state.type === 'text') { + input = this.generateTextInput(disabled); + } + + if(this.state.type === 'btn-get') { + input = this.generateButtonGetInput(); + } + + if(this.state.earlyReturn) { + return input; + } + + return ( + + {this.state.label && + {this.formatName(this.state.name)} + } + + {input} + + {this.state.description && !this.state.hideDescription && +

+ } + + {this.state.readonly && + This setting is defined as an env variable and is not editable. + } +
+ ); + } + + render() { + var input = this.generateInput(); + + return input; + } +} + +if (document.getElementById('SettingsInput')) { + ReactDOM.render(, document.getElementById('SettingsInput')); +} diff --git a/conf/site/resources/js/components/Settings/SettingsModalCard.js b/conf/site/resources/js/components/Settings/SettingsModalCard.js deleted file mode 100644 index 76acf663..00000000 --- a/conf/site/resources/js/components/Settings/SettingsModalCard.js +++ /dev/null @@ -1,37 +0,0 @@ -import React, { Component } from 'react'; -import ReactDOM from 'react-dom'; -import { Card, Button } from 'react-bootstrap'; - -export default class SettingsModalCard extends Component { - constructor(props) { - super(props) - - this.state = { - title: this.props.title, - description: this.props.description, - toggleShow: this.props.toggleShow, - } - } - - render() { - var title = this.state.title; - var description = this.state.description; - var toggleShow = this.state.toggleShow; - - return ( - - -
-

{title}

-

{description}

- -
-
-
- ); - } -} - -if (document.getElementById('SettingModalCard')) { - ReactDOM.render(, document.getElementById('SettingModalCard')); -} diff --git a/conf/site/resources/js/components/Settings/SettingsTabs.js b/conf/site/resources/js/components/Settings/SettingsTabs.js new file mode 100644 index 00000000..5b3ea97a --- /dev/null +++ b/conf/site/resources/js/components/Settings/SettingsTabs.js @@ -0,0 +1,177 @@ +import Axios from 'axios'; +import React, { Component } from 'react'; +import { Nav, Tab, Tabs } from 'react-bootstrap'; +import ReactDOM from 'react-dom'; +import { toast } from 'react-toastify'; +import SettingsInput from './SettingsInput'; +import ResetSettings from './tabs/ResetSettings'; +import BackupSettings from './tabs/BackupSettings'; +import GeneralSettings from './tabs/GeneralSettings'; +import GraphsSettings from './tabs/GraphsSettings'; +import HealthchecksSettings from './tabs/HealthchecksSettings'; +import NotificationsSettings from './tabs/NotificationsSettings'; +import Authentication from '../Authentication/Authentication'; + +export default class SettingsTabs extends Component { + constructor(props) { + super(props) + + this.state = { + tab: "General", + data: this.props.data + } + } + + generateTabs = () => { + var tabs = [ + 'General', + 'Graphs', + 'Notifications', + 'healthchecks.io', + 'Reset', + 'Backup/Restore', + ]; + + if(window.config.auth) { + tabs.push('Authentication'); + } + + return tabs.map((tab) => { + return + }); + } + + switchTab = (tab) => { + this.setState({ + tab: tab + }); + } + + save = (settings, name) => { + var url = 'api/settings/bulk?token=' + window.token; + var data = []; + + settings.forEach(e => { + if(e.type !== 'btn-get') { + var res = { + name: e.obj.name, + value: e.obj.value + }; + data.push(res); + } + }); + + data = { + data: data + }; + + Axios.post(url, data) + .then((resp) => { + toast.success(name + ' settings updated'); + Axios.get('api/settings/config') + .then((resp) => { + window.config = resp.data; + }) + }) + .catch((err) => { + if(err.response.status == 422) { + toast.error('Your input was invalid'); + } else { + toast.error('Something went wrong') + } + }) + } + + generateInputs = (settings, handler) => { + return settings.map((setting) => { + return + }) + } + + getTabContent = () => { + var data = this.state.data; + + switch(this.state.tab) { + case 'General': + return + case 'Graphs': + return + case 'Notifications': + return + case 'healthchecks.io': + return + case 'Reset': + return + case 'Backup/Restore': + return + case 'Authentication': + return + } + } + + render() { + var tabs = this.generateTabs(); + var activeTab = this.state.tab; + var tabContent = this.getTabContent(); + + return ( +
+ { this.switchTab(tab) }} + activeKey={activeTab} + > + {tabs} + + +
+ {tabContent} +
+
+ ); + } +} + +if (document.getElementById('settingsTabs')) { + ReactDOM.render(, document.getElementById('settingsTabs')); +} diff --git a/conf/site/resources/js/components/Settings/tabs/BackupSettings.js b/conf/site/resources/js/components/Settings/tabs/BackupSettings.js new file mode 100644 index 00000000..db981313 --- /dev/null +++ b/conf/site/resources/js/components/Settings/tabs/BackupSettings.js @@ -0,0 +1,26 @@ +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import { Modal, Button, Tab } from 'react-bootstrap'; +import Axios from 'axios'; +import DataRow from '../../Data/DataRow'; + +export default class BackupSettings extends Component { + constructor(props) { + super(props) + + this.state = { + } + } + + render() { + return ( + + + + ); + } +} + +if (document.getElementById('BackupSettings')) { + ReactDOM.render(, document.getElementById('BackupSettings')); +} diff --git a/conf/site/resources/js/components/Settings/tabs/GeneralSettings.js b/conf/site/resources/js/components/Settings/tabs/GeneralSettings.js new file mode 100644 index 00000000..af5cf16b --- /dev/null +++ b/conf/site/resources/js/components/Settings/tabs/GeneralSettings.js @@ -0,0 +1,46 @@ +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import { Modal, Button, Tab } from 'react-bootstrap'; +import Axios from 'axios'; + +export default class GeneralSettings extends Component { + constructor(props) { + super(props) + + this.state = { + data: this.props.data + } + } + + inputHandler = (name, val) => { + var settings = this.state.data; + var i = 0; + settings.forEach(ele => { + if(ele.obj.name == name) { + ele.obj.value = val; + } + settings[i] = ele; + i++; + }); + this.setState({ + data: settings + }); + } + + render() { + var settings = this.props.generateInputs(this.state.data, this.inputHandler); + + return ( + + {settings} +
+ +
+
+ ); + } +} + +if (document.getElementById('GeneralSettings')) { + ReactDOM.render(, document.getElementById('GeneralSettings')); +} diff --git a/conf/site/resources/js/components/Settings/tabs/GraphsSettings.js b/conf/site/resources/js/components/Settings/tabs/GraphsSettings.js new file mode 100644 index 00000000..8c9a1a32 --- /dev/null +++ b/conf/site/resources/js/components/Settings/tabs/GraphsSettings.js @@ -0,0 +1,48 @@ +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import { Modal, Button, Tab } from 'react-bootstrap'; +import Axios from 'axios'; +import { toast } from 'react-toastify'; +import SettingsInput from '../SettingsInput'; + +export default class GraphsSettings extends Component { + constructor(props) { + super(props) + + this.state = { + data: this.props.data + } + } + + inputHandler = (name, val) => { + var settings = this.state.data; + var i = 0; + settings.forEach(ele => { + if(ele.obj.name == name) { + ele.obj.value = val; + } + settings[i] = ele; + i++; + }); + this.setState({ + data: settings + }); + } + + render() { + var settings = this.props.generateInputs(this.state.data, this.inputHandler); + + return ( + + {settings} +
+ +
+
+ ); + } +} + +if (document.getElementById('GraphsSettings')) { + ReactDOM.render(, document.getElementById('GraphsSettings')); +} diff --git a/conf/site/resources/js/components/Settings/tabs/HealthchecksSettings.js b/conf/site/resources/js/components/Settings/tabs/HealthchecksSettings.js new file mode 100644 index 00000000..22bb563e --- /dev/null +++ b/conf/site/resources/js/components/Settings/tabs/HealthchecksSettings.js @@ -0,0 +1,48 @@ +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import { Modal, Button, Tab } from 'react-bootstrap'; +import Axios from 'axios'; +import { toast } from 'react-toastify'; +import SettingsInput from '../SettingsInput'; + +export default class HealthchecksSettings extends Component { + constructor(props) { + super(props) + + this.state = { + data: this.props.data + } + } + + inputHandler = (name, val) => { + var settings = this.state.data; + var i = 0; + settings.forEach(ele => { + if(ele.obj.name == name) { + ele.obj.value = val; + } + settings[i] = ele; + i++; + }); + this.setState({ + data: settings + }); + } + + render() { + var settings = this.props.generateInputs(this.state.data, this.inputHandler); + + return ( + + {settings} +
+ +
+
+ ); + } +} + +if (document.getElementById('HealthchecksSettings')) { + ReactDOM.render(, document.getElementById('HealthchecksSettings')); +} diff --git a/conf/site/resources/js/components/Settings/tabs/NotificationsSettings.js b/conf/site/resources/js/components/Settings/tabs/NotificationsSettings.js new file mode 100644 index 00000000..42bc2903 --- /dev/null +++ b/conf/site/resources/js/components/Settings/tabs/NotificationsSettings.js @@ -0,0 +1,46 @@ +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import { Modal, Button, Tab } from 'react-bootstrap'; +import Axios from 'axios'; + +export default class NotificationsSettings extends Component { + constructor(props) { + super(props) + + this.state = { + data: this.props.data + } + } + + inputHandler = (name, val) => { + var settings = this.state.data; + var i = 0; + settings.forEach(ele => { + if(ele.obj.name == name) { + ele.obj.value = val; + } + settings[i] = ele; + i++; + }); + this.setState({ + data: settings + }); + } + + render() { + var settings = this.props.generateInputs(this.state.data, this.inputHandler); + + return ( + + {settings} +
+ +
+
+ ); + } +} + +if (document.getElementById('NotificationsSettings')) { + ReactDOM.render(, document.getElementById('NotificationsSettings')); +} diff --git a/conf/site/resources/js/components/Settings/ResetSettings.js b/conf/site/resources/js/components/Settings/tabs/ResetSettings.js similarity index 50% rename from conf/site/resources/js/components/Settings/ResetSettings.js rename to conf/site/resources/js/components/Settings/tabs/ResetSettings.js index bbf75d31..116bda19 100644 --- a/conf/site/resources/js/components/Settings/ResetSettings.js +++ b/conf/site/resources/js/components/Settings/tabs/ResetSettings.js @@ -1,7 +1,6 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; -import { Modal, Button } from 'react-bootstrap'; -import SettingsModalCard from './SettingsModalCard'; +import { Button } from 'react-bootstrap'; import Axios from 'axios'; import { toast } from 'react-toastify'; @@ -10,15 +9,6 @@ export default class ResetSettings extends Component { super(props) this.state = { - show: false, - } - } - - toggleShow = () => { - if(this.state.show) { - this.setState({ show: false }); - } else { - this.setState({ show:true }); } } @@ -45,17 +35,9 @@ export default class ResetSettings extends Component { return ( <> - - - - {title} - - -

Clear all speedtests

-

If using SQLite, a backup of the database will be stored in the location of the current database.

- -
-
+

Clear all speedtests

+

If using SQLite, a backup of the database will be stored in the location of the current database.

+ ); } diff --git a/conf/site/resources/js/components/SpeedtestsPage.js b/conf/site/resources/js/components/SpeedtestsPage.js new file mode 100644 index 00000000..79e91b3b --- /dev/null +++ b/conf/site/resources/js/components/SpeedtestsPage.js @@ -0,0 +1,29 @@ +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import TestsTable from './Graphics/TestsTable'; +import Footer from './Home/Footer'; +import Navbar from './Navbar'; + +export default class SpeedtestsPage extends Component { + constructor(props) { + super(props) + + this.state = { + + } + } + + render() { + return ( +
+ + +
+
+ ); + } +} + +if (document.getElementById('SpeedtestsPage')) { + ReactDOM.render(, document.getElementById('SpeedtestsPage')); +} diff --git a/conf/site/resources/js/index.js b/conf/site/resources/js/index.js index 4f2ac9f6..6277564d 100644 --- a/conf/site/resources/js/index.js +++ b/conf/site/resources/js/index.js @@ -8,6 +8,8 @@ import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import HomePage from './components/Home/HomePage'; import Cookies from 'js-cookie'; +import SettingsIndex from './components/Settings/SettingsIndex'; +import SpeedtestsPage from './components/SpeedtestsPage'; export default class Index extends Component { constructor(props) { @@ -84,6 +86,18 @@ export default class Index extends Component {
)} /> + ( +
+ + +
+ )} /> + ( +
+ + +
+ )} /> ( )} /> ()} /> diff --git a/conf/site/routes/web.php b/conf/site/routes/web.php index d41f71d1..a25f2e5a 100644 --- a/conf/site/routes/web.php +++ b/conf/site/routes/web.php @@ -16,20 +16,20 @@ use Illuminate\Support\Facades\Route; | */ -Route::get(SettingsHelper::getBase() . 'files/{path?}', function($file) { +Route::get(SettingsHelper::getBase() . 'files/{path?}', function ($file) { $fileP = explode('?', $file)[0]; $fileP = public_path() . '/' . $fileP; - if(file_exists($fileP)) { + if (file_exists($fileP)) { $contents = File::get($fileP); $mime = \GuzzleHttp\Psr7\mimetype_from_filename($fileP); - return Response::make(File::get($fileP), 200, [ 'Content-type' => $mime ]); + return Response::make(File::get($fileP), 200, ['Content-type' => $mime]); } else { abort(404); } })->where('path', '.*') - ->name('files'); + ->name('files'); -Route::get('/{path?}', function() { - return view('app', [ 'title' => 'Speedtest Tracker' ]); +Route::get('/{path?}', function () { + return view('app', ['title' => SettingsHelper::get('app_name')->value]); })->where('path', '^((?!\/api\/).)*$') - ->name('react'); + ->name('react');