From b1a6c02e56fdc01a7ff69fa7e7dd8ea71380b7ba Mon Sep 17 00:00:00 2001 From: Yassine Doghri <yassine@doghri.fr> Date: Wed, 6 Jul 2022 15:29:15 +0000 Subject: [PATCH] feat(admin): add instance wide dashboard with storage and bandwidth usage * add DashboardCard component * add instance wide podcasts and episodes numbers * add app.storageLimit environment variable * divide bytes by 1000 instead of 1024 in stats sql queries closes #216 --- app/Config/App.php | 5 ++ app/Helpers/components_helper.php | 66 ++++++++++++--- app/Helpers/misc_helper.php | 34 +------- app/Resources/icons/database.svg | 6 ++ app/Resources/icons/play-circle.svg | 6 ++ app/Views/Components/DashboardCard.php | 46 +++++++++++ ecs.php | 1 + modules/Admin/Config/Routes.php | 2 +- .../Admin/Controllers/DashboardController.php | 82 +++++++++++++++++++ modules/Admin/Controllers/HomeController.php | 22 ----- modules/Admin/Language/ar/Common.php | 1 + .../Language/ar/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/br/Common.php | 1 + .../Language/br/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/de/Common.php | 1 + .../Language/de/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/el/Common.php | 1 + .../Language/el/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/en/Charts.php | 2 + modules/Admin/Language/en/Common.php | 2 + modules/Admin/Language/en/Dashboard.php | 28 +++++++ modules/Admin/Language/es/Common.php | 1 + .../Language/es/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/fr/Common.php | 1 + .../Language/fr/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/id/Common.php | 1 + .../{en/Admin.php => id/Dashboard.php} | 3 +- modules/Admin/Language/it/Common.php | 1 + .../{id/Admin.php => it/Dashboard.php} | 3 +- modules/Admin/Language/nl/Common.php | 1 + .../Language/nl/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/nn-NO/Common.php | 1 + .../nn-NO/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/oc/Common.php | 1 + .../Language/oc/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/pl/Common.php | 1 + .../Language/pl/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/pt-BR/Common.php | 1 + .../pt-BR/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/pt/Admin.php | 15 ---- modules/Admin/Language/pt/Common.php | 1 + .../{it/Admin.php => pt/Dashboard.php} | 3 +- modules/Admin/Language/ru/Common.php | 1 + .../Language/ru/{Admin.php => Dashboard.php} | 3 +- modules/Admin/Language/sv/Admin.php | 15 ---- modules/Admin/Language/sv/Common.php | 1 + modules/Admin/Language/sv/Dashboard.php | 14 ++++ modules/Analytics/Config/Routes.php | 6 +- .../Controllers/AnalyticsController.php | 19 ++++- .../Models/AnalyticsPodcastModel.php | 48 ++++++++++- themes/cp_admin/_partials/_nav_header.php | 2 +- themes/cp_admin/_sidebar.php | 4 + themes/cp_admin/dashboard.php | 35 +++++++- themes/cp_admin/episode/create.php | 4 +- themes/cp_admin/episode/edit.php | 4 +- themes/cp_admin/podcast/_sidebar.php | 2 +- themes/cp_app/_admin_navbar.php | 2 +- 57 files changed, 394 insertions(+), 139 deletions(-) create mode 100644 app/Resources/icons/database.svg create mode 100644 app/Resources/icons/play-circle.svg create mode 100644 app/Views/Components/DashboardCard.php create mode 100644 modules/Admin/Controllers/DashboardController.php delete mode 100644 modules/Admin/Controllers/HomeController.php rename modules/Admin/Language/ar/{Admin.php => Dashboard.php} (68%) rename modules/Admin/Language/br/{Admin.php => Dashboard.php} (73%) rename modules/Admin/Language/de/{Admin.php => Dashboard.php} (69%) rename modules/Admin/Language/el/{Admin.php => Dashboard.php} (63%) create mode 100644 modules/Admin/Language/en/Dashboard.php rename modules/Admin/Language/es/{Admin.php => Dashboard.php} (72%) rename modules/Admin/Language/fr/{Admin.php => Dashboard.php} (72%) rename modules/Admin/Language/{en/Admin.php => id/Dashboard.php} (73%) rename modules/Admin/Language/{id/Admin.php => it/Dashboard.php} (73%) rename modules/Admin/Language/nl/{Admin.php => Dashboard.php} (70%) rename modules/Admin/Language/nn-NO/{Admin.php => Dashboard.php} (72%) rename modules/Admin/Language/oc/{Admin.php => Dashboard.php} (73%) rename modules/Admin/Language/pl/{Admin.php => Dashboard.php} (71%) rename modules/Admin/Language/pt-BR/{Admin.php => Dashboard.php} (71%) delete mode 100644 modules/Admin/Language/pt/Admin.php rename modules/Admin/Language/{it/Admin.php => pt/Dashboard.php} (73%) rename modules/Admin/Language/ru/{Admin.php => Dashboard.php} (66%) delete mode 100644 modules/Admin/Language/sv/Admin.php create mode 100644 modules/Admin/Language/sv/Dashboard.php diff --git a/app/Config/App.php b/app/Config/App.php index fe5c59a8a7..cf921c7c6e 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -451,4 +451,9 @@ class App extends BaseConfig ]; public string $theme = 'pine'; + + /** + * Storage limit in Gigabytes + */ + public ?int $storageLimit = null; } diff --git a/app/Helpers/components_helper.php b/app/Helpers/components_helper.php index 6bef701359..6989ee4ea7 100644 --- a/app/Helpers/components_helper.php +++ b/app/Helpers/components_helper.php @@ -179,9 +179,9 @@ if (! function_exists('publication_button')) { break; } - return <<<CODE_SAMPLE + return <<<HTML <Button variant="{$variant}" uri="{$route}" iconLeft="{$iconLeft}" >{$label}</Button> - CODE_SAMPLE; + HTML; } } @@ -205,7 +205,7 @@ if (! function_exists('publication_status_banner')) { case 'scheduled': $bannerDisclaimer = lang('Podcast.publication_status_banner.draft_mode'); $bannerText = lang('Podcast.publication_status_banner.scheduled', [ - 'publication_date' => local_time($publicationDate), + 'publication_date' => local_datetime($publicationDate), ], null, false); $linkRoute = route_to('podcast-publish_edit', $podcastId); $linkLabel = lang('Podcast.publish_edit'); @@ -218,7 +218,7 @@ if (! function_exists('publication_status_banner')) { break; } - return <<<CODE_SAMPLE + return <<<HTML <div class="flex items-center px-12 py-1 border-b bg-stripes-gray border-subtle" role="alert"> <p class="text-gray-900"> <span class="text-xs font-semibold tracking-wide uppercase">{$bannerDisclaimer}</span> @@ -226,7 +226,7 @@ if (! function_exists('publication_status_banner')) { </p> <a href="{$linkRoute}" class="ml-1 text-sm font-semibold underline shadow-xs text-accent-base hover:text-accent-hover hover:no-underline">{$linkLabel}</a> </div> - CODE_SAMPLE; + HTML; } } @@ -321,7 +321,7 @@ if (! function_exists('audio_player')) { $language = service('request') ->getLocale(); - return <<<CODE_SAMPLE + return <<<HTML <vm-player id="castopod-vm-player" theme="light" @@ -346,7 +346,7 @@ if (! function_exists('audio_player')) { </vm-controls> </vm-ui> </vm-player> - CODE_SAMPLE; + HTML; } } @@ -361,16 +361,60 @@ if (! function_exists('relative_time')) { $translatedDate = $time->toLocalizedString($formatter->getPattern()); $datetime = $time->format(DateTime::ISO8601); - return <<<CODE_SAMPLE + return <<<HTML <time-ago class="{$class}" datetime="{$datetime}"> <time datetime="{$datetime}" title="{$time}">{$translatedDate}</time> </time-ago> - CODE_SAMPLE; + HTML; } } +// ------------------------------------------------------------------------ + +if (! function_exists('local_datetime')) { + function local_datetime(Time $time): string + { + $formatter = new IntlDateFormatter(service( + 'request' + )->getLocale(), IntlDateFormatter::MEDIUM, IntlDateFormatter::LONG); + $translatedDate = $time->toLocalizedString($formatter->getPattern()); + $datetime = $time->format(DateTime::ISO8601); + + return <<<HTML + <local-time datetime="{$datetime}" + weekday="long" + month="long" + day="numeric" + year="numeric" + hour="numeric" + minute="numeric"> + <time + datetime="{$datetime}" + title="{$time}">{$translatedDate}</time> + </local-time> + HTML; + } +} + +// ------------------------------------------------------------------------ + +if (! function_exists('local_date')) { + function local_date(Time $time): string + { + $formatter = new IntlDateFormatter(service( + 'request' + )->getLocale(), IntlDateFormatter::MEDIUM, IntlDateFormatter::NONE); + $translatedDate = $time->toLocalizedString($formatter->getPattern()); + + return <<<HTML + <time title="{$time}">{$translatedDate}</time> + HTML; + } +} + + // ------------------------------------------------------------------------ if (! function_exists('explicit_badge')) { @@ -381,9 +425,9 @@ if (! function_exists('explicit_badge')) { } $explicitLabel = lang('Common.explicit'); - return <<<CODE_SAMPLE + return <<<HTML <span class="px-1 text-xs font-semibold leading-tight tracking-wider uppercase border md:border-white/50 {$class}">{$explicitLabel}</span> - CODE_SAMPLE; + HTML; } } diff --git a/app/Helpers/misc_helper.php b/app/Helpers/misc_helper.php index e69e9e87e8..7975bdc123 100644 --- a/app/Helpers/misc_helper.php +++ b/app/Helpers/misc_helper.php @@ -8,7 +8,6 @@ declare(strict_types=1); * @link https://castopod.org/ */ -use CodeIgniter\I18n\Time; if (! function_exists('get_browser_language')) { /** @@ -281,41 +280,16 @@ if (! function_exists('format_bytes')) { /** * Adapted from https://stackoverflow.com/a/2510459 */ - function formatBytes(float $bytes, int $precision = 2): string + function formatBytes(float $bytes, bool $is_binary = false, int $precision = 2): string { - $units = ['B', 'KiB', 'MiB', 'GiB', 'TiB']; + $units = $is_binary ? ['B', 'KiB', 'MiB', 'GiB', 'TiB'] : ['B', 'KB', 'MB', 'GB', 'TB']; $bytes = max($bytes, 0); - $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); + $pow = floor(($bytes ? log($bytes) : 0) / log($is_binary ? 1024 : 1000)); $pow = min($pow, count($units) - 1); - $bytes /= pow(1024, $pow); + $bytes /= pow($is_binary ? 1024 : 1000, $pow); return round($bytes, $precision) . $units[$pow]; } } - -if (! function_exists('local_time')) { - function local_time(Time $time): string - { - $formatter = new IntlDateFormatter(service( - 'request' - )->getLocale(), IntlDateFormatter::MEDIUM, IntlDateFormatter::LONG); - $translatedDate = $time->toLocalizedString($formatter->getPattern()); - $datetime = $time->format(DateTime::ISO8601); - - return <<<CODE_SAMPLE - <local-time datetime="{$datetime}" - weekday="long" - month="long" - day="numeric" - year="numeric" - hour="numeric" - minute="numeric"> - <time - datetime="{$datetime}" - title="{$time}">{$translatedDate}</time> - </local-time> - CODE_SAMPLE; - } -} diff --git a/app/Resources/icons/database.svg b/app/Resources/icons/database.svg new file mode 100644 index 0000000000..6dc449b48c --- /dev/null +++ b/app/Resources/icons/database.svg @@ -0,0 +1,6 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <g> + <path fill="none" d="M0 0h24v24H0z"/> + <path d="M21 9.5v3c0 2.485-4.03 4.5-9 4.5s-9-2.015-9-4.5v-3c0 2.485 4.03 4.5 9 4.5s9-2.015 9-4.5zm-18 5c0 2.485 4.03 4.5 9 4.5s9-2.015 9-4.5v3c0 2.485-4.03 4.5-9 4.5s-9-2.015-9-4.5v-3zm9-2.5c-4.97 0-9-2.015-9-4.5S7.03 3 12 3s9 2.015 9 4.5-4.03 4.5-9 4.5z"/> + </g> +</svg> \ No newline at end of file diff --git a/app/Resources/icons/play-circle.svg b/app/Resources/icons/play-circle.svg new file mode 100644 index 0000000000..5d5f703938 --- /dev/null +++ b/app/Resources/icons/play-circle.svg @@ -0,0 +1,6 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <g> + <path fill="none" d="M0 0h24v24H0z"/> + <path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM10.622 8.415l4.879 3.252a.4.4 0 0 1 0 .666l-4.88 3.252a.4.4 0 0 1-.621-.332V8.747a.4.4 0 0 1 .622-.332z"/> + </g> +</svg> \ No newline at end of file diff --git a/app/Views/Components/DashboardCard.php b/app/Views/Components/DashboardCard.php new file mode 100644 index 0000000000..474022378c --- /dev/null +++ b/app/Views/Components/DashboardCard.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace App\Views\Components; + +use ViewComponents\Component; + +class DashboardCard extends Component +{ + protected ?string $href = null; + + protected string $glyph; + + protected string $title; + + protected string $subtitle; + + public function setSubtitle(string $value): void + { + $this->subtitle = html_entity_decode($value); + } + + public function render(): string + { + $glyph = icon($this->glyph, 'flex-shrink-0 bg-base rounded-full w-8 h-8 p-2 text-accent-base'); + + if ($this->href !== null && $this->href !== '') { + $chevronRight = icon('chevron-right'); + $viewLang = lang('Common.view'); + return <<<HTML + <a href="{$this->href}" class="flex items-center justify-between w-full max-w-sm p-4 bg-elevated focus:ring-accent rounded-xl border-3 border-subtle group"> + <div class="flex items-start">{$glyph}<div class="flex flex-col ml-2"><div class="flex items-center"><span class="text-xs font-semibold leading-loose tracking-wider uppercase">{$this->title}</span><div class="inline-flex items-center ml-4 transition -translate-x-full group-hover:translate-x-0 group-focus:translate-x-0"><span class="-ml-2 text-xs lowercase transition opacity-0 group-hover:opacity-100 group-focus:opacity-100">{$viewLang}</span>{$chevronRight}</div></div><p class="text-xs">{$this->subtitle}</p></div></div> + <div class="mx-2 text-5xl font-bold">{$this->slot}</div> + </a> + HTML; + } + + return <<<HTML + <div class="flex items-center justify-between w-full max-w-sm p-4 bg-elevated rounded-xl border-3 border-subtle"> + <div class="flex items-start">{$glyph}<div class="flex flex-col ml-2"><span class="text-xs font-semibold leading-loose tracking-wider uppercase">{$this->title}</span><p class="text-xs">{$this->subtitle}</p></div></div> + <div class="mx-2 text-5xl font-bold">{$this->slot}</div> + </div> + HTML; + } +} diff --git a/ecs.php b/ecs.php index 6abb2da582..8e2da3b116 100644 --- a/ecs.php +++ b/ecs.php @@ -26,6 +26,7 @@ return static function (ECSConfig $ecsConfig): void { __DIR__ . '/app/Views/Components/*', __DIR__ . '/modules/**/Views/Components/*', __DIR__ . '/themes/**/Views/Components/*', + __DIR__ . '/app/Helpers/components_helper.php' ], LineLengthFixer::class => [ diff --git a/modules/Admin/Config/Routes.php b/modules/Admin/Config/Routes.php index b3ffcd13ae..d6c58357a5 100644 --- a/modules/Admin/Config/Routes.php +++ b/modules/Admin/Config/Routes.php @@ -19,7 +19,7 @@ $routes->group( 'namespace' => 'Modules\Admin\Controllers', ], function ($routes): void { - $routes->get('/', 'HomeController', [ + $routes->get('/', 'DashboardController', [ 'as' => 'admin', ]); diff --git a/modules/Admin/Controllers/DashboardController.php b/modules/Admin/Controllers/DashboardController.php new file mode 100644 index 0000000000..14057bcd0e --- /dev/null +++ b/modules/Admin/Controllers/DashboardController.php @@ -0,0 +1,82 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2020 Ad Aures + * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 + * @link https://castopod.org/ + */ + +namespace Modules\Admin\Controllers; + +use App\Models\EpisodeModel; +use App\Models\MediaModel; +use App\Models\PodcastModel; +use CodeIgniter\I18n\Time; + +class DashboardController extends BaseController +{ + public function index(): string + { + $podcastsData = []; + $podcastsCount = (new PodcastModel())->builder() + ->countAll(); + $podcastsLastPublishedAt = (new PodcastModel())->builder() + ->select('MAX(published_at) as last_published_at') + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->get() + ->getResultArray()[0]['last_published_at']; + $podcastsData['number_of_podcasts'] = (int) $podcastsCount; + $podcastsData['last_published_at'] = $podcastsLastPublishedAt === null ? null : new Time( + $podcastsLastPublishedAt + ); + + $episodesData = []; + $episodesCount = (new EpisodeModel())->builder() + ->countAll(); + $episodesLastPublishedAt = (new EpisodeModel())->builder() + ->select('MAX(published_at) as last_published_at') + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->get() + ->getResultArray()[0]['last_published_at']; + $episodesData['number_of_episodes'] = (int) $episodesCount; + $episodesData['last_published_at'] = $episodesLastPublishedAt === null ? null : new Time( + $episodesLastPublishedAt + ); + + $totalUploaded = (new MediaModel())->builder() + ->selectSum('file_size') + ->get() + ->getResultArray()[0]; + + $appStorageLimit = config('App') + ->storageLimit; + if ($appStorageLimit === null || $appStorageLimit < 0) { + $storageLimitBytes = disk_free_space('./'); + } else { + $storageLimitBytes = $appStorageLimit * 1000000000; + } + + $storageData = [ + 'limit' => formatBytes((int) $storageLimitBytes), + 'percentage' => round((((int) $totalUploaded['file_size']) / $storageLimitBytes) * 100, 0), + 'total_uploaded' => formatBytes((int) $totalUploaded['file_size']), + ]; + + $onlyPodcastId = null; + if ($podcastsData['number_of_podcasts'] === 1) { + $onlyPodcastId = (new PodcastModel())->first() + ->id; + } + + $data = [ + 'podcastsData' => $podcastsData, + 'episodesData' => $episodesData, + 'storageData' => $storageData, + 'onlyPodcastId' => $onlyPodcastId, + ]; + + return view('dashboard', $data); + } +} diff --git a/modules/Admin/Controllers/HomeController.php b/modules/Admin/Controllers/HomeController.php deleted file mode 100644 index 9248cb4c22..0000000000 --- a/modules/Admin/Controllers/HomeController.php +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright 2020 Ad Aures - * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 - * @link https://castopod.org/ - */ - -namespace Modules\Admin\Controllers; - -use CodeIgniter\HTTP\RedirectResponse; - -class HomeController extends BaseController -{ - public function index(): RedirectResponse - { - session()->keepFlashdata('message'); - return redirect()->route('podcast-list'); - } -} diff --git a/modules/Admin/Language/ar/Common.php b/modules/Admin/Language/ar/Common.php index 9021d57efb..8df4418606 100644 --- a/modules/Admin/Language/ar/Common.php +++ b/modules/Admin/Language/ar/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Playing', ], 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'اختر أسلوب التÙاعل', ]; diff --git a/modules/Admin/Language/ar/Admin.php b/modules/Admin/Language/ar/Dashboard.php similarity index 68% rename from modules/Admin/Language/ar/Admin.php rename to modules/Admin/Language/ar/Dashboard.php index 971ecb1018..43d1496397 100644 --- a/modules/Admin/Language/ar/Admin.php +++ b/modules/Admin/Language/ar/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'لوØØ© التØكم الإدارية', + 'home' => 'لوØØ© التØكم الإدارية', 'welcome_message' => 'أهلًا بك ÙÙŠ المنطقة الإدارية!', - 'choose_interact' => 'اختر أسلوب التÙاعل', ]; diff --git a/modules/Admin/Language/br/Common.php b/modules/Admin/Language/br/Common.php index 7a0ca7e0e1..93bb776d22 100644 --- a/modules/Admin/Language/br/Common.php +++ b/modules/Admin/Language/br/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'O lenn', ], 'size_limit' => 'Bevenn ar vent: {0}.', + 'choose_interact' => 'Dibabit penaos interaktiñ', ]; diff --git a/modules/Admin/Language/br/Admin.php b/modules/Admin/Language/br/Dashboard.php similarity index 73% rename from modules/Admin/Language/br/Admin.php rename to modules/Admin/Language/br/Dashboard.php index 3773855d69..dd55b106b6 100644 --- a/modules/Admin/Language/br/Admin.php +++ b/modules/Admin/Language/br/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Taolenn-stur', + 'home' => 'Taolenn-stur', 'welcome_message' => 'Degemer mat en daolenn-stur!', - 'choose_interact' => 'Dibabit penaos interaktiñ', ]; diff --git a/modules/Admin/Language/de/Common.php b/modules/Admin/Language/de/Common.php index 64ee6f3e85..71549ddb5b 100644 --- a/modules/Admin/Language/de/Common.php +++ b/modules/Admin/Language/de/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Spielt', ], 'size_limit' => 'Größenlimit: {0}.', + 'choose_interact' => 'Mit welchem Podcast-Profil wollen Sie handeln', ]; diff --git a/modules/Admin/Language/de/Admin.php b/modules/Admin/Language/de/Dashboard.php similarity index 69% rename from modules/Admin/Language/de/Admin.php rename to modules/Admin/Language/de/Dashboard.php index ec6d5e7955..b3e24a6971 100644 --- a/modules/Admin/Language/de/Admin.php +++ b/modules/Admin/Language/de/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Adminübersicht', + 'home' => 'Adminübersicht', 'welcome_message' => 'Willkommen im Administrationsbereich!', - 'choose_interact' => 'Mit welchem Podcast-Profil wollen Sie handeln', ]; diff --git a/modules/Admin/Language/el/Common.php b/modules/Admin/Language/el/Common.php index e19b3e7360..126fc83ae7 100644 --- a/modules/Admin/Language/el/Common.php +++ b/modules/Admin/Language/el/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'ΑναπαÏάγεται', ], 'size_limit' => 'ÎŒÏιο μεγÎθους: {0}.', + 'choose_interact' => 'ΕπιλÎξτε τον Ï„Ïόπο αλληλεπίδÏασης', ]; diff --git a/modules/Admin/Language/el/Admin.php b/modules/Admin/Language/el/Dashboard.php similarity index 63% rename from modules/Admin/Language/el/Admin.php rename to modules/Admin/Language/el/Dashboard.php index 7b4a8544fa..516b5368d9 100644 --- a/modules/Admin/Language/el/Admin.php +++ b/modules/Admin/Language/el/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Πίνακας ελÎγχου διαχειÏιστή', + 'home' => 'Πίνακας ελÎγχου διαχειÏιστή', 'welcome_message' => 'Καλώς ήÏθατε στην πεÏιοχή διαχείÏισης!', - 'choose_interact' => 'ΕπιλÎξτε τον Ï„Ïόπο αλληλεπίδÏασης', ]; diff --git a/modules/Admin/Language/en/Charts.php b/modules/Admin/Language/en/Charts.php index d9a75a1d84..4b33530ef0 100644 --- a/modules/Admin/Language/en/Charts.php +++ b/modules/Admin/Language/en/Charts.php @@ -35,4 +35,6 @@ return [ 'by_weekday' => 'By week day (for the past 60 days)', 'by_hour' => 'By time of day (for the past 60 days)', 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', ]; diff --git a/modules/Admin/Language/en/Common.php b/modules/Admin/Language/en/Common.php index d97bcf991f..596c8bcdec 100644 --- a/modules/Admin/Language/en/Common.php +++ b/modules/Admin/Language/en/Common.php @@ -46,4 +46,6 @@ return [ 'playing' => 'Playing', ], 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', ]; diff --git a/modules/Admin/Language/en/Dashboard.php b/modules/Admin/Language/en/Dashboard.php new file mode 100644 index 0000000000..881073fd26 --- /dev/null +++ b/modules/Admin/Language/en/Dashboard.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2020 Ad Aures + * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 + * @link https://castopod.org/ + */ + +return [ + 'home' => 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/es/Common.php b/modules/Admin/Language/es/Common.php index 05648953c2..61a42889f9 100644 --- a/modules/Admin/Language/es/Common.php +++ b/modules/Admin/Language/es/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Reproduciendo', ], 'size_limit' => 'LÃmite de tamaño: {0}.', + 'choose_interact' => 'Elige cómo interactuar', ]; diff --git a/modules/Admin/Language/es/Admin.php b/modules/Admin/Language/es/Dashboard.php similarity index 72% rename from modules/Admin/Language/es/Admin.php rename to modules/Admin/Language/es/Dashboard.php index 83f9f8d57e..05ea795513 100644 --- a/modules/Admin/Language/es/Admin.php +++ b/modules/Admin/Language/es/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Panel de administración', + 'home' => 'Panel de administración', 'welcome_message' => '¡Bienvenido al área de administración!', - 'choose_interact' => 'Elige cómo interactuar', ]; diff --git a/modules/Admin/Language/fr/Common.php b/modules/Admin/Language/fr/Common.php index 04725db62e..4187008ef4 100644 --- a/modules/Admin/Language/fr/Common.php +++ b/modules/Admin/Language/fr/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'En cours', ], 'size_limit' => 'Taille maximale : {0}.', + 'choose_interact' => 'Choisissez comment interagir', ]; diff --git a/modules/Admin/Language/fr/Admin.php b/modules/Admin/Language/fr/Dashboard.php similarity index 72% rename from modules/Admin/Language/fr/Admin.php rename to modules/Admin/Language/fr/Dashboard.php index 3b37a2b240..358a486b6a 100644 --- a/modules/Admin/Language/fr/Admin.php +++ b/modules/Admin/Language/fr/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Tableau de bord', + 'home' => 'Tableau de bord', 'welcome_message' => 'Bienvenue dans l’administration !', - 'choose_interact' => 'Choisissez comment interagir', ]; diff --git a/modules/Admin/Language/id/Common.php b/modules/Admin/Language/id/Common.php index d97bcf991f..be498dacf3 100644 --- a/modules/Admin/Language/id/Common.php +++ b/modules/Admin/Language/id/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Playing', ], 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', ]; diff --git a/modules/Admin/Language/en/Admin.php b/modules/Admin/Language/id/Dashboard.php similarity index 73% rename from modules/Admin/Language/en/Admin.php rename to modules/Admin/Language/id/Dashboard.php index 5e3942371f..7f28d24dfe 100644 --- a/modules/Admin/Language/en/Admin.php +++ b/modules/Admin/Language/id/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Admin dashboard', + 'home' => 'Admin dashboard', 'welcome_message' => 'Welcome to the admin area!', - 'choose_interact' => 'Choose how to interact', ]; diff --git a/modules/Admin/Language/it/Common.php b/modules/Admin/Language/it/Common.php index d97bcf991f..be498dacf3 100644 --- a/modules/Admin/Language/it/Common.php +++ b/modules/Admin/Language/it/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Playing', ], 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', ]; diff --git a/modules/Admin/Language/id/Admin.php b/modules/Admin/Language/it/Dashboard.php similarity index 73% rename from modules/Admin/Language/id/Admin.php rename to modules/Admin/Language/it/Dashboard.php index 5e3942371f..7f28d24dfe 100644 --- a/modules/Admin/Language/id/Admin.php +++ b/modules/Admin/Language/it/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Admin dashboard', + 'home' => 'Admin dashboard', 'welcome_message' => 'Welcome to the admin area!', - 'choose_interact' => 'Choose how to interact', ]; diff --git a/modules/Admin/Language/nl/Common.php b/modules/Admin/Language/nl/Common.php index 9ef0b7721d..ac06748dee 100644 --- a/modules/Admin/Language/nl/Common.php +++ b/modules/Admin/Language/nl/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Wordt afgespeeld', ], 'size_limit' => 'Maximale grootte: {0}.', + 'choose_interact' => 'Kies hoe de interactie moet worden', ]; diff --git a/modules/Admin/Language/nl/Admin.php b/modules/Admin/Language/nl/Dashboard.php similarity index 70% rename from modules/Admin/Language/nl/Admin.php rename to modules/Admin/Language/nl/Dashboard.php index 8e50419d8a..b5c5ef8182 100644 --- a/modules/Admin/Language/nl/Admin.php +++ b/modules/Admin/Language/nl/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Beheerder overzicht', + 'home' => 'Beheerder overzicht', 'welcome_message' => 'Welkom bij de beheerder omgeving!', - 'choose_interact' => 'Kies hoe de interactie moet worden', ]; diff --git a/modules/Admin/Language/nn-NO/Common.php b/modules/Admin/Language/nn-NO/Common.php index 813bb910aa..14026246c9 100644 --- a/modules/Admin/Language/nn-NO/Common.php +++ b/modules/Admin/Language/nn-NO/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Spelar', ], 'size_limit' => 'Maks storleik: {0}.', + 'choose_interact' => 'Vel korleis du vil samhandla', ]; diff --git a/modules/Admin/Language/nn-NO/Admin.php b/modules/Admin/Language/nn-NO/Dashboard.php similarity index 72% rename from modules/Admin/Language/nn-NO/Admin.php rename to modules/Admin/Language/nn-NO/Dashboard.php index 2b69c6971f..776337abeb 100644 --- a/modules/Admin/Language/nn-NO/Admin.php +++ b/modules/Admin/Language/nn-NO/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Styringspanel', + 'home' => 'Styringspanel', 'welcome_message' => 'Velkomen til styraromrÃ¥det!', - 'choose_interact' => 'Vel korleis du vil samhandla', ]; diff --git a/modules/Admin/Language/oc/Common.php b/modules/Admin/Language/oc/Common.php index d97bcf991f..be498dacf3 100644 --- a/modules/Admin/Language/oc/Common.php +++ b/modules/Admin/Language/oc/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Playing', ], 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', ]; diff --git a/modules/Admin/Language/oc/Admin.php b/modules/Admin/Language/oc/Dashboard.php similarity index 73% rename from modules/Admin/Language/oc/Admin.php rename to modules/Admin/Language/oc/Dashboard.php index 5e3942371f..7f28d24dfe 100644 --- a/modules/Admin/Language/oc/Admin.php +++ b/modules/Admin/Language/oc/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Admin dashboard', + 'home' => 'Admin dashboard', 'welcome_message' => 'Welcome to the admin area!', - 'choose_interact' => 'Choose how to interact', ]; diff --git a/modules/Admin/Language/pl/Common.php b/modules/Admin/Language/pl/Common.php index f015f1f889..00e9c9f2a2 100644 --- a/modules/Admin/Language/pl/Common.php +++ b/modules/Admin/Language/pl/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Odtwarzanie', ], 'size_limit' => 'Limit rozmiaru: {0}.', + 'choose_interact' => 'Wybierz sposób interakcji', ]; diff --git a/modules/Admin/Language/pl/Admin.php b/modules/Admin/Language/pl/Dashboard.php similarity index 71% rename from modules/Admin/Language/pl/Admin.php rename to modules/Admin/Language/pl/Dashboard.php index cb262679da..9c9a1268cf 100644 --- a/modules/Admin/Language/pl/Admin.php +++ b/modules/Admin/Language/pl/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Pulpit administratora', + 'home' => 'Pulpit administratora', 'welcome_message' => 'Witamy w panelu administracyjnym!', - 'choose_interact' => 'Wybierz sposób interakcji', ]; diff --git a/modules/Admin/Language/pt-BR/Common.php b/modules/Admin/Language/pt-BR/Common.php index e57238eb17..82cb61806e 100644 --- a/modules/Admin/Language/pt-BR/Common.php +++ b/modules/Admin/Language/pt-BR/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Reproduzindo', ], 'size_limit' => 'Limite de tamanho: {0}.', + 'choose_interact' => 'Escolha como interagir', ]; diff --git a/modules/Admin/Language/pt-BR/Admin.php b/modules/Admin/Language/pt-BR/Dashboard.php similarity index 71% rename from modules/Admin/Language/pt-BR/Admin.php rename to modules/Admin/Language/pt-BR/Dashboard.php index 432b6a925d..6625b47d28 100644 --- a/modules/Admin/Language/pt-BR/Admin.php +++ b/modules/Admin/Language/pt-BR/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Painel de administração', + 'home' => 'Painel de administração', 'welcome_message' => 'Bem-vindo à área de administração!', - 'choose_interact' => 'Escolha como interagir', ]; diff --git a/modules/Admin/Language/pt/Admin.php b/modules/Admin/Language/pt/Admin.php deleted file mode 100644 index 5e3942371f..0000000000 --- a/modules/Admin/Language/pt/Admin.php +++ /dev/null @@ -1,15 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright 2020 Ad Aures - * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 - * @link https://castopod.org/ - */ - -return [ - 'dashboard' => 'Admin dashboard', - 'welcome_message' => 'Welcome to the admin area!', - 'choose_interact' => 'Choose how to interact', -]; diff --git a/modules/Admin/Language/pt/Common.php b/modules/Admin/Language/pt/Common.php index d97bcf991f..be498dacf3 100644 --- a/modules/Admin/Language/pt/Common.php +++ b/modules/Admin/Language/pt/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Playing', ], 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', ]; diff --git a/modules/Admin/Language/it/Admin.php b/modules/Admin/Language/pt/Dashboard.php similarity index 73% rename from modules/Admin/Language/it/Admin.php rename to modules/Admin/Language/pt/Dashboard.php index 5e3942371f..7f28d24dfe 100644 --- a/modules/Admin/Language/it/Admin.php +++ b/modules/Admin/Language/pt/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Admin dashboard', + 'home' => 'Admin dashboard', 'welcome_message' => 'Welcome to the admin area!', - 'choose_interact' => 'Choose how to interact', ]; diff --git a/modules/Admin/Language/ru/Common.php b/modules/Admin/Language/ru/Common.php index d97bcf991f..a020253294 100644 --- a/modules/Admin/Language/ru/Common.php +++ b/modules/Admin/Language/ru/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Playing', ], 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Выберите как взаимодейÑтвовать', ]; diff --git a/modules/Admin/Language/ru/Admin.php b/modules/Admin/Language/ru/Dashboard.php similarity index 66% rename from modules/Admin/Language/ru/Admin.php rename to modules/Admin/Language/ru/Dashboard.php index 1babcd9fc6..102be71dd6 100644 --- a/modules/Admin/Language/ru/Admin.php +++ b/modules/Admin/Language/ru/Dashboard.php @@ -9,7 +9,6 @@ declare(strict_types=1); */ return [ - 'dashboard' => 'Панель ÐдминиÑтратора', + 'home' => 'Панель ÐдминиÑтратора', 'welcome_message' => 'Добро пожаловать в панель админиÑтрированиÑ!', - 'choose_interact' => 'Выберите как взаимодейÑтвовать', ]; diff --git a/modules/Admin/Language/sv/Admin.php b/modules/Admin/Language/sv/Admin.php deleted file mode 100644 index 5e3942371f..0000000000 --- a/modules/Admin/Language/sv/Admin.php +++ /dev/null @@ -1,15 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright 2020 Ad Aures - * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 - * @link https://castopod.org/ - */ - -return [ - 'dashboard' => 'Admin dashboard', - 'welcome_message' => 'Welcome to the admin area!', - 'choose_interact' => 'Choose how to interact', -]; diff --git a/modules/Admin/Language/sv/Common.php b/modules/Admin/Language/sv/Common.php index d97bcf991f..be498dacf3 100644 --- a/modules/Admin/Language/sv/Common.php +++ b/modules/Admin/Language/sv/Common.php @@ -46,4 +46,5 @@ return [ 'playing' => 'Playing', ], 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', ]; diff --git a/modules/Admin/Language/sv/Dashboard.php b/modules/Admin/Language/sv/Dashboard.php new file mode 100644 index 0000000000..7f28d24dfe --- /dev/null +++ b/modules/Admin/Language/sv/Dashboard.php @@ -0,0 +1,14 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2020 Ad Aures + * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 + * @link https://castopod.org/ + */ + +return [ + 'home' => 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', +]; diff --git a/modules/Analytics/Config/Routes.php b/modules/Analytics/Config/Routes.php index 1261e9abeb..352682eb18 100644 --- a/modules/Analytics/Config/Routes.php +++ b/modules/Analytics/Config/Routes.php @@ -19,7 +19,7 @@ $routes->addPlaceholder( ); $routes->addPlaceholder( 'filter', - '\bWeekly|\bYearly|\bByDay|\bByWeekday|\bByMonth|\bByAppWeekly|\bByAppYearly|\bByOsWeekly|\bByDeviceWeekly|\bBots|\bByServiceWeekly|\bBandwidthByDay|\bUniqueListenersByDay|\bUniqueListenersByMonth|\bTotalListeningTimeByDay|\bTotalListeningTimeByMonth|\bByDomainWeekly|\bByDomainYearly', + '\bWeekly|\bYearly|\bByDay|\bByWeekday|\bByMonth|\bByAppWeekly|\bByAppYearly|\bByOsWeekly|\bByDeviceWeekly|\bBots|\bByServiceWeekly|\bBandwidthByDay|\bUniqueListenersByDay|\bUniqueListenersByMonth|\bTotalListeningTimeByDay|\bTotalListeningTimeByMonth|\bByDomainWeekly|\bByDomainYearly|\bTotalBandwidthByMonth|\bTotalStorageByMonth', ); $routes->group('', [ @@ -53,6 +53,10 @@ $routes->group('', [ ); }); + $routes->get(config('Analytics')->gateway . '/(:class)/(:filter)', 'AnalyticsController::getData/$1/$2', [ + 'as' => 'analytics-data-instance', + ]); + // Route for podcast audio file analytics (/audio/pack(podcast_id,episode_id,bytes_threshold,filesize,duration,date)/podcast_folder/filename.mp3) $routes->head( 'audio/(:base64)/(:any)', diff --git a/modules/Analytics/Controllers/AnalyticsController.php b/modules/Analytics/Controllers/AnalyticsController.php index 06dfd1802b..fb0a03150a 100644 --- a/modules/Analytics/Controllers/AnalyticsController.php +++ b/modules/Analytics/Controllers/AnalyticsController.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace Modules\Analytics\Controllers; +use CodeIgniter\API\ResponseTrait; use CodeIgniter\Controller; use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\HTTP\ResponseInterface; @@ -17,6 +18,8 @@ use CodeIgniter\Model; class AnalyticsController extends Controller { + use ResponseTrait; + protected Model $analyticsModel; protected string $methodName = ''; @@ -27,6 +30,12 @@ class AnalyticsController extends Controller throw PageNotFoundException::forPageNotFound(); } + if (! is_numeric($params[0])) { + $this->analyticsModel = model('Analytics' . $params[0] . 'Model'); + $this->methodName = 'getData' . $params[1]; + return $this->{$method}(); + } + $this->analyticsModel = model('Analytics' . $params[1] . 'Model'); $this->methodName = 'getData' . (count($params) >= 3 ? $params[2] : ''); @@ -36,14 +45,18 @@ class AnalyticsController extends Controller ); } - public function getData(int $podcastId, ?int $episodeId = null): ResponseInterface + public function getData(?int $podcastId = null, ?int $episodeId = null): ResponseInterface { $methodName = $this->methodName; + if ($podcastId === null) { + return $this->respond($this->analyticsModel->{$methodName}()); + } + if ($episodeId === null) { - return $this->response->setJSON($this->analyticsModel->{$methodName}($podcastId)); + return $this->respond($this->analyticsModel->{$methodName}($podcastId)); } - return $this->response->setJSON($this->analyticsModel->{$methodName}($podcastId, $episodeId)); + return $this->respond($this->analyticsModel->{$methodName}($podcastId, $episodeId)); } } diff --git a/modules/Analytics/Models/AnalyticsPodcastModel.php b/modules/Analytics/Models/AnalyticsPodcastModel.php index 493dd5da31..fee1ae4452 100644 --- a/modules/Analytics/Models/AnalyticsPodcastModel.php +++ b/modules/Analytics/Models/AnalyticsPodcastModel.php @@ -12,6 +12,8 @@ declare(strict_types=1); namespace Modules\Analytics\Models; +use App\Entities\Media\BaseMedia; +use App\Models\MediaModel; use CodeIgniter\Model; use Modules\Analytics\Entities\AnalyticsPodcasts; @@ -93,7 +95,7 @@ class AnalyticsPodcastModel extends Model public function getDataBandwidthByDay(int $podcastId): array { if (! ($found = cache("{$podcastId}_analytics_podcast_by_bandwidth"))) { - $found = $this->select('date as labels, round(bandwidth / 1048576, 1) as `values`') + $found = $this->select('date as labels, ROUND(bandwidth / 1000000, 2) as `values`') ->where([ 'podcast_id' => $podcastId, 'date >' => date('Y-m-d', strtotime('-60 days')), @@ -235,4 +237,48 @@ class AnalyticsPodcastModel extends Model return $found; } + + /** + * Gets total bandwidth data for instance + * + * @return AnalyticsPodcasts[] + */ + public function getDataTotalBandwidthByMonth(): array + { + if (! ($found = cache('analytics_total_bandwidth_by_month'))) { + $found = $this->select( + 'DATE_FORMAT(updated_at,"%Y-%m") as labels, ROUND(sum(bandwidth) / 1000000, 2) as `values`' + ) + ->groupBy('labels') + ->orderBy('labels', 'ASC') + ->findAll(); + + cache() + ->save('analytics_total_bandwidth_by_month', $found, 600); + } + + return $found; + } + + /** + * Get total storage + * + * @return BaseMedia[] + */ + public function getDataTotalStorageByMonth(): array + { + if (! ($found = cache('analytics_total_storage_by_month'))) { + $found = (new MediaModel())->select( + 'DATE_FORMAT(uploaded_at,"%Y-%m") as labels, ROUND(sum(file_size) / 1000000, 2) as `values`' + ) + ->groupBy('labels') + ->orderBy('labels', 'ASC') + ->findAll(); + + cache() + ->save('analytics_total_storage_by_month', $found, 600); + } + + return $found; + } } diff --git a/themes/cp_admin/_partials/_nav_header.php b/themes/cp_admin/_partials/_nav_header.php index 8280862898..6b40fafce1 100644 --- a/themes/cp_admin/_partials/_nav_header.php +++ b/themes/cp_admin/_partials/_nav_header.php @@ -42,7 +42,7 @@ CODE_SAMPLE; } - $interactAsText = lang('Admin.choose_interact'); + $interactAsText = lang('Common.choose_interact'); $route = route_to('interact-as-actor'); $csrfField = csrf_field(); diff --git a/themes/cp_admin/_sidebar.php b/themes/cp_admin/_sidebar.php index 8f53e8153d..f557e5e9b4 100644 --- a/themes/cp_admin/_sidebar.php +++ b/themes/cp_admin/_sidebar.php @@ -1,6 +1,10 @@ <?php declare(strict_types=1); $navigation = [ + 'dashboard' => [ + 'icon' => 'dashboard', + 'items' => ['admin'], + ], 'podcasts' => [ 'icon' => 'mic', 'items' => ['podcast-list', 'podcast-create', 'podcast-import'], diff --git a/themes/cp_admin/dashboard.php b/themes/cp_admin/dashboard.php index 7dce6c0d1d..bebdc2d0a0 100644 --- a/themes/cp_admin/dashboard.php +++ b/themes/cp_admin/dashboard.php @@ -2,13 +2,42 @@ <?= $this->extend('_layout') ?> <?= $this->section('title') ?> -<?= lang('Admin.dashboard') ?> +<?= lang('Dashboard.home') ?> <?= $this->endSection() ?> <?= $this->section('pageTitle') ?> -<?= lang('Admin.dashboard') ?> +<?= lang('Dashboard.home') ?> <?= $this->endSection() ?> <?= $this->section('content') ?> -<?= lang('Admin.welcome_message') ?> + +<div class="flex flex-wrap items-start gap-4"> + <DashboardCard href="<?= route_to('podcast-list') ?>" glyph="mic" title="<?= lang('Dashboard.podcasts.title') ?>" subtitle="<?= $podcastsData['last_published_at'] ? esc(lang('Dashboard.podcasts.last_published', [ + 'lastPublicationDate' => local_date($podcastsData['last_published_at']), + ], null, false)) : lang('Dashboard.podcasts.not_found') ?>"><?= $podcastsData['number_of_podcasts'] ?></DashboardCard> + <DashboardCard href="<?= $onlyPodcastId === null ? '' : route_to('episode-list', $onlyPodcastId) ?>" glyph="play" title="<?= lang('Dashboard.episodes.title') ?>" subtitle="<?= $episodesData['last_published_at'] ? esc(lang('Dashboard.episodes.last_published', [ + 'lastPublicationDate' => local_date($episodesData['last_published_at']), + ], null, false)) : lang('Dashboard.episodes.not_found') ?>"><?= $episodesData['number_of_episodes'] ?></DashboardCard> + <DashboardCard glyph="database" title="<?= lang('Dashboard.storage.title') ?>" subtitle="<?= lang('Dashboard.storage.subtitle', [ + 'totalUploaded' => $storageData['total_uploaded'], + 'totalStorage' => $storageData['limit'], + ]) ?>"><?= $storageData['percentage'] ?>%</DashboardCard> +</div> + +<div class="grid grid-cols-1 gap-4 mt-4 lg:grid-cols-2"> + <Charts.XY class="col-span-1" title="<?= lang('Charts.total_storage_by_month') ?>" dataUrl="<?= route_to( + 'analytics-data-instance', + 'Podcast', + 'TotalStorageByMonth', + ) ?>" /> + <Charts.XY class="col-span-1" title="<?= lang('Charts.total_bandwidth_by_month') ?>" dataUrl="<?= route_to( + 'analytics-data-instance', + 'Podcast', + 'TotalBandwidthByMonth', + ) ?>" /> +</div> + + +<?= service('vite') + ->asset('js/charts.ts', 'js') ?> <?= $this->endsection() ?> diff --git a/themes/cp_admin/episode/create.php b/themes/cp_admin/episode/create.php index 61f050730b..a35ab5a884 100644 --- a/themes/cp_admin/episode/create.php +++ b/themes/cp_admin/episode/create.php @@ -21,12 +21,12 @@ name="audio_file" label="<?= lang('Episode.form.audio_file') ?>" hint="<?= lang('Episode.form.audio_file_hint') ?>" - helper="<?= lang('Common.size_limit', [formatBytes(file_upload_max_size())]) ?>" + helper="<?= lang('Common.size_limit', [formatBytes(file_upload_max_size(), true)]) ?>" type="file" accept=".mp3,.m4a" required="true" data-max-size="<?= file_upload_max_size() ?>" - data-max-size-error="<?= lang('Episode.form.file_size_error', [formatBytes(file_upload_max_size())]) ?>" /> + data-max-size-error="<?= lang('Episode.form.file_size_error', [formatBytes(file_upload_max_size(), true)]) ?>" /> <Forms.Field name="cover" diff --git a/themes/cp_admin/episode/edit.php b/themes/cp_admin/episode/edit.php index 9191635d31..64a78eef3a 100644 --- a/themes/cp_admin/episode/edit.php +++ b/themes/cp_admin/episode/edit.php @@ -25,11 +25,11 @@ name="audio_file" label="<?= lang('Episode.form.audio_file') ?>" hint="<?= lang('Episode.form.audio_file_hint') ?>" - helper="<?= lang('Common.size_limit', [formatBytes(file_upload_max_size())]) ?>" + helper="<?= lang('Common.size_limit', [formatBytes(file_upload_max_size(), true)]) ?>" type="file" accept=".mp3,.m4a" data-max-size="<?= file_upload_max_size() ?>" - data-max-size-error="<?= lang('Episode.form.file_size_error', [formatBytes(file_upload_max_size())]) ?>" /> + data-max-size-error="<?= lang('Episode.form.file_size_error', [formatBytes(file_upload_max_size(), true)]) ?>" /> <Forms.Field name="cover" diff --git a/themes/cp_admin/podcast/_sidebar.php b/themes/cp_admin/podcast/_sidebar.php index 619e1f4cf7..bbe873e889 100644 --- a/themes/cp_admin/podcast/_sidebar.php +++ b/themes/cp_admin/podcast/_sidebar.php @@ -6,7 +6,7 @@ $podcastNavigation = [ 'items' => ['podcast-view', 'podcast-edit', 'podcast-persons-manage'], ], 'episodes' => [ - 'icon' => 'mic', + 'icon' => 'play-circle', 'items' => ['episode-list', 'episode-create'], ], 'analytics' => [ diff --git a/themes/cp_app/_admin_navbar.php b/themes/cp_app/_admin_navbar.php index f2a4100426..690ac5909e 100644 --- a/themes/cp_app/_admin_navbar.php +++ b/themes/cp_app/_admin_navbar.php @@ -37,7 +37,7 @@ CODE_SAMPLE; } - $interactAsText = lang('Admin.choose_interact'); + $interactAsText = lang('Common.choose_interact'); $route = route_to('interact-as-actor'); $csrfField = csrf_field(); -- GitLab