From e95c61c7e5253267ce0ec24dc6d6812e450a6751 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Wed, 15 Jan 2025 15:00:53 +0100 Subject: [PATCH 01/37] Fix detail view --- application/controllers/DaemonsetController.php | 8 +++++++- application/controllers/DeploymentController.php | 7 ++++++- application/controllers/JobController.php | 7 ++++++- application/controllers/NodeController.php | 7 ++++++- application/controllers/PodController.php | 7 ++++++- application/controllers/ReplicasetController.php | 7 ++++++- application/controllers/StatefulsetController.php | 7 ++++++- library/Kubernetes/Common/BaseItemList.php | 6 +++++- library/Kubernetes/Web/CronJobDetail.php | 10 ++++++---- library/Kubernetes/Web/DaemonSetDetail.php | 10 ++++++---- library/Kubernetes/Web/DeploymentDetail.php | 10 ++++++---- library/Kubernetes/Web/EventDetail.php | 1 + library/Kubernetes/Web/JobDetail.php | 10 ++++++---- library/Kubernetes/Web/NamespaceDetail.php | 5 +++-- library/Kubernetes/Web/NodeDetail.php | 5 +++-- .../Kubernetes/Web/PersistentVolumeClaimDetail.php | 10 ++++++---- library/Kubernetes/Web/PersistentVolumeDetail.php | 10 ++++++---- library/Kubernetes/Web/PodDetail.php | 11 +++++------ library/Kubernetes/Web/ReplicaSetDetail.php | 10 ++++++---- library/Kubernetes/Web/ServiceDetail.php | 6 +++--- library/Kubernetes/Web/StatefulSetDetail.php | 10 ++++++---- 21 files changed, 111 insertions(+), 53 deletions(-) diff --git a/application/controllers/DaemonsetController.php b/application/controllers/DaemonsetController.php index 354239c1..6a392188 100644 --- a/application/controllers/DaemonsetController.php +++ b/application/controllers/DaemonsetController.php @@ -10,6 +10,7 @@ use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\DaemonSetDetail; use Icinga\Module\Kubernetes\Web\DaemonSetList; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -33,7 +34,12 @@ public function indexAction(): void $this->httpNotFound($this->translate('Daemon Set not found')); } - $this->addControl((new DaemonSetList([$daemonSet]))->setActionList(false)); + $this->addControl((new DaemonSetList([$daemonSet]))); + $this->addControl( + (new DaemonSetList([$daemonSet])) + ->setActionList(false) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ); $this->addContent(new DaemonSetDetail($daemonSet)); } diff --git a/application/controllers/DeploymentController.php b/application/controllers/DeploymentController.php index 3204668b..423c1003 100644 --- a/application/controllers/DeploymentController.php +++ b/application/controllers/DeploymentController.php @@ -10,6 +10,7 @@ use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\DeploymentDetail; use Icinga\Module\Kubernetes\Web\DeploymentList; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -33,7 +34,11 @@ public function indexAction(): void $this->httpNotFound($this->translate('Deployment not found')); } - $this->addControl((new DeploymentList([$deployment]))->setActionList(false)); + $this->addControl( + (new DeploymentList([$deployment])) + ->setActionList(false) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ); $this->addContent(new DeploymentDetail($deployment)); } diff --git a/application/controllers/JobController.php b/application/controllers/JobController.php index 9c61a37c..0aad33f5 100644 --- a/application/controllers/JobController.php +++ b/application/controllers/JobController.php @@ -10,6 +10,7 @@ use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\JobDetail; use Icinga\Module\Kubernetes\Web\JobList; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -33,7 +34,11 @@ public function indexAction(): void $this->httpNotFound($this->translate('Job not found')); } - $this->addControl((new JobList([$job]))->setActionList(false)); + $this->addControl( + (new JobList([$job])) + ->setActionList(false) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ); $this->addContent(new JobDetail($job)); } diff --git a/application/controllers/NodeController.php b/application/controllers/NodeController.php index b969e2c4..76a902ef 100644 --- a/application/controllers/NodeController.php +++ b/application/controllers/NodeController.php @@ -10,6 +10,7 @@ use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\NodeDetail; use Icinga\Module\Kubernetes\Web\NodeList; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -33,7 +34,11 @@ public function indexAction(): void $this->httpNotFound($this->translate('Node not found')); } - $this->addControl((new NodeList([$node]))->setActionList(false)); + $this->addControl( + (new NodeList([$node])) + ->setActionList(false) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ); $this->addContent(new NodeDetail($node)); } diff --git a/application/controllers/PodController.php b/application/controllers/PodController.php index 436b53c9..d055bba2 100644 --- a/application/controllers/PodController.php +++ b/application/controllers/PodController.php @@ -10,6 +10,7 @@ use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\PodDetail; use Icinga\Module\Kubernetes\Web\PodList; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -33,7 +34,11 @@ public function indexAction(): void $this->httpNotFound($this->translate('Pod not found')); } - $this->addControl((new PodList([$pod]))->setActionList(false)); + $this->addControl( + (new PodList([$pod])) + ->setActionList(false) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ); $this->addContent(new PodDetail($pod)); } diff --git a/application/controllers/ReplicasetController.php b/application/controllers/ReplicasetController.php index dd6bf81f..3d0f7fb6 100644 --- a/application/controllers/ReplicasetController.php +++ b/application/controllers/ReplicasetController.php @@ -10,6 +10,7 @@ use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\ReplicaSetDetail; use Icinga\Module\Kubernetes\Web\ReplicaSetList; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -33,7 +34,11 @@ public function indexAction(): void $this->httpNotFound($this->translate('Replica Set not found')); } - $this->addControl((new ReplicaSetList([$replicaSet]))->setActionList(false)); + $this->addControl( + (new ReplicaSetList([$replicaSet])) + ->setActionList(false) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ); $this->addContent(new ReplicaSetDetail($replicaSet)); } diff --git a/application/controllers/StatefulsetController.php b/application/controllers/StatefulsetController.php index 1ac28d0b..17f023c0 100644 --- a/application/controllers/StatefulsetController.php +++ b/application/controllers/StatefulsetController.php @@ -10,6 +10,7 @@ use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\StatefulSetDetail; use Icinga\Module\Kubernetes\Web\StatefulSetList; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -33,7 +34,11 @@ public function indexAction(): void $this->httpNotFound($this->translate('Stateful Set not found')); } - $this->addControl((new StatefulSetList([$statefulSet]))->setActionList(false)); + $this->addControl( + (new StatefulSetList([$statefulSet])) + ->setActionList(false) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ); $this->addContent(new StatefulSetDetail($statefulSet)); } diff --git a/library/Kubernetes/Common/BaseItemList.php b/library/Kubernetes/Common/BaseItemList.php index 7f2291af..77ee5e56 100644 --- a/library/Kubernetes/Common/BaseItemList.php +++ b/library/Kubernetes/Common/BaseItemList.php @@ -48,6 +48,7 @@ public function __construct(iterable $query) * property. * * @param bool $actionList + * * @return static */ public function setActionList(bool $actionList): static @@ -88,7 +89,10 @@ protected function assemble(): void Filter::equal('id', Uuid::fromBytes($item->uuid)->toString()) ) ]); - $listItem->setViewMode($this->getViewMode()); + + if ($this->getViewMode() !== null) { + $listItem->setViewMode($this->getViewMode()); + } $this->addHtml( $listItem diff --git a/library/Kubernetes/Web/CronJobDetail.php b/library/Kubernetes/Web/CronJobDetail.php index c9d0f90f..e5e9d7ea 100644 --- a/library/Kubernetes/Web/CronJobDetail.php +++ b/library/Kubernetes/Web/CronJobDetail.php @@ -68,10 +68,11 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Jobs'))), - new JobList(Auth::getInstance()->withRestrictions( + (new JobList(Auth::getInstance()->withRestrictions( Auth::SHOW_JOBS, $this->cronJob->job - )) + ))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } @@ -80,8 +81,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Events'))), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->cronJob->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->cronJob->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/DaemonSetDetail.php b/library/Kubernetes/Web/DaemonSetDetail.php index 1e49a2b8..591a72ed 100644 --- a/library/Kubernetes/Web/DaemonSetDetail.php +++ b/library/Kubernetes/Web/DaemonSetDetail.php @@ -89,10 +89,11 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Pods'))), - new PodList(Auth::getInstance()->withRestrictions( + (new PodList(Auth::getInstance()->withRestrictions( Auth::SHOW_PODS, $this->daemonSet->pod->with(['node']) - )) + ))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } @@ -101,8 +102,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Events'))), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->daemonSet->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->daemonSet->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/DeploymentDetail.php b/library/Kubernetes/Web/DeploymentDetail.php index 07bcef92..b9c397f7 100644 --- a/library/Kubernetes/Web/DeploymentDetail.php +++ b/library/Kubernetes/Web/DeploymentDetail.php @@ -91,10 +91,11 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Replica Sets'))), - new ReplicaSetList(Auth::getInstance()->withRestrictions( + (new ReplicaSetList(Auth::getInstance()->withRestrictions( Auth::SHOW_REPLICA_SETS, $this->deployment->replica_set - )) + ))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } @@ -103,8 +104,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Events'))), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->deployment->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->deployment->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/EventDetail.php b/library/Kubernetes/Web/EventDetail.php index 9f107008..88bd25c6 100644 --- a/library/Kubernetes/Web/EventDetail.php +++ b/library/Kubernetes/Web/EventDetail.php @@ -58,6 +58,7 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Referent'))), + // TODO fix with restrictions Factory::createList($this->event->reference_kind, Filter::equal('uuid', $this->event->reference_uuid)) ) ); diff --git a/library/Kubernetes/Web/JobDetail.php b/library/Kubernetes/Web/JobDetail.php index b77a64e6..b2344613 100644 --- a/library/Kubernetes/Web/JobDetail.php +++ b/library/Kubernetes/Web/JobDetail.php @@ -87,10 +87,11 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Pods'))), - new PodList(Auth::getInstance()->withRestrictions( + (new PodList(Auth::getInstance()->withRestrictions( Auth::SHOW_PODS, $this->job->pod->with(['node']) - )) + ))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } @@ -99,8 +100,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text('Events')), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->job->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->job->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/NamespaceDetail.php b/library/Kubernetes/Web/NamespaceDetail.php index 50c45b97..846afd35 100644 --- a/library/Kubernetes/Web/NamespaceDetail.php +++ b/library/Kubernetes/Web/NamespaceDetail.php @@ -55,8 +55,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Events'))), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->namespace->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->namespace->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/NodeDetail.php b/library/Kubernetes/Web/NodeDetail.php index 31426411..6421f912 100644 --- a/library/Kubernetes/Web/NodeDetail.php +++ b/library/Kubernetes/Web/NodeDetail.php @@ -101,8 +101,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Events'))), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->node->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->node->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/PersistentVolumeClaimDetail.php b/library/Kubernetes/Web/PersistentVolumeClaimDetail.php index b7f6deca..15a6cbfc 100644 --- a/library/Kubernetes/Web/PersistentVolumeClaimDetail.php +++ b/library/Kubernetes/Web/PersistentVolumeClaimDetail.php @@ -73,10 +73,11 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Pods'))), - new PodList(Auth::getInstance()->withRestrictions( + (new PodList(Auth::getInstance()->withRestrictions( Auth::SHOW_PODS, $this->pvc->pod - )) + ))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } @@ -85,8 +86,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Events'))), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->pvc->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->pvc->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/PersistentVolumeDetail.php b/library/Kubernetes/Web/PersistentVolumeDetail.php index 2abc1b15..9836de99 100644 --- a/library/Kubernetes/Web/PersistentVolumeDetail.php +++ b/library/Kubernetes/Web/PersistentVolumeDetail.php @@ -67,10 +67,11 @@ protected function assemble(): void 'section', new Attributes(['class' => 'persistent-volume-claims']), new HtmlElement('h2', null, new Text($this->translate('Claims'))), - new PersistentVolumeClaimList(Auth::getInstance()->withRestrictions( + (new PersistentVolumeClaimList(Auth::getInstance()->withRestrictions( Auth::SHOW_PERSISTENT_VOLUME_CLAIMS, $this->persistentVolume->pvc - )) + ))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } @@ -79,8 +80,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Events'))), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->persistentVolume->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->persistentVolume->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/PodDetail.php b/library/Kubernetes/Web/PodDetail.php index c38f7bd1..d84f90ca 100644 --- a/library/Kubernetes/Web/PodDetail.php +++ b/library/Kubernetes/Web/PodDetail.php @@ -13,7 +13,6 @@ use Icinga\Module\Kubernetes\Model\Container; use Icinga\Module\Kubernetes\Model\Event; use Icinga\Module\Kubernetes\Model\Pod; -use Icinga\Module\Kubernetes\Model\PodOwner; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; use ipl\Html\HtmlDocument; @@ -24,7 +23,6 @@ use ipl\Web\Widget\EmptyState; use ipl\Web\Widget\Icon; use ipl\Web\Widget\StateBall; -use Ramsey\Uuid\Uuid; class PodDetail extends BaseHtmlElement { @@ -123,10 +121,10 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Persistent Volume Claims'))), - new PersistentVolumeClaimList(Auth::getInstance()->withRestrictions( + (new PersistentVolumeClaimList(Auth::getInstance()->withRestrictions( Auth::SHOW_PERSISTENT_VOLUME_CLAIMS, $this->pod->pvc - )) + )))->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } @@ -135,8 +133,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text('Events')), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->pod->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->pod->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/ReplicaSetDetail.php b/library/Kubernetes/Web/ReplicaSetDetail.php index 5db81462..0d324150 100644 --- a/library/Kubernetes/Web/ReplicaSetDetail.php +++ b/library/Kubernetes/Web/ReplicaSetDetail.php @@ -82,10 +82,11 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Pods'))), - new PodList(Auth::getInstance()->withRestrictions( + (new PodList(Auth::getInstance()->withRestrictions( Auth::SHOW_PODS, $this->replicaSet->pod->with(['node']) - )) + ))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } @@ -94,8 +95,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Events'))), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->replicaSet->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->replicaSet->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } diff --git a/library/Kubernetes/Web/ServiceDetail.php b/library/Kubernetes/Web/ServiceDetail.php index 02ba67c3..3ef97936 100644 --- a/library/Kubernetes/Web/ServiceDetail.php +++ b/library/Kubernetes/Web/ServiceDetail.php @@ -10,7 +10,6 @@ use Icinga\Module\Kubernetes\Common\ResourceDetails; use Icinga\Module\Kubernetes\Model\Endpoint; use Icinga\Module\Kubernetes\Model\EndpointSlice; -use Icinga\Module\Kubernetes\Model\Ingress; use Icinga\Module\Kubernetes\Model\Pod; use Icinga\Module\Kubernetes\Model\Service; use Icinga\Module\Kubernetes\Model\ServicePort; @@ -101,10 +100,11 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Pods'))), - new PodList(Auth::getInstance()->withRestrictions( + (new PodList(Auth::getInstance()->withRestrictions( Auth::SHOW_PODS, $pods - )) + ))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } diff --git a/library/Kubernetes/Web/StatefulSetDetail.php b/library/Kubernetes/Web/StatefulSetDetail.php index ff272806..3a0ac51b 100644 --- a/library/Kubernetes/Web/StatefulSetDetail.php +++ b/library/Kubernetes/Web/StatefulSetDetail.php @@ -96,10 +96,11 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Pods'))), - new PodList(Auth::getInstance()->withRestrictions( + (new PodList(Auth::getInstance()->withRestrictions( Auth::SHOW_PODS, $this->statefulSet->pod->with(['node']) - )) + ))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) )); } @@ -108,8 +109,9 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Events'))), - new EventList(Event::on(Database::connection()) - ->filter(Filter::equal('reference_uuid', $this->statefulSet->uuid))) + (new EventList(Event::on(Database::connection()) + ->filter(Filter::equal('reference_uuid', $this->statefulSet->uuid)))) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_COMMON) )); } From 5f565386e2a800ac1a6810a1c4e8042d1dcc2a77 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Wed, 15 Jan 2025 15:35:18 +0100 Subject: [PATCH 02/37] Fix referents in event detail view --- library/Kubernetes/Web/EventDetail.php | 7 +- library/Kubernetes/Web/Factory.php | 121 +++++++++++++++++++++---- 2 files changed, 108 insertions(+), 20 deletions(-) diff --git a/library/Kubernetes/Web/EventDetail.php b/library/Kubernetes/Web/EventDetail.php index 88bd25c6..f59dcfb8 100644 --- a/library/Kubernetes/Web/EventDetail.php +++ b/library/Kubernetes/Web/EventDetail.php @@ -58,8 +58,11 @@ protected function assemble(): void 'section', null, new HtmlElement('h2', null, new Text($this->translate('Referent'))), - // TODO fix with restrictions - Factory::createList($this->event->reference_kind, Filter::equal('uuid', $this->event->reference_uuid)) + Factory::createList( + $this->event->reference_kind, + Filter::equal('uuid', $this->event->reference_uuid), + ViewModeSwitcher::VIEW_MODE_DETAILED + ) ) ); diff --git a/library/Kubernetes/Web/Factory.php b/library/Kubernetes/Web/Factory.php index cf253f0e..3f1d3cb5 100644 --- a/library/Kubernetes/Web/Factory.php +++ b/library/Kubernetes/Web/Factory.php @@ -60,7 +60,7 @@ public static function createIcon(string $kind): ?ValidHtml }; } - public static function createList(string $kind, Rule $filter): ValidHtml + public static function createList(string $kind, Rule $filter, $viewMode = null): ValidHtml { $kind = strtolower(str_replace(['_', '-'], '', $kind)); @@ -70,71 +70,156 @@ public static function createList(string $kind, Rule $filter): ValidHtml case 'configmap': $q = ConfigMap::on($database)->filter($filter); - return new ConfigMapList($q); + $list = new ConfigMapList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'container': $q = Container::on($database)->filter($filter); - return new ContainerList($q); + $list = new ContainerList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'cronjob': $q = CronJob::on($database)->filter($filter); - return new CronJobList($q); + $list = new CronJobList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'daemonset': $q = DaemonSet::on($database)->filter($filter); - return new DaemonSetList($q); + $list = new DaemonSetList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'deployment': $q = Deployment::on($database)->filter($filter); - return new DeploymentList($q); + $list = new DeploymentList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'event': $q = Event::on($database)->filter($filter); - return new EventList($q); + $list = new EventList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'ingress': $q = Ingress::on($database)->filter($filter); - return new IngressList($q); + $list = new IngressList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'job': $q = Job::on($database)->filter($filter); - return new JobList($q); + $list = new JobList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'namespace': $q = NamespaceModel::on($database)->filter($filter); - return new NamespaceList($q); + $list = new NamespaceList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'node': $q = Node::on($database)->filter($filter); - return new NodeList($q); + $list = new NodeList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'persistentvolume': $q = PersistentVolume::on($database)->filter($filter); - return new PersistentVolumeList($q); + $list = new PersistentVolumeList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'persistentvolumeclaim': $q = PersistentVolumeClaim::on($database)->filter($filter); - return new PersistentVolumeClaimList($q); + $list = new PersistentVolumeClaimList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'pod': $q = Pod::on($database)->filter($filter); - return new PodList($q); + $list = new PodList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'replicaset': $q = ReplicaSet::on($database)->filter($filter); - return new ReplicaSetList($q); + $list = new ReplicaSetList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'secret': $q = Secret::on($database)->filter($filter); - return new SecretList($q); + $list = new SecretList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'service': $q = Service::on($database)->filter($filter); - return new ServiceList($q); + $list = new ServiceList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; case 'statefulset': $q = StatefulSet::on($database)->filter($filter); - return new StatefulSetList($q); + $list = new StatefulSetList($q); + if (isset($viewMode)) { + $list->setViewMode($viewMode); + } + + return $list; default: return new EmptyState("No items to display. $kind seems to be a custom resource."); } From dc64ad06efe5d2dc070ff5c7de4fa56f6a762cc7 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 08:44:37 +0100 Subject: [PATCH 03/37] Remove redundant line --- application/controllers/DaemonsetController.php | 1 - 1 file changed, 1 deletion(-) diff --git a/application/controllers/DaemonsetController.php b/application/controllers/DaemonsetController.php index 6a392188..ca0bdcb5 100644 --- a/application/controllers/DaemonsetController.php +++ b/application/controllers/DaemonsetController.php @@ -34,7 +34,6 @@ public function indexAction(): void $this->httpNotFound($this->translate('Daemon Set not found')); } - $this->addControl((new DaemonSetList([$daemonSet]))); $this->addControl( (new DaemonSetList([$daemonSet])) ->setActionList(false) From 6866b0ca30287cad8f878ff4f97d6759d029bfa6 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 08:46:06 +0100 Subject: [PATCH 04/37] Add missing parameter and return type --- library/Kubernetes/Common/ViewMode.php | 2 +- library/Kubernetes/Web/ViewModeSwitcher.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/Kubernetes/Common/ViewMode.php b/library/Kubernetes/Common/ViewMode.php index 9cee0f05..25ef02e0 100644 --- a/library/Kubernetes/Common/ViewMode.php +++ b/library/Kubernetes/Common/ViewMode.php @@ -14,7 +14,7 @@ trait ViewMode * * @return ?string */ - public function getViewMode() + public function getViewMode(): string|null { return $this->viewMode; } diff --git a/library/Kubernetes/Web/ViewModeSwitcher.php b/library/Kubernetes/Web/ViewModeSwitcher.php index dc6b80b7..9a1f3363 100644 --- a/library/Kubernetes/Web/ViewModeSwitcher.php +++ b/library/Kubernetes/Web/ViewModeSwitcher.php @@ -130,7 +130,7 @@ public function getViewMode(): string * * @return $this */ - public function setViewMode(string $name) + public function setViewMode(string $name): self { $this->populate([$this->getViewModeParam() => $name]); @@ -151,7 +151,7 @@ public function setIdProtector(callable $protector): self return $this; } - private function protectId($id) + private function protectId(string $id): string { if (is_callable($this->protector)) { return call_user_func($this->protector, $id); From 6d7c9485685e47f5336ca8f36021823367dbf818 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 09:00:11 +0100 Subject: [PATCH 05/37] Use match expressions instead of if-else --- library/Kubernetes/Web/CronJobListItem.php | 13 ++++++++----- library/Kubernetes/Web/DaemonSetListItem.php | 13 ++++++++----- library/Kubernetes/Web/DeploymentListItem.php | 13 ++++++++----- library/Kubernetes/Web/EventListItem.php | 12 +++++++----- library/Kubernetes/Web/IngressListItem.php | 13 ++++++++----- library/Kubernetes/Web/JobListItem.php | 13 ++++++++----- library/Kubernetes/Web/NamespaceListItem.php | 13 ++++++++----- library/Kubernetes/Web/NodeListItem.php | 13 ++++++++----- .../Web/PersistentVolumeClaimListItem.php | 13 ++++++++----- library/Kubernetes/Web/PersistentVolumeListItem.php | 13 ++++++++----- library/Kubernetes/Web/PodListItem.php | 13 ++++++++----- library/Kubernetes/Web/ReplicaSetListItem.php | 13 ++++++++----- library/Kubernetes/Web/SecretListItem.php | 12 +++++++----- library/Kubernetes/Web/ServiceListItem.php | 13 ++++++++----- library/Kubernetes/Web/StatefulSetListItem.php | 13 ++++++++----- 15 files changed, 118 insertions(+), 75 deletions(-) diff --git a/library/Kubernetes/Web/CronJobListItem.php b/library/Kubernetes/Web/CronJobListItem.php index 02e5b3f3..f4c79d67 100644 --- a/library/Kubernetes/Web/CronJobListItem.php +++ b/library/Kubernetes/Web/CronJobListItem.php @@ -25,7 +25,9 @@ class CronJobListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -35,10 +37,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/DaemonSetListItem.php b/library/Kubernetes/Web/DaemonSetListItem.php index c1cdeea3..dead2229 100644 --- a/library/Kubernetes/Web/DaemonSetListItem.php +++ b/library/Kubernetes/Web/DaemonSetListItem.php @@ -26,7 +26,9 @@ class DaemonSetListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -36,10 +38,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/DeploymentListItem.php b/library/Kubernetes/Web/DeploymentListItem.php index 6bf6fda6..9afa2b14 100644 --- a/library/Kubernetes/Web/DeploymentListItem.php +++ b/library/Kubernetes/Web/DeploymentListItem.php @@ -26,7 +26,9 @@ class DeploymentListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -36,10 +38,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/EventListItem.php b/library/Kubernetes/Web/EventListItem.php index 8f06f503..61f3a538 100644 --- a/library/Kubernetes/Web/EventListItem.php +++ b/library/Kubernetes/Web/EventListItem.php @@ -25,7 +25,8 @@ class EventListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_MINIMAL) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL => $header->addHtml( Html::tag( 'span', @@ -35,10 +36,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_COMMON) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_COMMON => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/IngressListItem.php b/library/Kubernetes/Web/IngressListItem.php index a1dd4595..63fd3e24 100644 --- a/library/Kubernetes/Web/IngressListItem.php +++ b/library/Kubernetes/Web/IngressListItem.php @@ -24,7 +24,9 @@ class IngressListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -34,10 +36,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/JobListItem.php b/library/Kubernetes/Web/JobListItem.php index 29470735..d935d0c0 100644 --- a/library/Kubernetes/Web/JobListItem.php +++ b/library/Kubernetes/Web/JobListItem.php @@ -26,7 +26,9 @@ class JobListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -36,10 +38,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/NamespaceListItem.php b/library/Kubernetes/Web/NamespaceListItem.php index b9057e26..b740298a 100644 --- a/library/Kubernetes/Web/NamespaceListItem.php +++ b/library/Kubernetes/Web/NamespaceListItem.php @@ -36,7 +36,9 @@ class NamespaceListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -46,10 +48,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/NodeListItem.php b/library/Kubernetes/Web/NodeListItem.php index 271f6223..4347772a 100644 --- a/library/Kubernetes/Web/NodeListItem.php +++ b/library/Kubernetes/Web/NodeListItem.php @@ -25,7 +25,9 @@ class NodeListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -35,10 +37,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; } protected function assembleCaption(BaseHtmlElement $caption): void diff --git a/library/Kubernetes/Web/PersistentVolumeClaimListItem.php b/library/Kubernetes/Web/PersistentVolumeClaimListItem.php index b7d28d55..cfd16da7 100644 --- a/library/Kubernetes/Web/PersistentVolumeClaimListItem.php +++ b/library/Kubernetes/Web/PersistentVolumeClaimListItem.php @@ -39,7 +39,9 @@ protected function getPhaseIcon(): string protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -49,10 +51,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/PersistentVolumeListItem.php b/library/Kubernetes/Web/PersistentVolumeListItem.php index 10898add..65511af9 100644 --- a/library/Kubernetes/Web/PersistentVolumeListItem.php +++ b/library/Kubernetes/Web/PersistentVolumeListItem.php @@ -40,7 +40,9 @@ protected function getPhaseIcon(): string protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -50,10 +52,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/PodListItem.php b/library/Kubernetes/Web/PodListItem.php index ac904621..1402a52f 100644 --- a/library/Kubernetes/Web/PodListItem.php +++ b/library/Kubernetes/Web/PodListItem.php @@ -34,7 +34,9 @@ class PodListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -44,10 +46,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/ReplicaSetListItem.php b/library/Kubernetes/Web/ReplicaSetListItem.php index 1bd1d738..2727ec3b 100644 --- a/library/Kubernetes/Web/ReplicaSetListItem.php +++ b/library/Kubernetes/Web/ReplicaSetListItem.php @@ -26,7 +26,9 @@ class ReplicaSetListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -36,10 +38,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/SecretListItem.php b/library/Kubernetes/Web/SecretListItem.php index 36a15b96..e652cbd0 100644 --- a/library/Kubernetes/Web/SecretListItem.php +++ b/library/Kubernetes/Web/SecretListItem.php @@ -23,7 +23,8 @@ class SecretListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_MINIMAL) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL => $header->addHtml( Html::tag( 'span', @@ -33,10 +34,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_COMMON) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_COMMON => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/ServiceListItem.php b/library/Kubernetes/Web/ServiceListItem.php index d5abf5c3..ff7ace96 100644 --- a/library/Kubernetes/Web/ServiceListItem.php +++ b/library/Kubernetes/Web/ServiceListItem.php @@ -24,7 +24,9 @@ class ServiceListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -34,10 +36,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } diff --git a/library/Kubernetes/Web/StatefulSetListItem.php b/library/Kubernetes/Web/StatefulSetListItem.php index 03056b68..18fc54ac 100644 --- a/library/Kubernetes/Web/StatefulSetListItem.php +++ b/library/Kubernetes/Web/StatefulSetListItem.php @@ -36,7 +36,9 @@ class StatefulSetListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - if (in_array($this->getViewMode(), [ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON])) { + match ($this->getViewMode()) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( Html::tag( 'span', @@ -46,10 +48,11 @@ protected function assembleHeader(BaseHtmlElement $header): void $this->createCaption() ] ) - ); - } elseif ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $header->addHtml($this->createTitle()); - } + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); } From e4d309b5b50f0a83c2091bc0911a77415d7a434d Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 09:11:45 +0100 Subject: [PATCH 06/37] Use ->viewMode instead of ->getViewMode() --- library/Kubernetes/Common/BaseItemList.php | 4 ++-- library/Kubernetes/Web/CronJobListItem.php | 6 +++--- library/Kubernetes/Web/DaemonSetListItem.php | 6 +++--- library/Kubernetes/Web/DeploymentListItem.php | 6 +++--- library/Kubernetes/Web/EventListItem.php | 4 ++-- library/Kubernetes/Web/IngressListItem.php | 6 +++--- library/Kubernetes/Web/JobListItem.php | 6 +++--- library/Kubernetes/Web/NamespaceListItem.php | 6 +++--- library/Kubernetes/Web/NodeListItem.php | 6 +++--- library/Kubernetes/Web/PersistentVolumeClaimListItem.php | 6 +++--- library/Kubernetes/Web/PersistentVolumeListItem.php | 6 +++--- library/Kubernetes/Web/PodListItem.php | 6 +++--- library/Kubernetes/Web/ReplicaSetListItem.php | 6 +++--- library/Kubernetes/Web/SecretListItem.php | 4 ++-- library/Kubernetes/Web/ServiceListItem.php | 6 +++--- library/Kubernetes/Web/StatefulSetListItem.php | 6 +++--- 16 files changed, 45 insertions(+), 45 deletions(-) diff --git a/library/Kubernetes/Common/BaseItemList.php b/library/Kubernetes/Common/BaseItemList.php index 77ee5e56..d2b3ac69 100644 --- a/library/Kubernetes/Common/BaseItemList.php +++ b/library/Kubernetes/Common/BaseItemList.php @@ -90,8 +90,8 @@ protected function assemble(): void ) ]); - if ($this->getViewMode() !== null) { - $listItem->setViewMode($this->getViewMode()); + if ($this->viewMode !== null) { + $listItem->setViewMode($this->viewMode); } $this->addHtml( diff --git a/library/Kubernetes/Web/CronJobListItem.php b/library/Kubernetes/Web/CronJobListItem.php index f4c79d67..723399a2 100644 --- a/library/Kubernetes/Web/CronJobListItem.php +++ b/library/Kubernetes/Web/CronJobListItem.php @@ -25,7 +25,7 @@ class CronJobListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -56,11 +56,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/DaemonSetListItem.php b/library/Kubernetes/Web/DaemonSetListItem.php index dead2229..38f5b1ab 100644 --- a/library/Kubernetes/Web/DaemonSetListItem.php +++ b/library/Kubernetes/Web/DaemonSetListItem.php @@ -26,7 +26,7 @@ class DaemonSetListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -56,11 +56,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/DeploymentListItem.php b/library/Kubernetes/Web/DeploymentListItem.php index 9afa2b14..8499f6ef 100644 --- a/library/Kubernetes/Web/DeploymentListItem.php +++ b/library/Kubernetes/Web/DeploymentListItem.php @@ -26,7 +26,7 @@ class DeploymentListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -56,11 +56,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/EventListItem.php b/library/Kubernetes/Web/EventListItem.php index 61f3a538..d841eb64 100644 --- a/library/Kubernetes/Web/EventListItem.php +++ b/library/Kubernetes/Web/EventListItem.php @@ -25,7 +25,7 @@ class EventListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL => $header->addHtml( Html::tag( @@ -54,7 +54,7 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_COMMON) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_COMMON) { $main->addHtml($this->createCaption()); } } diff --git a/library/Kubernetes/Web/IngressListItem.php b/library/Kubernetes/Web/IngressListItem.php index 63fd3e24..ba87e330 100644 --- a/library/Kubernetes/Web/IngressListItem.php +++ b/library/Kubernetes/Web/IngressListItem.php @@ -24,7 +24,7 @@ class IngressListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -55,11 +55,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/JobListItem.php b/library/Kubernetes/Web/JobListItem.php index d935d0c0..46e4509d 100644 --- a/library/Kubernetes/Web/JobListItem.php +++ b/library/Kubernetes/Web/JobListItem.php @@ -26,7 +26,7 @@ class JobListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -56,11 +56,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/NamespaceListItem.php b/library/Kubernetes/Web/NamespaceListItem.php index b740298a..d378c2b9 100644 --- a/library/Kubernetes/Web/NamespaceListItem.php +++ b/library/Kubernetes/Web/NamespaceListItem.php @@ -36,7 +36,7 @@ class NamespaceListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -97,11 +97,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/NodeListItem.php b/library/Kubernetes/Web/NodeListItem.php index 4347772a..38e26301 100644 --- a/library/Kubernetes/Web/NodeListItem.php +++ b/library/Kubernetes/Web/NodeListItem.php @@ -25,7 +25,7 @@ class NodeListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -53,11 +53,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/PersistentVolumeClaimListItem.php b/library/Kubernetes/Web/PersistentVolumeClaimListItem.php index cfd16da7..7a4c144a 100644 --- a/library/Kubernetes/Web/PersistentVolumeClaimListItem.php +++ b/library/Kubernetes/Web/PersistentVolumeClaimListItem.php @@ -39,7 +39,7 @@ protected function getPhaseIcon(): string protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -69,11 +69,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/PersistentVolumeListItem.php b/library/Kubernetes/Web/PersistentVolumeListItem.php index 65511af9..cdec4f1c 100644 --- a/library/Kubernetes/Web/PersistentVolumeListItem.php +++ b/library/Kubernetes/Web/PersistentVolumeListItem.php @@ -40,7 +40,7 @@ protected function getPhaseIcon(): string protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -70,11 +70,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/PodListItem.php b/library/Kubernetes/Web/PodListItem.php index 1402a52f..35e8be18 100644 --- a/library/Kubernetes/Web/PodListItem.php +++ b/library/Kubernetes/Web/PodListItem.php @@ -34,7 +34,7 @@ class PodListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -64,11 +64,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/ReplicaSetListItem.php b/library/Kubernetes/Web/ReplicaSetListItem.php index 2727ec3b..b3ca3360 100644 --- a/library/Kubernetes/Web/ReplicaSetListItem.php +++ b/library/Kubernetes/Web/ReplicaSetListItem.php @@ -26,7 +26,7 @@ class ReplicaSetListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -56,11 +56,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/SecretListItem.php b/library/Kubernetes/Web/SecretListItem.php index e652cbd0..0e6116fa 100644 --- a/library/Kubernetes/Web/SecretListItem.php +++ b/library/Kubernetes/Web/SecretListItem.php @@ -23,7 +23,7 @@ class SecretListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL => $header->addHtml( Html::tag( @@ -47,7 +47,7 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_COMMON) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_COMMON) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/ServiceListItem.php b/library/Kubernetes/Web/ServiceListItem.php index ff7ace96..d885a70a 100644 --- a/library/Kubernetes/Web/ServiceListItem.php +++ b/library/Kubernetes/Web/ServiceListItem.php @@ -24,7 +24,7 @@ class ServiceListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -55,11 +55,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } diff --git a/library/Kubernetes/Web/StatefulSetListItem.php b/library/Kubernetes/Web/StatefulSetListItem.php index 18fc54ac..b71d89eb 100644 --- a/library/Kubernetes/Web/StatefulSetListItem.php +++ b/library/Kubernetes/Web/StatefulSetListItem.php @@ -36,7 +36,7 @@ class StatefulSetListItem extends BaseListItem protected function assembleHeader(BaseHtmlElement $header): void { - match ($this->getViewMode()) { + match ($this->viewMode) { ViewModeSwitcher::VIEW_MODE_MINIMAL, ViewModeSwitcher::VIEW_MODE_COMMON => $header->addHtml( @@ -66,11 +66,11 @@ protected function assembleMain(BaseHtmlElement $main): void { $main->addHtml($this->createHeader()); - if ($this->getViewMode() === ViewModeSwitcher::VIEW_MODE_DETAILED) { + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { $main->addHtml($this->createCaption()); } - if ($this->getViewMode() !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } } From e70a710422c02e88c09d631da509394558181fbd Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 09:24:25 +0100 Subject: [PATCH 07/37] Remove superfluous if statement --- library/Kubernetes/Web/Factory.php | 68 ++++++++---------------------- 1 file changed, 17 insertions(+), 51 deletions(-) diff --git a/library/Kubernetes/Web/Factory.php b/library/Kubernetes/Web/Factory.php index 3f1d3cb5..ffbe04de 100644 --- a/library/Kubernetes/Web/Factory.php +++ b/library/Kubernetes/Web/Factory.php @@ -71,153 +71,119 @@ public static function createList(string $kind, Rule $filter, $viewMode = null): $q = ConfigMap::on($database)->filter($filter); $list = new ConfigMapList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'container': $q = Container::on($database)->filter($filter); $list = new ContainerList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'cronjob': $q = CronJob::on($database)->filter($filter); $list = new CronJobList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'daemonset': $q = DaemonSet::on($database)->filter($filter); $list = new DaemonSetList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'deployment': $q = Deployment::on($database)->filter($filter); $list = new DeploymentList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'event': $q = Event::on($database)->filter($filter); $list = new EventList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'ingress': $q = Ingress::on($database)->filter($filter); $list = new IngressList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'job': $q = Job::on($database)->filter($filter); $list = new JobList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'namespace': $q = NamespaceModel::on($database)->filter($filter); $list = new NamespaceList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'node': $q = Node::on($database)->filter($filter); $list = new NodeList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'persistentvolume': $q = PersistentVolume::on($database)->filter($filter); $list = new PersistentVolumeList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'persistentvolumeclaim': $q = PersistentVolumeClaim::on($database)->filter($filter); $list = new PersistentVolumeClaimList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'pod': $q = Pod::on($database)->filter($filter); $list = new PodList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'replicaset': $q = ReplicaSet::on($database)->filter($filter); $list = new ReplicaSetList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'secret': $q = Secret::on($database)->filter($filter); $list = new SecretList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'service': $q = Service::on($database)->filter($filter); $list = new ServiceList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; case 'statefulset': $q = StatefulSet::on($database)->filter($filter); $list = new StatefulSetList($q); - if (isset($viewMode)) { - $list->setViewMode($viewMode); - } + $viewMode && $list->setViewMode($viewMode); return $list; default: From f279c66fa23c191329590a4166606b552822a9fb Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 09:39:53 +0100 Subject: [PATCH 08/37] Simplify namespace's caption and footer --- library/Kubernetes/Web/Factory.php | 1 + library/Kubernetes/Web/NamespaceListItem.php | 158 ++++++------------- 2 files changed, 47 insertions(+), 112 deletions(-) diff --git a/library/Kubernetes/Web/Factory.php b/library/Kubernetes/Web/Factory.php index ffbe04de..b192b05f 100644 --- a/library/Kubernetes/Web/Factory.php +++ b/library/Kubernetes/Web/Factory.php @@ -317,6 +317,7 @@ public static function fetchResource(string $kind): ?Query 'deployment' => Deployment::on($database), 'ingress' => Ingress::on($database), 'job' => Job::on($database), + 'persistentvolume' => PersistentVolume::on($database), 'persistentvolumeclaim' => PersistentVolumeClaim::on($database), 'pod' => Pod::on($database), 'replicaset' => ReplicaSet::on($database), diff --git a/library/Kubernetes/Web/NamespaceListItem.php b/library/Kubernetes/Web/NamespaceListItem.php index d378c2b9..ccd10471 100644 --- a/library/Kubernetes/Web/NamespaceListItem.php +++ b/library/Kubernetes/Web/NamespaceListItem.php @@ -5,18 +5,8 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; -use Icinga\Module\Kubernetes\Common\Database; use Icinga\Module\Kubernetes\Common\Links; -use Icinga\Module\Kubernetes\Model\DaemonSet; -use Icinga\Module\Kubernetes\Model\Deployment; -use Icinga\Module\Kubernetes\Model\Ingress; use Icinga\Module\Kubernetes\Model\NamespaceModel; -use Icinga\Module\Kubernetes\Model\PersistentVolume; -use Icinga\Module\Kubernetes\Model\PersistentVolumeClaim; -use Icinga\Module\Kubernetes\Model\Pod; -use Icinga\Module\Kubernetes\Model\ReplicaSet; -use Icinga\Module\Kubernetes\Model\Service; -use Icinga\Module\Kubernetes\Model\StatefulSet; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; @@ -59,32 +49,13 @@ protected function assembleHeader(BaseHtmlElement $header): void protected function assembleCaption(BaseHtmlElement $caption): void { - $resourceCount = DaemonSet::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); + $filter = $this->getResourceFilter(); + $resources = $this->getResourcesToCheck(); + $resourceCount = 0; - $resourceCount += Deployment::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $resourceCount += Ingress::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $resourceCount += PersistentVolume::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $resourceCount += PersistentVolumeClaim::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $resourceCount += Pod::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $resourceCount += ReplicaSet::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $resourceCount += Service::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $resourceCount += StateFulSet::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); + foreach ($resources as $resource => $_) { + $resourceCount += Factory::fetchResource($resource)->filter($filter)->count(); + } $caption->addHtml(Html::sprintf( $this->translate('Namespace %s has %s resources'), @@ -108,83 +79,16 @@ protected function assembleMain(BaseHtmlElement $main): void protected function assembleFooter(BaseHtmlElement $footer): void { - $resourceCount = DaemonSet::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $footer->addHtml(new HorizontalKeyValue( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-daemonset', 'title' => 'Daemon Sets'])), - $resourceCount - )); - - $resourceCount = Deployment::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $footer->addHtml(new HorizontalKeyValue( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-deployment', 'title' => 'Deployments'])), - $resourceCount - )); - - $resourceCount = Ingress::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $footer->addHtml(new HorizontalKeyValue( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-ingress', 'title' => 'Ingresses'])), - $resourceCount - )); - - $resourceCount = PersistentVolume::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $footer->addHtml(new HorizontalKeyValue( - new HtmlElement( - 'i', - new Attributes(['class' => 'icon kicon-persistentvolume', 'title' => 'Persistent Volumes']) - ), - $resourceCount - )); - - $resourceCount = PersistentVolumeClaim::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $footer->addHtml(new HorizontalKeyValue( - new HtmlElement( - 'i', - new Attributes(['class' => 'icon kicon-persistentvolumeclaim', 'title' => 'Persistent Volume Claims']) - ), - $resourceCount - )); - - $resourceCount = Pod::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $footer->addHtml(new HorizontalKeyValue( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-pod', 'title' => 'Pods'])), - $resourceCount - )); - - $resourceCount = ReplicaSet::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $footer->addHtml(new HorizontalKeyValue( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-replicaset', 'title' => 'Replica Sets'])), - $resourceCount - )); - - $resourceCount = Service::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $footer->addHtml(new HorizontalKeyValue( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-service', 'title' => 'Services'])), - $resourceCount - )); - - $resourceCount = StateFulSet::on(Database::connection()) - ->filter(Filter::equal('namespace', $this->item->name))->count(); - - $footer->addHtml(new HorizontalKeyValue( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-statefulset', 'title' => 'Stateful Sets'])), - $resourceCount - )); + $filter = $this->getResourceFilter(); + $resources = $this->getResourcesToCheck(); + + foreach ($resources as $resource => $title) { + $resourceCount = Factory::fetchResource($resource)->filter($filter)->count(); + $footer->addHtml(new HorizontalKeyValue( + new HtmlElement('i', new Attributes(['class' => "icon kicon-$resource", 'title' => $title])), + $resourceCount + )); + } } protected function assembleTitle(BaseHtmlElement $title): void @@ -211,4 +115,34 @@ protected function assembleVisual(BaseHtmlElement $visual): void $visual->addHtml(new StateBall('none', StateBall::SIZE_MEDIUM)); } } + + /** + * Get the filter to use for the resources + * + * @return Filter\Condition + */ + protected function getResourceFilter(): Filter\Condition + { + return Filter::equal('namespace', $this->item->name); + } + + /** + * Get the resources to check for the namespace + * + * @return string[] + */ + protected function getResourcesToCheck(): array + { + return [ + 'daemonset' => 'Daemon Sets', + 'deployment' => 'Deployments', + 'ingress' => 'Ingresses', + 'persistentvolume' => 'Persistent Volumes', + 'persistentvolumeclaim' => 'Persistent Volume Claims', + 'pod' => 'Pods', + 'replicaset' => 'Replica Sets', + 'service' => 'Services', + 'statefulset' => 'Stateful Sets' + ]; + } } From 215a04d9ebb51cb551e508cd37d750dcfed7a325 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 10:57:38 +0100 Subject: [PATCH 09/37] Use view mode constants --- application/controllers/ConfigmapsController.php | 3 ++- application/controllers/EventsController.php | 3 ++- application/controllers/SecretsController.php | 3 ++- library/Kubernetes/Web/ViewModeSwitcher.php | 10 +++++----- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/application/controllers/ConfigmapsController.php b/application/controllers/ConfigmapsController.php index e2950632..a20876af 100644 --- a/application/controllers/ConfigmapsController.php +++ b/application/controllers/ConfigmapsController.php @@ -9,6 +9,7 @@ use Icinga\Module\Kubernetes\Model\ConfigMap; use Icinga\Module\Kubernetes\Web\ConfigMapList; use Icinga\Module\Kubernetes\Web\ListController; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Orm\Query; class ConfigmapsController extends ListController @@ -44,6 +45,6 @@ protected function getPermission(): string protected function getIgnoredViewModes(): array { - return ['common', 'detailed']; + return [ViewModeSwitcher::VIEW_MODE_COMMON, ViewModeSwitcher::VIEW_MODE_DETAILED]; } } diff --git a/application/controllers/EventsController.php b/application/controllers/EventsController.php index 638a9186..b5600d63 100644 --- a/application/controllers/EventsController.php +++ b/application/controllers/EventsController.php @@ -9,6 +9,7 @@ use Icinga\Module\Kubernetes\Model\Event; use Icinga\Module\Kubernetes\Web\EventList; use Icinga\Module\Kubernetes\Web\ListController; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Orm\Query; use ipl\Stdlib\Filter; @@ -54,6 +55,6 @@ protected function getPermission(): string protected function getIgnoredViewModes(): array { - return ['detailed']; + return [ViewModeSwitcher::VIEW_MODE_DETAILED]; } } diff --git a/application/controllers/SecretsController.php b/application/controllers/SecretsController.php index 1602806b..ba2226e5 100644 --- a/application/controllers/SecretsController.php +++ b/application/controllers/SecretsController.php @@ -9,6 +9,7 @@ use Icinga\Module\Kubernetes\Model\Secret; use Icinga\Module\Kubernetes\Web\ListController; use Icinga\Module\Kubernetes\Web\SecretList; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Orm\Query; class SecretsController extends ListController @@ -44,6 +45,6 @@ protected function getPermission(): string protected function getIgnoredViewModes(): array { - return ['detailed']; + return [ViewModeSwitcher::VIEW_MODE_DETAILED]; } } diff --git a/library/Kubernetes/Web/ViewModeSwitcher.php b/library/Kubernetes/Web/ViewModeSwitcher.php index 9a1f3363..49f12302 100644 --- a/library/Kubernetes/Web/ViewModeSwitcher.php +++ b/library/Kubernetes/Web/ViewModeSwitcher.php @@ -31,17 +31,17 @@ class ViewModeSwitcher extends Form public const VIEW_MODE_DETAILED = 'detailed'; /** @var string Default view mode */ - public const DEFAULT_VIEW_MODE = 'common'; + public const DEFAULT_VIEW_MODE = self::VIEW_MODE_COMMON; /** @var string Default view mode param */ public const DEFAULT_VIEW_MODE_PARAM = 'view'; /** @var array View mode-icon pairs */ public static $viewModes = [ - 'minimal' => 'minimal', - 'common' => 'default', - 'detailed' => 'detailed', - 'tabular' => 'tabular' + self::VIEW_MODE_MINIMAL => 'minimal', + self::VIEW_MODE_COMMON => 'default', + self::VIEW_MODE_DETAILED => 'detailed', + 'tabular' => 'tabular' ]; /** @var string */ From efbad1f3c45d3f60b11aa54586b82e3351cfb274 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 11:02:07 +0100 Subject: [PATCH 10/37] Remove tabular view mode from ViewModeSwitcher --- library/Kubernetes/Web/ViewModeSwitcher.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/Kubernetes/Web/ViewModeSwitcher.php b/library/Kubernetes/Web/ViewModeSwitcher.php index 49f12302..c5b85f61 100644 --- a/library/Kubernetes/Web/ViewModeSwitcher.php +++ b/library/Kubernetes/Web/ViewModeSwitcher.php @@ -41,7 +41,6 @@ class ViewModeSwitcher extends Form self::VIEW_MODE_MINIMAL => 'minimal', self::VIEW_MODE_COMMON => 'default', self::VIEW_MODE_DETAILED => 'detailed', - 'tabular' => 'tabular' ]; /** @var string */ @@ -57,7 +56,7 @@ class ViewModeSwitcher extends Form protected $viewModeParam = self::DEFAULT_VIEW_MODE_PARAM; /** @var array */ - protected $ignoredViewModes = ['tabular']; + protected $ignoredViewModes = []; /** * Get the default mode From 4d4ee16c7b4014e272cefd8de4c511ac27725a81 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 11:02:29 +0100 Subject: [PATCH 11/37] Add docs for addIgnoredViewModes() --- library/Kubernetes/Web/ViewModeSwitcher.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/Kubernetes/Web/ViewModeSwitcher.php b/library/Kubernetes/Web/ViewModeSwitcher.php index c5b85f61..39d065a2 100644 --- a/library/Kubernetes/Web/ViewModeSwitcher.php +++ b/library/Kubernetes/Web/ViewModeSwitcher.php @@ -159,6 +159,13 @@ private function protectId(string $id): string return $id; } + /** + * Add view modes to be ignored + * + * @param string ...$viewModes + * + * @return $this + */ public function addIgnoredViewModes(string ...$viewModes): self { array_push($this->ignoredViewModes, ...$viewModes); From c75631cf256ffcb877e91238e5cc987643e43eb6 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 11:18:13 +0100 Subject: [PATCH 12/37] Hide view mode switcher Hide view mode switcher in the Web UI if all view modes are ignored or only one view mode is not ignored. --- library/Kubernetes/Web/ListController.php | 13 ++++++++++--- library/Kubernetes/Web/ViewModeSwitcher.php | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/library/Kubernetes/Web/ListController.php b/library/Kubernetes/Web/ListController.php index fc6a536e..78993a10 100644 --- a/library/Kubernetes/Web/ListController.php +++ b/library/Kubernetes/Web/ListController.php @@ -138,11 +138,18 @@ public function createViewModeSwitcher( LimitControl $limitControl, bool $verticalPagination = false ): ViewModeSwitcher { - $ignoredViewModes = $this->getIgnoredViewModes(); - $viewModeSwitcher = new ViewModeSwitcher(); $viewModeSwitcher->setIdProtector([$this->getRequest(), 'protectId']); - $viewModeSwitcher->addIgnoredViewModes(...$ignoredViewModes); + + $ignoredViewModes = $this->getIgnoredViewModes(); + + // Check if only one or no view mode should be selectable. If so don't show view mode switcher in the Web UI. + // This is the case if all view modes are ignored or only one view mode is not ignored. + if (count($ignoredViewModes) >= count(ViewModeSwitcher::$viewModes) - 1) { + $viewModeSwitcher->addIgnoredViewModes(...array_keys(ViewModeSwitcher::$viewModes)); + } else { + $viewModeSwitcher->addIgnoredViewModes(...$ignoredViewModes); + } $user = $this->Auth()->getUser(); if (($preferredModes = $user->getAdditional('kubernetes.view_modes')) === null) { diff --git a/library/Kubernetes/Web/ViewModeSwitcher.php b/library/Kubernetes/Web/ViewModeSwitcher.php index 39d065a2..c97a9514 100644 --- a/library/Kubernetes/Web/ViewModeSwitcher.php +++ b/library/Kubernetes/Web/ViewModeSwitcher.php @@ -169,6 +169,7 @@ private function protectId(string $id): string public function addIgnoredViewModes(string ...$viewModes): self { array_push($this->ignoredViewModes, ...$viewModes); + $this->ignoredViewModes = array_values(array_unique($this->ignoredViewModes)); return $this; } From dfb8ee1d9fc1e7ca4f6d1651de79a30ee0604edd Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 11:20:43 +0100 Subject: [PATCH 13/37] Format docs --- library/Kubernetes/Web/ListController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Kubernetes/Web/ListController.php b/library/Kubernetes/Web/ListController.php index 78993a10..cf42cacc 100644 --- a/library/Kubernetes/Web/ListController.php +++ b/library/Kubernetes/Web/ListController.php @@ -128,8 +128,8 @@ public function searchEditorAction(): void * This automatically shifts the view mode URL parameter from {@link $params}. * * @param PaginationControl $paginationControl - * @param LimitControl $limitControl - * @param bool $verticalPagination + * @param LimitControl $limitControl + * @param bool $verticalPagination * * @return ViewModeSwitcher */ From dd2767aefb62508e0ceecc1b75145fbd1ff7be27 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 16 Jan 2025 14:04:59 +0100 Subject: [PATCH 14/37] Fix license headers --- library/Kubernetes/Common/ViewMode.php | 2 +- library/Kubernetes/Web/ViewModeSwitcher.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Kubernetes/Common/ViewMode.php b/library/Kubernetes/Common/ViewMode.php index 25ef02e0..9fa622ad 100644 --- a/library/Kubernetes/Common/ViewMode.php +++ b/library/Kubernetes/Common/ViewMode.php @@ -1,6 +1,6 @@ Date: Tue, 21 Jan 2025 15:28:46 +0100 Subject: [PATCH 15/37] Pass db via argument Pass database via argument to fetchResource() instead of creating a new connection for each loop pass what can lead to an 'Too many connections' error. --- library/Kubernetes/Web/Factory.php | 5 +++-- library/Kubernetes/Web/NamespaceListItem.php | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/library/Kubernetes/Web/Factory.php b/library/Kubernetes/Web/Factory.php index b192b05f..f3b2e157 100644 --- a/library/Kubernetes/Web/Factory.php +++ b/library/Kubernetes/Web/Factory.php @@ -27,6 +27,7 @@ use ipl\Html\ValidHtml; use ipl\Orm\Model; use ipl\Orm\Query; +use ipl\Sql\Connection; use ipl\Stdlib\Filter\Rule; use ipl\Web\Url; use ipl\Web\Widget\EmptyState; @@ -303,11 +304,11 @@ public static function getKindFromModel(Model $model): string * * @return Query|null */ - public static function fetchResource(string $kind): ?Query + public static function fetchResource(string $kind, Connection $db = null): ?Query { $kind = strtolower(str_replace(['_', '-'], '', $kind)); - $database = Database::connection(); + $database = $db ?? Database::connection(); $query = match ($kind) { 'configmap' => ConfigMap::on($database), diff --git a/library/Kubernetes/Web/NamespaceListItem.php b/library/Kubernetes/Web/NamespaceListItem.php index ccd10471..e7ac2134 100644 --- a/library/Kubernetes/Web/NamespaceListItem.php +++ b/library/Kubernetes/Web/NamespaceListItem.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\Database; use Icinga\Module\Kubernetes\Common\Links; use Icinga\Module\Kubernetes\Model\NamespaceModel; use ipl\Html\Attributes; @@ -81,9 +82,10 @@ protected function assembleFooter(BaseHtmlElement $footer): void { $filter = $this->getResourceFilter(); $resources = $this->getResourcesToCheck(); + $db = Database::connection(); foreach ($resources as $resource => $title) { - $resourceCount = Factory::fetchResource($resource)->filter($filter)->count(); + $resourceCount = Factory::fetchResource($resource, $db)->filter($filter)->count(); $footer->addHtml(new HorizontalKeyValue( new HtmlElement('i', new Attributes(['class' => "icon kicon-$resource", 'title' => $title])), $resourceCount From 64f7f1d67dab402326a57bc45f575f856a48261e Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Wed, 22 Jan 2025 14:31:57 +0100 Subject: [PATCH 16/37] Make getIgnoredViewModes() not abstract anymore --- application/controllers/CronjobsController.php | 5 ----- application/controllers/DaemonsetsController.php | 5 ----- application/controllers/DeploymentsController.php | 5 ----- application/controllers/IngressesController.php | 5 ----- application/controllers/JobsController.php | 5 ----- application/controllers/NamespacesController.php | 5 ----- application/controllers/NodesController.php | 5 ----- application/controllers/PersistentvolumeclaimsController.php | 5 ----- application/controllers/PersistentvolumesController.php | 5 ----- application/controllers/PodsController.php | 5 ----- application/controllers/ReplicasetsController.php | 5 ----- application/controllers/ServicesController.php | 5 ----- application/controllers/StatefulsetsController.php | 5 ----- library/Kubernetes/Web/ListController.php | 5 ++++- 14 files changed, 4 insertions(+), 66 deletions(-) diff --git a/application/controllers/CronjobsController.php b/application/controllers/CronjobsController.php index 50be31ef..77a3d3dd 100644 --- a/application/controllers/CronjobsController.php +++ b/application/controllers/CronjobsController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_CRON_JOBS; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/DaemonsetsController.php b/application/controllers/DaemonsetsController.php index e5941bf8..59edd19f 100644 --- a/application/controllers/DaemonsetsController.php +++ b/application/controllers/DaemonsetsController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_DAEMON_SETS; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/DeploymentsController.php b/application/controllers/DeploymentsController.php index aa003954..8ec8d9f4 100644 --- a/application/controllers/DeploymentsController.php +++ b/application/controllers/DeploymentsController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_DEPLOYMENTS; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/IngressesController.php b/application/controllers/IngressesController.php index 15d21fac..430c69a8 100644 --- a/application/controllers/IngressesController.php +++ b/application/controllers/IngressesController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_INGRESSES; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/JobsController.php b/application/controllers/JobsController.php index 041daf4e..5451c7dc 100644 --- a/application/controllers/JobsController.php +++ b/application/controllers/JobsController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_JOBS; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/NamespacesController.php b/application/controllers/NamespacesController.php index 1719eb80..fe421176 100644 --- a/application/controllers/NamespacesController.php +++ b/application/controllers/NamespacesController.php @@ -40,9 +40,4 @@ protected function getPermission(): string { return Auth::SHOW_NAMESPACES; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/NodesController.php b/application/controllers/NodesController.php index 6e57ab4d..39e68740 100644 --- a/application/controllers/NodesController.php +++ b/application/controllers/NodesController.php @@ -40,9 +40,4 @@ protected function getPermission(): string { return Auth::SHOW_NODES; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/PersistentvolumeclaimsController.php b/application/controllers/PersistentvolumeclaimsController.php index e771d9f4..1890abc6 100644 --- a/application/controllers/PersistentvolumeclaimsController.php +++ b/application/controllers/PersistentvolumeclaimsController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_PERSISTENT_VOLUME_CLAIMS; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/PersistentvolumesController.php b/application/controllers/PersistentvolumesController.php index 58cffbf8..b3d9b738 100644 --- a/application/controllers/PersistentvolumesController.php +++ b/application/controllers/PersistentvolumesController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_PERSISTENT_VOLUMES; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/PodsController.php b/application/controllers/PodsController.php index cef598f8..d65861a2 100644 --- a/application/controllers/PodsController.php +++ b/application/controllers/PodsController.php @@ -43,9 +43,4 @@ protected function getPermission(): string { return Auth::SHOW_PODS; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/ReplicasetsController.php b/application/controllers/ReplicasetsController.php index 361cc64a..e46a0862 100644 --- a/application/controllers/ReplicasetsController.php +++ b/application/controllers/ReplicasetsController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_REPLICA_SETS; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/ServicesController.php b/application/controllers/ServicesController.php index 74082cc2..da904c81 100644 --- a/application/controllers/ServicesController.php +++ b/application/controllers/ServicesController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_SERVICES; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/application/controllers/StatefulsetsController.php b/application/controllers/StatefulsetsController.php index 43e2e054..7a7e639f 100644 --- a/application/controllers/StatefulsetsController.php +++ b/application/controllers/StatefulsetsController.php @@ -41,9 +41,4 @@ protected function getPermission(): string { return Auth::SHOW_STATEFUL_SETS; } - - protected function getIgnoredViewModes(): array - { - return []; - } } diff --git a/library/Kubernetes/Web/ListController.php b/library/Kubernetes/Web/ListController.php index cf42cacc..efba4f37 100644 --- a/library/Kubernetes/Web/ListController.php +++ b/library/Kubernetes/Web/ListController.php @@ -110,7 +110,10 @@ abstract protected function getContentClass(): string; abstract protected function getPermission(): string; - abstract protected function getIgnoredViewModes(): array; + protected function getIgnoredViewModes(): array + { + return []; + } public function searchEditorAction(): void { From 46a481f35761f5795b3c5a4f3aca0961a0407525 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Wed, 22 Jan 2025 14:49:08 +0100 Subject: [PATCH 17/37] Add function to canonicalize resource kinds --- library/Kubernetes/Web/Factory.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/Kubernetes/Web/Factory.php b/library/Kubernetes/Web/Factory.php index f3b2e157..e0b3d69d 100644 --- a/library/Kubernetes/Web/Factory.php +++ b/library/Kubernetes/Web/Factory.php @@ -35,9 +35,17 @@ abstract class Factory { + public static function canonicalizeKind(string $kind): string + { + if ($kind === 'pvc') { + return 'persistentvolumeclaim'; + } + return strtolower(str_replace(['_', '-'], '', $kind)); + } + public static function createIcon(string $kind): ?ValidHtml { - $kind = strtolower(str_replace(['_', '-'], '', $kind)); + $kind = self::canonicalizeKind($kind); return match ($kind) { 'configmap', From e8691edf4dfa1d5f7488dd777ca4b5a9d2d66113 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Wed, 22 Jan 2025 14:51:56 +0100 Subject: [PATCH 18/37] Add default traits for list item parts --- .../Common/DefaultListItemCaption.php | 14 ++++++ .../Common/DefaultListItemHeader.php | 35 +++++++++++++++ .../Kubernetes/Common/DefaultListItemMain.php | 22 ++++++++++ .../Common/DefaultListItemTitle.php | 44 +++++++++++++++++++ .../Common/DefaultListItemVisual.php | 16 +++++++ 5 files changed, 131 insertions(+) create mode 100644 library/Kubernetes/Common/DefaultListItemCaption.php create mode 100644 library/Kubernetes/Common/DefaultListItemHeader.php create mode 100644 library/Kubernetes/Common/DefaultListItemMain.php create mode 100644 library/Kubernetes/Common/DefaultListItemTitle.php create mode 100644 library/Kubernetes/Common/DefaultListItemVisual.php diff --git a/library/Kubernetes/Common/DefaultListItemCaption.php b/library/Kubernetes/Common/DefaultListItemCaption.php new file mode 100644 index 00000000..74d0dd23 --- /dev/null +++ b/library/Kubernetes/Common/DefaultListItemCaption.php @@ -0,0 +1,14 @@ +addHtml(new Text($this->item->icinga_state_reason)); + } +} diff --git a/library/Kubernetes/Common/DefaultListItemHeader.php b/library/Kubernetes/Common/DefaultListItemHeader.php new file mode 100644 index 00000000..b5b786dd --- /dev/null +++ b/library/Kubernetes/Common/DefaultListItemHeader.php @@ -0,0 +1,35 @@ +viewMode) { + ViewModeSwitcher::VIEW_MODE_MINIMAL, + ViewModeSwitcher::VIEW_MODE_COMMON => + $header->addHtml( + Html::tag( + 'span', + Attributes::create(['class' => 'header-minimal']), + [ + $this->createTitle(), + $this->createCaption() + ] + ) + ), + ViewModeSwitcher::VIEW_MODE_DETAILED => + $header->addHtml($this->createTitle()), + default => null + }; + + $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); + } +} diff --git a/library/Kubernetes/Common/DefaultListItemMain.php b/library/Kubernetes/Common/DefaultListItemMain.php new file mode 100644 index 00000000..55bf0236 --- /dev/null +++ b/library/Kubernetes/Common/DefaultListItemMain.php @@ -0,0 +1,22 @@ +addHtml($this->createHeader()); + + if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { + $main->addHtml($this->createCaption()); + } + + if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { + $main->addHtml($this->createFooter()); + } + } +} diff --git a/library/Kubernetes/Common/DefaultListItemTitle.php b/library/Kubernetes/Common/DefaultListItemTitle.php new file mode 100644 index 00000000..aa32b9dd --- /dev/null +++ b/library/Kubernetes/Common/DefaultListItemTitle.php @@ -0,0 +1,44 @@ +item->getTableAlias()); + $title->addHtml(Html::sprintf( + $this->translate('%s is %s', "<$kind> is "), + [ + new HtmlElement( + 'span', + new Attributes(['class' => 'namespace-badge']), + new HtmlElement('i', new Attributes(['class' => 'icon kicon-namespace'])), + new Text($this->item->namespace) + ), + new Link( + (new HtmlDocument())->addHtml( + new HtmlElement('i', new Attributes(['class' => "icon kicon-$kind"])), + new Text($this->item->name) + ), + Links::$kind($this->item), + new Attributes(['class' => 'subject']) + ) + ], + new HtmlElement( + 'span', + new Attributes(['class' => 'icinga-state-text']), + new Text($this->item->icinga_state) + ) + )); + } +} diff --git a/library/Kubernetes/Common/DefaultListItemVisual.php b/library/Kubernetes/Common/DefaultListItemVisual.php new file mode 100644 index 00000000..12ea6cda --- /dev/null +++ b/library/Kubernetes/Common/DefaultListItemVisual.php @@ -0,0 +1,16 @@ +addHtml(new StateBall($this->item->icinga_state, StateBall::SIZE_MEDIUM)); + } +} From 8e153ab383263e4afdcbe32dec801179a7a248c0 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Wed, 22 Jan 2025 14:56:20 +0100 Subject: [PATCH 19/37] Adjust function names to canonicalized kind names --- library/Kubernetes/Common/Links.php | 14 +++++++------- library/Kubernetes/Web/ConfigMapListItem.php | 2 +- library/Kubernetes/Web/ContainerMountTable.php | 2 +- library/Kubernetes/Web/CronJobListItem.php | 2 +- library/Kubernetes/Web/DaemonSetListItem.php | 2 +- .../Web/PersistentVolumeClaimListItem.php | 2 +- .../Kubernetes/Web/PersistentVolumeListItem.php | 2 +- library/Kubernetes/Web/ReplicaSetListItem.php | 2 +- library/Kubernetes/Web/StatefulSetListItem.php | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/library/Kubernetes/Common/Links.php b/library/Kubernetes/Common/Links.php index a0d98901..114ebcf0 100644 --- a/library/Kubernetes/Common/Links.php +++ b/library/Kubernetes/Common/Links.php @@ -28,7 +28,7 @@ abstract class Links { - public static function configMap(ConfigMap $configMap): Url + public static function configmap(ConfigMap $configMap): Url { return Url::fromPath('kubernetes/configmap', ['id' => (string) Uuid::fromBytes($configMap->uuid)]); } @@ -38,12 +38,12 @@ public static function container(Container $container): Url return Url::fromPath('kubernetes/container', ['id' => (string) Uuid::fromBytes($container->uuid)]); } - public static function cronJob(CronJob $cronjob): Url + public static function cronjob(CronJob $cronjob): Url { return Url::fromPath('kubernetes/cronjob', ['id' => (string) Uuid::fromBytes($cronjob->uuid)]); } - public static function daemonSet(DaemonSet $daemonSet): Url + public static function daemonset(DaemonSet $daemonSet): Url { return Url::fromPath('kubernetes/daemonset', ['id' => (string) Uuid::fromBytes($daemonSet->uuid)]); } @@ -83,7 +83,7 @@ public static function node(Node $node): Url return Url::fromPath('kubernetes/node', ['id' => (string) Uuid::fromBytes($node->uuid)]); } - public static function persistentVolume(PersistentVolume $persistentVolume): Url + public static function persistentvolume(PersistentVolume $persistentVolume): Url { return Url::fromPath( 'kubernetes/persistentvolume', @@ -96,7 +96,7 @@ public static function pod(Pod $pod): Url return Url::fromPath('kubernetes/pod', ['id' => (string) Uuid::fromBytes($pod->uuid)]); } - public static function pvc(PersistentVolumeClaim $persistentVolumeClaim): Url + public static function persistentvolumeclaim(PersistentVolumeClaim $persistentVolumeClaim): Url { return Url::fromPath( 'kubernetes/persistentvolumeclaim', @@ -104,7 +104,7 @@ public static function pvc(PersistentVolumeClaim $persistentVolumeClaim): Url ); } - public static function replicaSet(ReplicaSet $replicaSet): Url + public static function replicaset(ReplicaSet $replicaSet): Url { return Url::fromPath('kubernetes/replicaset', ['id' => (string) Uuid::fromBytes($replicaSet->uuid)]); } @@ -127,7 +127,7 @@ public static function sidecarContainer(SidecarContainer $sidecarContainer): Url ); } - public static function statefulSet(StatefulSet $statefulSet): Url + public static function statefulset(StatefulSet $statefulSet): Url { return Url::fromPath('kubernetes/statefulset', ['id' => (string) Uuid::fromBytes($statefulSet->uuid)]); } diff --git a/library/Kubernetes/Web/ConfigMapListItem.php b/library/Kubernetes/Web/ConfigMapListItem.php index d517a41e..d4e2ace6 100644 --- a/library/Kubernetes/Web/ConfigMapListItem.php +++ b/library/Kubernetes/Web/ConfigMapListItem.php @@ -43,7 +43,7 @@ protected function assembleTitle(BaseHtmlElement $title): void new HtmlElement('i', new Attributes(['class' => 'icon kicon-config-map'])), new Text($this->item->name) ), - Links::configMap($this->item), + Links::configmap($this->item), new Attributes(['class' => 'subject']) ) ); diff --git a/library/Kubernetes/Web/ContainerMountTable.php b/library/Kubernetes/Web/ContainerMountTable.php index 0f95ce6c..a2d4b24b 100644 --- a/library/Kubernetes/Web/ContainerMountTable.php +++ b/library/Kubernetes/Web/ContainerMountTable.php @@ -72,7 +72,7 @@ protected function assemble(): void if ($column === 'source') { $content = new Link( $podPvc->claim_name, - Links::pvc($pvc), + Links::persistentvolumeclaim($pvc), ['class' => 'subject'] ); } else { diff --git a/library/Kubernetes/Web/CronJobListItem.php b/library/Kubernetes/Web/CronJobListItem.php index 723399a2..df321c7d 100644 --- a/library/Kubernetes/Web/CronJobListItem.php +++ b/library/Kubernetes/Web/CronJobListItem.php @@ -102,7 +102,7 @@ protected function assembleTitle(BaseHtmlElement $title): void new HtmlElement('i', new Attributes(['class' => 'icon kicon-cronjob'])), new Text($this->item->name) ), - Links::cronJob($this->item), + Links::cronjob($this->item), new Attributes(['class' => 'subject']) ) ); diff --git a/library/Kubernetes/Web/DaemonSetListItem.php b/library/Kubernetes/Web/DaemonSetListItem.php index 38f5b1ab..8673b50a 100644 --- a/library/Kubernetes/Web/DaemonSetListItem.php +++ b/library/Kubernetes/Web/DaemonSetListItem.php @@ -116,7 +116,7 @@ protected function assembleTitle(BaseHtmlElement $title): void new HtmlElement('i', new Attributes(['class' => 'icon kicon-daemon-set'])), new Text($this->item->name) ), - Links::daemonSet($this->item), + Links::daemonset($this->item), new Attributes(['class' => 'subject']) ) ], diff --git a/library/Kubernetes/Web/PersistentVolumeClaimListItem.php b/library/Kubernetes/Web/PersistentVolumeClaimListItem.php index 7a4c144a..37f357c5 100644 --- a/library/Kubernetes/Web/PersistentVolumeClaimListItem.php +++ b/library/Kubernetes/Web/PersistentVolumeClaimListItem.php @@ -121,7 +121,7 @@ protected function assembleTitle(BaseHtmlElement $title): void new HtmlElement('i', new Attributes(['class' => 'icon kicon-pvc'])), new Text($this->item->name) ), - Links::pvc($this->item), + Links::persistentvolumeclaim($this->item), new Attributes(['class' => 'subject']) ) ], diff --git a/library/Kubernetes/Web/PersistentVolumeListItem.php b/library/Kubernetes/Web/PersistentVolumeListItem.php index cdec4f1c..9ea03860 100644 --- a/library/Kubernetes/Web/PersistentVolumeListItem.php +++ b/library/Kubernetes/Web/PersistentVolumeListItem.php @@ -111,7 +111,7 @@ protected function assembleTitle(BaseHtmlElement $title): void new HtmlElement('i', new Attributes(['class' => 'icon kicon-persistent-volume'])), new Text($this->item->name) ), - Links::persistentVolume($this->item), + Links::persistentvolume($this->item), new Attributes(['class' => 'subject']) ), new HtmlElement( diff --git a/library/Kubernetes/Web/ReplicaSetListItem.php b/library/Kubernetes/Web/ReplicaSetListItem.php index b3ca3360..e6f1a963 100644 --- a/library/Kubernetes/Web/ReplicaSetListItem.php +++ b/library/Kubernetes/Web/ReplicaSetListItem.php @@ -111,7 +111,7 @@ protected function assembleTitle(BaseHtmlElement $title): void new HtmlElement('i', new Attributes(['class' => 'icon kicon-replica-set'])), new Text($this->item->name) ), - Links::replicaSet($this->item), + Links::replicaset($this->item), new Attributes(['class' => 'subject']) ) ], diff --git a/library/Kubernetes/Web/StatefulSetListItem.php b/library/Kubernetes/Web/StatefulSetListItem.php index b71d89eb..6a406ff0 100644 --- a/library/Kubernetes/Web/StatefulSetListItem.php +++ b/library/Kubernetes/Web/StatefulSetListItem.php @@ -137,7 +137,7 @@ protected function assembleTitle(BaseHtmlElement $title): void new HtmlElement('i', new Attributes(['class' => 'icon kicon-stateful-set'])), new Text($this->item->name) ), - Links::statefulSet($this->item), + Links::statefulset($this->item), new Attributes(['class' => 'subject']) ) ], From 610011e75dffb60fa6781ecdeb75562b6c9773ea Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Wed, 22 Jan 2025 15:34:37 +0100 Subject: [PATCH 20/37] Use default traits for item list parts --- library/Kubernetes/Web/CronJobListItem.php | 45 ++------- library/Kubernetes/Web/DaemonSetListItem.php | 91 ++---------------- library/Kubernetes/Web/DeploymentListItem.php | 91 ++---------------- library/Kubernetes/Web/IngressListItem.php | 44 +-------- library/Kubernetes/Web/JobListItem.php | 90 ++---------------- library/Kubernetes/Web/NamespaceListItem.php | 41 +------- library/Kubernetes/Web/NodeListItem.php | 53 ++--------- .../Web/PersistentVolumeClaimListItem.php | 42 +-------- .../Web/PersistentVolumeListItem.php | 42 +-------- library/Kubernetes/Web/PodListItem.php | 93 ++----------------- library/Kubernetes/Web/ReplicaSetListItem.php | 91 ++---------------- library/Kubernetes/Web/ServiceListItem.php | 44 +-------- .../Kubernetes/Web/StatefulSetListItem.php | 91 ++---------------- 13 files changed, 98 insertions(+), 760 deletions(-) diff --git a/library/Kubernetes/Web/CronJobListItem.php b/library/Kubernetes/Web/CronJobListItem.php index df321c7d..4791d617 100644 --- a/library/Kubernetes/Web/CronJobListItem.php +++ b/library/Kubernetes/Web/CronJobListItem.php @@ -5,11 +5,12 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; use Icinga\Module\Kubernetes\Common\Icons; use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\Html; use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; use ipl\Html\Text; @@ -17,54 +18,19 @@ use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Link; use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class CronJobListItem extends BaseListItem { use Translation; - - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } + use DefaultListItemHeader; + use DefaultListItemMain; protected function assembleCaption(BaseHtmlElement $caption): void { - // TODO add state reason + // TODO add state reason then replace function by DefaultListItemCaption trait $caption->addHtml(new Text('Placeholder for Icinga State Reason')); } - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } - protected function assembleFooter(BaseHtmlElement $footer): void { if (isset($this->item->last_schedule_time)) { @@ -110,6 +76,7 @@ protected function assembleTitle(BaseHtmlElement $title): void protected function assembleVisual(BaseHtmlElement $visual): void { + // TODO add icinga state then replace function by DefaultListItemVisual trait $visual->addHtml(new StateBall('none', StateBall::SIZE_MEDIUM)); } } diff --git a/library/Kubernetes/Web/DaemonSetListItem.php b/library/Kubernetes/Web/DaemonSetListItem.php index 8673b50a..cacc5034 100644 --- a/library/Kubernetes/Web/DaemonSetListItem.php +++ b/library/Kubernetes/Web/DaemonSetListItem.php @@ -5,65 +5,27 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemCaption; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; +use Icinga\Module\Kubernetes\Common\DefaultListItemTitle; +use Icinga\Module\Kubernetes\Common\DefaultListItemVisual; use Icinga\Module\Kubernetes\Common\Format; -use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\Html; -use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; -use ipl\Html\Text; use ipl\I18n\Translation; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class DaemonSetListItem extends BaseListItem { use Translation; - - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } - - protected function assembleCaption(BaseHtmlElement $caption): void - { - $caption->addHtml(new Text($this->item->icinga_state_reason)); - } - - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } + use DefaultListItemHeader; + use DefaultListItemCaption; + use DefaultListItemMain; + use DefaultListItemTitle; + use DefaultListItemVisual; protected function assembleFooter(BaseHtmlElement $footer): void { @@ -99,37 +61,4 @@ protected function assembleFooter(BaseHtmlElement $footer): void ) ); } - - protected function assembleTitle(BaseHtmlElement $title): void - { - $title->addHtml(Html::sprintf( - $this->translate('%s is %s', ' is '), - [ - new HtmlElement( - 'span', - new Attributes(['class' => 'namespace-badge']), - new HtmlElement('i', new Attributes(['class' => 'icon kicon-namespace'])), - new Text($this->item->namespace) - ), - new Link( - (new HtmlDocument())->addHtml( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-daemon-set'])), - new Text($this->item->name) - ), - Links::daemonset($this->item), - new Attributes(['class' => 'subject']) - ) - ], - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->item->icinga_state) - ) - )); - } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - $visual->addHtml(new StateBall($this->item->icinga_state, StateBall::SIZE_MEDIUM)); - } } diff --git a/library/Kubernetes/Web/DeploymentListItem.php b/library/Kubernetes/Web/DeploymentListItem.php index 8499f6ef..8ddf4b56 100644 --- a/library/Kubernetes/Web/DeploymentListItem.php +++ b/library/Kubernetes/Web/DeploymentListItem.php @@ -5,65 +5,27 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemCaption; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; +use Icinga\Module\Kubernetes\Common\DefaultListItemTitle; +use Icinga\Module\Kubernetes\Common\DefaultListItemVisual; use Icinga\Module\Kubernetes\Common\Format; -use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\Html; -use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; -use ipl\Html\Text; use ipl\I18n\Translation; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class DeploymentListItem extends BaseListItem { use Translation; - - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } - - protected function assembleCaption(BaseHtmlElement $caption): void - { - $caption->addHtml(new Text($this->item->icinga_state_reason)); - } - - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } + use DefaultListItemHeader; + use DefaultListItemCaption; + use DefaultListItemMain; + use DefaultListItemTitle; + use DefaultListItemVisual; protected function assembleFooter(BaseHtmlElement $footer): void { @@ -103,37 +65,4 @@ protected function assembleFooter(BaseHtmlElement $footer): void ) ); } - - protected function assembleTitle(BaseHtmlElement $title): void - { - $title->addHtml(Html::sprintf( - $this->translate('%s is %s', ' is '), - [ - new HtmlElement( - 'span', - new Attributes(['class' => 'namespace-badge']), - new HtmlElement('i', new Attributes(['class' => 'icon kicon-namespace'])), - new Text($this->item->namespace) - ), - new Link( - (new HtmlDocument())->addHtml( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-deployment'])), - new Text($this->item->name) - ), - Links::deployment($this->item), - new Attributes(['class' => 'subject']) - ) - ], - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->item->icinga_state) - ) - )); - } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - $visual->addHtml(new StateBall($this->item->icinga_state, StateBall::SIZE_MEDIUM)); - } } diff --git a/library/Kubernetes/Web/IngressListItem.php b/library/Kubernetes/Web/IngressListItem.php index ba87e330..f829a862 100644 --- a/library/Kubernetes/Web/IngressListItem.php +++ b/library/Kubernetes/Web/IngressListItem.php @@ -5,10 +5,11 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\Html; use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; use ipl\Html\Text; @@ -16,54 +17,19 @@ use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Link; use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class IngressListItem extends BaseListItem { use Translation; - - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } + use DefaultListItemHeader; + use DefaultListItemMain; protected function assembleCaption(BaseHtmlElement $caption): void { - // TODO add state reason + // TODO add state reason then replace function by DefaultListItemCaption trait $caption->addHtml(new Text('Placeholder for Icinga State Reason')); } - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } - protected function assembleFooter(BaseHtmlElement $footer): void { $hosts = []; diff --git a/library/Kubernetes/Web/JobListItem.php b/library/Kubernetes/Web/JobListItem.php index 46e4509d..054d99bd 100644 --- a/library/Kubernetes/Web/JobListItem.php +++ b/library/Kubernetes/Web/JobListItem.php @@ -5,65 +5,28 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemCaption; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; +use Icinga\Module\Kubernetes\Common\DefaultListItemTitle; +use Icinga\Module\Kubernetes\Common\DefaultListItemVisual; use Icinga\Module\Kubernetes\Common\Format; -use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\Html; -use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; use ipl\Html\Text; use ipl\I18n\Translation; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class JobListItem extends BaseListItem { use Translation; - - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } - - protected function assembleCaption(BaseHtmlElement $caption): void - { - $caption->addHtml(new Text($this->item->icinga_state_reason)); - } - - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } + use DefaultListItemHeader; + use DefaultListItemCaption; + use DefaultListItemMain; + use DefaultListItemTitle; + use DefaultListItemVisual; protected function assembleFooter(BaseHtmlElement $footer): void { @@ -110,37 +73,4 @@ protected function assembleFooter(BaseHtmlElement $footer): void ) ); } - - protected function assembleTitle(BaseHtmlElement $title): void - { - $title->addHtml(Html::sprintf( - $this->translate('%s is %s', ' is '), - [ - new HtmlElement( - 'span', - new Attributes(['class' => 'namespace-badge']), - new HtmlElement('i', new Attributes(['class' => 'icon kicon-namespace'])), - new Text($this->item->namespace) - ), - new Link( - (new HtmlDocument())->addHtml( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-job'])), - new Text($this->item->name) - ), - Links::job($this->item), - new Attributes(['class' => 'subject']) - ) - ], - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->item->icinga_state) - ) - )); - } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - $visual->addHtml(new StateBall($this->item->icinga_state, StateBall::SIZE_MEDIUM)); - } } diff --git a/library/Kubernetes/Web/NamespaceListItem.php b/library/Kubernetes/Web/NamespaceListItem.php index e7ac2134..6a55d75d 100644 --- a/library/Kubernetes/Web/NamespaceListItem.php +++ b/library/Kubernetes/Web/NamespaceListItem.php @@ -6,6 +6,8 @@ use Icinga\Module\Kubernetes\Common\BaseListItem; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; use Icinga\Module\Kubernetes\Common\Links; use Icinga\Module\Kubernetes\Model\NamespaceModel; use ipl\Html\Attributes; @@ -19,34 +21,12 @@ use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Link; use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class NamespaceListItem extends BaseListItem { use Translation; - - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } + use DefaultListItemHeader; + use DefaultListItemMain; protected function assembleCaption(BaseHtmlElement $caption): void { @@ -65,19 +45,6 @@ protected function assembleCaption(BaseHtmlElement $caption): void )); } - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } - protected function assembleFooter(BaseHtmlElement $footer): void { $filter = $this->getResourceFilter(); diff --git a/library/Kubernetes/Web/NodeListItem.php b/library/Kubernetes/Web/NodeListItem.php index 38e26301..c907fe10 100644 --- a/library/Kubernetes/Web/NodeListItem.php +++ b/library/Kubernetes/Web/NodeListItem.php @@ -5,6 +5,10 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemCaption; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; +use Icinga\Module\Kubernetes\Common\DefaultListItemVisual; use Icinga\Module\Kubernetes\Common\Links; use Icinga\Util\Format; use ipl\Html\Attributes; @@ -17,50 +21,14 @@ use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; class NodeListItem extends BaseListItem { use Translation; - - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - } - - protected function assembleCaption(BaseHtmlElement $caption): void - { - $caption->addHtml(new Text($this->item->icinga_state_reason)); - } - - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } + use DefaultListItemHeader; + use DefaultListItemCaption; + use DefaultListItemMain; + use DefaultListItemVisual; protected function assembleFooter(BaseHtmlElement $footer): void { @@ -96,9 +64,4 @@ protected function assembleTitle(BaseHtmlElement $title): void ) )); } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - $visual->addHtml(new StateBall($this->item->icinga_state, StateBall::SIZE_MEDIUM)); - } } diff --git a/library/Kubernetes/Web/PersistentVolumeClaimListItem.php b/library/Kubernetes/Web/PersistentVolumeClaimListItem.php index 37f357c5..f68db88c 100644 --- a/library/Kubernetes/Web/PersistentVolumeClaimListItem.php +++ b/library/Kubernetes/Web/PersistentVolumeClaimListItem.php @@ -6,6 +6,8 @@ use Icinga\Module\Kubernetes\Common\AccessModes; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; use Icinga\Module\Kubernetes\Common\Icons; use Icinga\Module\Kubernetes\Common\Links; use Icinga\Module\Kubernetes\Model\PersistentVolumeClaim; @@ -21,11 +23,12 @@ use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; use ipl\Web\Widget\Link; -use ipl\Web\Widget\TimeAgo; class PersistentVolumeClaimListItem extends BaseListItem { use Translation; + use DefaultListItemHeader; + use DefaultListItemMain; protected function getPhaseIcon(): string { @@ -37,47 +40,12 @@ protected function getPhaseIcon(): string }; } - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } - protected function assembleCaption(BaseHtmlElement $caption): void { + // TODO add state reason then replace function by DefaultListItemCaption trait $caption->addHtml(new Text('Placeholder for Icinga State Reason')); } - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } - protected function assembleFooter(BaseHtmlElement $footer): void { $footer->addHtml( diff --git a/library/Kubernetes/Web/PersistentVolumeListItem.php b/library/Kubernetes/Web/PersistentVolumeListItem.php index 9ea03860..fece890f 100644 --- a/library/Kubernetes/Web/PersistentVolumeListItem.php +++ b/library/Kubernetes/Web/PersistentVolumeListItem.php @@ -6,6 +6,8 @@ use Icinga\Module\Kubernetes\Common\AccessModes; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; use Icinga\Module\Kubernetes\Common\Icons; use Icinga\Module\Kubernetes\Common\Links; use Icinga\Module\Kubernetes\Model\PersistentVolume; @@ -20,11 +22,12 @@ use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; use ipl\Web\Widget\Link; -use ipl\Web\Widget\TimeAgo; class PersistentVolumeListItem extends BaseListItem { use Translation; + use DefaultListItemHeader; + use DefaultListItemMain; protected function getPhaseIcon(): string { @@ -38,47 +41,12 @@ protected function getPhaseIcon(): string }; } - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } - protected function assembleCaption(BaseHtmlElement $caption): void { + // TODO add state reason then replace function by DefaultListItemCaption trait $caption->addHtml(new Text('Placeholder for Icinga State Reason')); } - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } - protected function assembleFooter(BaseHtmlElement $footer): void { $footer->addHtml( diff --git a/library/Kubernetes/Web/PodListItem.php b/library/Kubernetes/Web/PodListItem.php index 35e8be18..d97c9c38 100644 --- a/library/Kubernetes/Web/PodListItem.php +++ b/library/Kubernetes/Web/PodListItem.php @@ -5,26 +5,27 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; -use Icinga\Module\Kubernetes\Common\Links; +use Icinga\Module\Kubernetes\Common\DefaultListItemCaption; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; +use Icinga\Module\Kubernetes\Common\DefaultListItemTitle; +use Icinga\Module\Kubernetes\Common\DefaultListItemVisual; use Icinga\Module\Kubernetes\Model\Container; use Icinga\Module\Kubernetes\Model\InitContainer; use Icinga\Module\Kubernetes\Model\SidecarContainer; -use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\Html; -use ipl\Html\HtmlDocument; -use ipl\Html\HtmlElement; -use ipl\Html\Text; use ipl\I18n\Translation; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class PodListItem extends BaseListItem { use Translation; + use DefaultListItemHeader; + use DefaultListItemCaption; + use DefaultListItemMain; + use DefaultListItemTitle; + use DefaultListItemVisual; public const QOS_ICONS = [ 'BestEffort' => 'eraser', @@ -32,47 +33,6 @@ class PodListItem extends BaseListItem 'Guaranteed' => 'heart-pulse' ]; - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } - - protected function assembleCaption(BaseHtmlElement $caption): void - { - $caption->addHtml(new Text($this->item->icinga_state_reason)); - } - - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } - protected function assembleFooter(BaseHtmlElement $footer): void { $containerRestarts = 0; @@ -132,37 +92,4 @@ protected function assembleFooter(BaseHtmlElement $footer): void new HorizontalKeyValue(new Icon('share-nodes'), $this->item->node_name ?? $this->translate('None')) ); } - - protected function assembleTitle(BaseHtmlElement $title): void - { - $title->addHtml(Html::sprintf( - $this->translate('%s is %s', ' is '), - [ - new HtmlElement( - 'span', - new Attributes(['class' => 'namespace-badge']), - new HtmlElement('i', new Attributes(['class' => 'icon kicon-namespace'])), - new Text($this->item->namespace) - ), - new Link( - (new HtmlDocument())->addHtml( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-pod'])), - new Text($this->item->name) - ), - Links::pod($this->item), - new Attributes(['class' => 'subject']) - ) - ], - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->item->icinga_state) - ) - )); - } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - $visual->addHtml(new StateBall($this->item->icinga_state, StateBall::SIZE_MEDIUM)); - } } diff --git a/library/Kubernetes/Web/ReplicaSetListItem.php b/library/Kubernetes/Web/ReplicaSetListItem.php index e6f1a963..8cb0c430 100644 --- a/library/Kubernetes/Web/ReplicaSetListItem.php +++ b/library/Kubernetes/Web/ReplicaSetListItem.php @@ -5,65 +5,27 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemCaption; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; +use Icinga\Module\Kubernetes\Common\DefaultListItemTitle; +use Icinga\Module\Kubernetes\Common\DefaultListItemVisual; use Icinga\Module\Kubernetes\Common\Format; -use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\Html; -use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; -use ipl\Html\Text; use ipl\I18n\Translation; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class ReplicaSetListItem extends BaseListItem { use Translation; - - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } - - protected function assembleCaption(BaseHtmlElement $caption): void - { - $caption->addHtml(new Text($this->item->icinga_state_reason)); - } - - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } + use DefaultListItemHeader; + use DefaultListItemCaption; + use DefaultListItemMain; + use DefaultListItemTitle; + use DefaultListItemVisual; protected function assembleFooter(BaseHtmlElement $footer): void { @@ -94,37 +56,4 @@ protected function assembleFooter(BaseHtmlElement $footer): void ), ); } - - protected function assembleTitle(BaseHtmlElement $title): void - { - $title->addHtml(Html::sprintf( - $this->translate('%s is %s', ' is '), - [ - new HtmlElement( - 'span', - new Attributes(['class' => 'namespace-badge']), - new HtmlElement('i', new Attributes(['class' => 'icon kicon-namespace'])), - new Text($this->item->namespace) - ), - new Link( - (new HtmlDocument())->addHtml( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-replica-set'])), - new Text($this->item->name) - ), - Links::replicaset($this->item), - new Attributes(['class' => 'subject']) - ) - ], - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->item->icinga_state) - ) - )); - } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - $visual->addHtml(new StateBall($this->item->icinga_state, StateBall::SIZE_MEDIUM)); - } } diff --git a/library/Kubernetes/Web/ServiceListItem.php b/library/Kubernetes/Web/ServiceListItem.php index d885a70a..d88f1c01 100644 --- a/library/Kubernetes/Web/ServiceListItem.php +++ b/library/Kubernetes/Web/ServiceListItem.php @@ -5,10 +5,11 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\Html; use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; use ipl\Html\Text; @@ -16,54 +17,19 @@ use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Link; use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class ServiceListItem extends BaseListItem { use Translation; - - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } + use DefaultListItemHeader; + use DefaultListItemMain; protected function assembleCaption(BaseHtmlElement $caption): void { - // TODO add state reason + // TODO add state reason then replace function by DefaultListItemCaption trait $caption->addHtml(new Text('Placeholder for Icinga State Reason')); } - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } - protected function assembleFooter(BaseHtmlElement $footer): void { $footer->addHtml( diff --git a/library/Kubernetes/Web/StatefulSetListItem.php b/library/Kubernetes/Web/StatefulSetListItem.php index 6a406ff0..b493f250 100644 --- a/library/Kubernetes/Web/StatefulSetListItem.php +++ b/library/Kubernetes/Web/StatefulSetListItem.php @@ -5,24 +5,27 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemCaption; +use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; +use Icinga\Module\Kubernetes\Common\DefaultListItemMain; +use Icinga\Module\Kubernetes\Common\DefaultListItemTitle; +use Icinga\Module\Kubernetes\Common\DefaultListItemVisual; use Icinga\Module\Kubernetes\Common\Format; -use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\Html; -use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; -use ipl\Html\Text; use ipl\I18n\Translation; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; -use ipl\Web\Widget\TimeAgo; class StatefulSetListItem extends BaseListItem { use Translation; + use DefaultListItemHeader; + use DefaultListItemCaption; + use DefaultListItemMain; + use DefaultListItemTitle; + use DefaultListItemVisual; public const UPDATE_STRATEGY_ICONS = [ 'RollingUpdate' => 'repeat', @@ -34,47 +37,6 @@ class StatefulSetListItem extends BaseListItem 'Parallel' => 'grip-lines' ]; - protected function assembleHeader(BaseHtmlElement $header): void - { - match ($this->viewMode) { - ViewModeSwitcher::VIEW_MODE_MINIMAL, - ViewModeSwitcher::VIEW_MODE_COMMON => - $header->addHtml( - Html::tag( - 'span', - Attributes::create(['class' => 'header-minimal']), - [ - $this->createTitle(), - $this->createCaption() - ] - ) - ), - ViewModeSwitcher::VIEW_MODE_DETAILED => - $header->addHtml($this->createTitle()), - default => null - }; - - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); - } - - protected function assembleCaption(BaseHtmlElement $caption): void - { - $caption->addHtml(new Text($this->item->icinga_state_reason)); - } - - protected function assembleMain(BaseHtmlElement $main): void - { - $main->addHtml($this->createHeader()); - - if ($this->viewMode === ViewModeSwitcher::VIEW_MODE_DETAILED) { - $main->addHtml($this->createCaption()); - } - - if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { - $main->addHtml($this->createFooter()); - } - } - protected function assembleFooter(BaseHtmlElement $footer): void { $pods = (new ItemCountIndicator()) @@ -120,37 +82,4 @@ protected function assembleFooter(BaseHtmlElement $footer): void ]) ); } - - protected function assembleTitle(BaseHtmlElement $title): void - { - $title->addHtml(Html::sprintf( - $this->translate('%s is %s', ' is '), - [ - new HtmlElement( - 'span', - new Attributes(['class' => 'namespace-badge']), - new HtmlElement('i', new Attributes(['class' => 'icon kicon-namespace'])), - new Text($this->item->namespace) - ), - new Link( - (new HtmlDocument())->addHtml( - new HtmlElement('i', new Attributes(['class' => 'icon kicon-stateful-set'])), - new Text($this->item->name) - ), - Links::statefulset($this->item), - new Attributes(['class' => 'subject']) - ) - ], - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->item->icinga_state) - ) - )); - } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - $visual->addHtml(new StateBall($this->item->icinga_state, StateBall::SIZE_MEDIUM)); - } } From 8530c79ebb7ad5b4a33e6044d6308b02007f51ca Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Fri, 28 Feb 2025 10:32:54 +0100 Subject: [PATCH 21/37] Add styles for list items --- library/Kubernetes/Common/BaseItemList.php | 1 + public/css/lists.less | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/library/Kubernetes/Common/BaseItemList.php b/library/Kubernetes/Common/BaseItemList.php index d2b3ac69..34e5716b 100644 --- a/library/Kubernetes/Common/BaseItemList.php +++ b/library/Kubernetes/Common/BaseItemList.php @@ -72,6 +72,7 @@ protected function assemble(): void $itemClass = $this->getItemClass(); $this->addAttributes($this->baseAttributes); + $this->addAttributes(['class' => $this->viewMode]); foreach ($this->query as $item) { if (! $detailUrlAdded) { $this->addAttributes(['class' => 'action-list'] + [ diff --git a/public/css/lists.less b/public/css/lists.less index 8db9e5eb..f3652d69 100644 --- a/public/css/lists.less +++ b/public/css/lists.less @@ -71,6 +71,8 @@ footer { .title { .text-ellipsis(); + height: 1.5em; + > .subject + .subject { margin-left: .2em; } @@ -80,9 +82,18 @@ footer { } } +.item-list.minimal .visual { + width: 2.2em; +} + .visual { - font-size: 1.5em; - justify-content: flex-start; + > .state-ball { + font-size: 1.5em; + } + + // Calculate the padding so that the icon is vertically centered in the minimal view, + // but has the same top padding in all other views. + padding: ~"calc((30px - (12px * 0.75 * 1.5)) / 2)" 0; } .config-map-list, From c700c0bf14c3ad5fa7a3f890f808544c245efdb1 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Wed, 18 Dec 2024 09:22:46 +0100 Subject: [PATCH 22/37] Use DetailState in resource details --- library/Kubernetes/Web/ContainerDetail.php | 10 +---- library/Kubernetes/Web/DaemonSetDetail.php | 11 +---- library/Kubernetes/Web/DeploymentDetail.php | 11 +---- library/Kubernetes/Web/DetailState.php | 40 +++++++++++++++++++ library/Kubernetes/Web/IcingaStateReason.php | 14 +++---- .../Kubernetes/Web/InitContainerDetail.php | 10 +---- library/Kubernetes/Web/JobDetail.php | 11 +---- library/Kubernetes/Web/NodeDetail.php | 11 +---- library/Kubernetes/Web/PodDetail.php | 11 +---- library/Kubernetes/Web/ReplicaSetDetail.php | 11 +---- library/Kubernetes/Web/StatefulSetDetail.php | 10 +---- public/css/common.less | 6 ++- 12 files changed, 60 insertions(+), 96 deletions(-) create mode 100644 library/Kubernetes/Web/DetailState.php diff --git a/library/Kubernetes/Web/ContainerDetail.php b/library/Kubernetes/Web/ContainerDetail.php index 939667ce..5c389753 100644 --- a/library/Kubernetes/Web/ContainerDetail.php +++ b/library/Kubernetes/Web/ContainerDetail.php @@ -18,7 +18,6 @@ use ipl\Stdlib\Str; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\StateBall; use ipl\Web\Widget\TimeAgo; class ContainerDetail extends BaseHtmlElement @@ -51,14 +50,7 @@ protected function assemble(): void new Icon('arrows-spin'), new Text($this->container->restart_count) ), - $this->translate('Icinga State') => (new HtmlDocument())->addHtml( - new StateBall($this->container->icinga_state, StateBall::SIZE_MEDIUM), - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->container->icinga_state) - ) - ), + $this->translate('Icinga State') => new DetailState($this->container->icinga_state), $this->translate('Icinga State Reason') => new IcingaStateReason($this->container->icinga_state_reason) ])); diff --git a/library/Kubernetes/Web/DaemonSetDetail.php b/library/Kubernetes/Web/DaemonSetDetail.php index 591a72ed..127a7195 100644 --- a/library/Kubernetes/Web/DaemonSetDetail.php +++ b/library/Kubernetes/Web/DaemonSetDetail.php @@ -14,7 +14,6 @@ use Icinga\Module\Kubernetes\Model\DaemonSet; use Icinga\Module\Kubernetes\Model\DaemonSetCondition; use Icinga\Module\Kubernetes\Model\Event; -use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; @@ -22,7 +21,6 @@ use ipl\I18n\Translation; use ipl\Stdlib\Filter; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\StateBall; class DaemonSetDetail extends BaseHtmlElement { @@ -66,14 +64,7 @@ protected function assemble(): void $this->translate('Number Ready') => $this->daemonSet->number_ready, $this->translate('Number Available') => $this->daemonSet->number_available, $this->translate('Number Unavailable') => $this->daemonSet->number_unavailable, - $this->translate('Icinga State') => (new HtmlDocument())->addHtml( - new StateBall($this->daemonSet->icinga_state, StateBall::SIZE_MEDIUM), - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->daemonSet->icinga_state) - ) - ), + $this->translate('Icinga State') => new DetailState($this->daemonSet->icinga_state), $this->translate('Icinga State Reason') => new IcingaStateReason( $this->daemonSet->icinga_state_reason ) diff --git a/library/Kubernetes/Web/DeploymentDetail.php b/library/Kubernetes/Web/DeploymentDetail.php index b9c397f7..079a4e1a 100644 --- a/library/Kubernetes/Web/DeploymentDetail.php +++ b/library/Kubernetes/Web/DeploymentDetail.php @@ -13,7 +13,6 @@ use Icinga\Module\Kubernetes\Common\ResourceDetails; use Icinga\Module\Kubernetes\Model\Deployment; use Icinga\Module\Kubernetes\Model\Event; -use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; @@ -21,7 +20,6 @@ use ipl\I18n\Translation; use ipl\Stdlib\Filter; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\StateBall; class DeploymentDetail extends BaseHtmlElement { @@ -68,14 +66,7 @@ protected function assemble(): void $this->translate('Ready Replicas') => $this->deployment->ready_replicas, $this->translate('Available Replicas') => $this->deployment->available_replicas, $this->translate('Unavailable Replicas') => $this->deployment->unavailable_replicas, - $this->translate('Icinga State') => (new HtmlDocument())->addHtml( - new StateBall($this->deployment->icinga_state, StateBall::SIZE_MEDIUM), - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->deployment->icinga_state) - ) - ), + $this->translate('Icinga State') => new DetailState($this->deployment->icinga_state), $this->translate('Icinga State Reason') => new IcingaStateReason( $this->deployment->icinga_state_reason ) diff --git a/library/Kubernetes/Web/DetailState.php b/library/Kubernetes/Web/DetailState.php new file mode 100644 index 00000000..e35ed095 --- /dev/null +++ b/library/Kubernetes/Web/DetailState.php @@ -0,0 +1,40 @@ +addHtml( + (new HtmlDocument())->addHtml( + new StateBall($this->state, StateBall::SIZE_MEDIUM), + new HtmlElement( + 'span', + new Attributes(['class' => 'icinga-state-text margin-to-ball']), + new Text($this->state) + ) + ) + ); + } +} diff --git a/library/Kubernetes/Web/IcingaStateReason.php b/library/Kubernetes/Web/IcingaStateReason.php index 23a84501..843c4d2a 100644 --- a/library/Kubernetes/Web/IcingaStateReason.php +++ b/library/Kubernetes/Web/IcingaStateReason.php @@ -25,13 +25,13 @@ class IcingaStateReason extends BaseHtmlElement /** @var string[] Replacements for {@see static::TEXT_PATTERNS} */ protected const TEXT_REPLACEMENTS = [ "\n", - '', - '', - '', - '', - '', - '', - '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', ]; protected string $icingaStateReason; diff --git a/library/Kubernetes/Web/InitContainerDetail.php b/library/Kubernetes/Web/InitContainerDetail.php index ed24a02c..33f1a46f 100644 --- a/library/Kubernetes/Web/InitContainerDetail.php +++ b/library/Kubernetes/Web/InitContainerDetail.php @@ -16,7 +16,6 @@ use ipl\Stdlib\Str; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\StateBall; use ipl\Web\Widget\TimeAgo; class InitContainerDetail extends BaseHtmlElement @@ -43,14 +42,7 @@ protected function assemble(): void new Icon('download'), new Text($this->initContainer->image_pull_policy) ), - $this->translate('Icinga State') => (new HtmlDocument())->addHtml( - new StateBall($this->initContainer->icinga_state, StateBall::SIZE_MEDIUM), - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->initContainer->icinga_state) - ) - ), + $this->translate('Icinga State') => new DetailState($this->initContainer->icinga_state), $this->translate('Icinga State Reason') => new IcingaStateReason($this->initContainer->icinga_state_reason) ])); diff --git a/library/Kubernetes/Web/JobDetail.php b/library/Kubernetes/Web/JobDetail.php index b2344613..d1526708 100644 --- a/library/Kubernetes/Web/JobDetail.php +++ b/library/Kubernetes/Web/JobDetail.php @@ -10,7 +10,6 @@ use Icinga\Module\Kubernetes\Common\ResourceDetails; use Icinga\Module\Kubernetes\Model\Event; use Icinga\Module\Kubernetes\Model\Job; -use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; @@ -18,7 +17,6 @@ use ipl\I18n\Translation; use ipl\Stdlib\Filter; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\StateBall; class JobDetail extends BaseHtmlElement { @@ -64,14 +62,7 @@ protected function assemble(): void new Icon('hourglass-start'), new Text(Format::seconds($this->job->ttl_seconds_after_finished) ?? $this->translate('None')) ), - $this->translate('Icinga State') => (new HtmlDocument())->addHtml( - new StateBall($this->job->icinga_state, StateBall::SIZE_MEDIUM), - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->job->icinga_state) - ) - ), + $this->translate('Icinga State') => new DetailState($this->job->icinga_state), $this->translate('Icinga State Reason') => new IcingaStateReason( $this->job->icinga_state_reason ) diff --git a/library/Kubernetes/Web/NodeDetail.php b/library/Kubernetes/Web/NodeDetail.php index 6421f912..2a434f31 100644 --- a/library/Kubernetes/Web/NodeDetail.php +++ b/library/Kubernetes/Web/NodeDetail.php @@ -14,14 +14,11 @@ use Icinga\Module\Kubernetes\Model\Node; use Icinga\Module\Kubernetes\Model\NodeCondition; use Icinga\Util\Format; -use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; -use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; use ipl\Html\Text; use ipl\I18n\Translation; use ipl\Stdlib\Filter; -use ipl\Web\Widget\StateBall; class NodeDetail extends BaseHtmlElement { @@ -80,13 +77,7 @@ protected function assemble(): void $this->translate('Container Runtime Version') => $this->node->container_runtime_version, $this->translate('Kubelet Version') => $this->node->kubelet_version, $this->translate('Kube Proxy Version') => $this->node->kube_proxy_version, - $this->translate('Icinga State') => (new HtmlDocument()) - ->addHtml(new StateBall($this->node->icinga_state, StateBall::SIZE_MEDIUM)) - ->addHtml(new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - Text::create($this->node->icinga_state) - )), + $this->translate('Icinga State') => new DetailState($this->node->icinga_state), $this->translate('Icinga State Reason') => new IcingaStateReason( $this->node->icinga_state_reason ) diff --git a/library/Kubernetes/Web/PodDetail.php b/library/Kubernetes/Web/PodDetail.php index d84f90ca..5b38b15c 100644 --- a/library/Kubernetes/Web/PodDetail.php +++ b/library/Kubernetes/Web/PodDetail.php @@ -13,7 +13,6 @@ use Icinga\Module\Kubernetes\Model\Container; use Icinga\Module\Kubernetes\Model\Event; use Icinga\Module\Kubernetes\Model\Pod; -use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; @@ -22,7 +21,6 @@ use ipl\Stdlib\Filter; use ipl\Web\Widget\EmptyState; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\StateBall; class PodDetail extends BaseHtmlElement { @@ -82,14 +80,7 @@ protected function assemble(): void new EmptyState($this->translate('None')), $this->translate('Message') => $this->pod->message ?? new EmptyState($this->translate('None')), - $this->translate('Icinga State') => (new HtmlDocument())->addHtml( - new StateBall($this->pod->icinga_state, StateBall::SIZE_MEDIUM), - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text($this->pod->icinga_state) - ) - ), + $this->translate('Icinga State') => new DetailState($this->pod->icinga_state), $this->translate('Icinga State Reason') => new IcingaStateReason($this->pod->icinga_state_reason) ])), new Labels($this->pod->label), diff --git a/library/Kubernetes/Web/ReplicaSetDetail.php b/library/Kubernetes/Web/ReplicaSetDetail.php index 0d324150..85af2761 100644 --- a/library/Kubernetes/Web/ReplicaSetDetail.php +++ b/library/Kubernetes/Web/ReplicaSetDetail.php @@ -13,7 +13,6 @@ use Icinga\Module\Kubernetes\Common\ResourceDetails; use Icinga\Module\Kubernetes\Model\Event; use Icinga\Module\Kubernetes\Model\ReplicaSet; -use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; @@ -21,7 +20,6 @@ use ipl\I18n\Translation; use ipl\Stdlib\Filter; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\StateBall; class ReplicaSetDetail extends BaseHtmlElement { @@ -59,14 +57,7 @@ protected function assemble(): void $this->translate('Fully Labeled Replicas') => $this->replicaSet->fully_labeled_replicas, $this->translate('Ready Replicas') => $this->replicaSet->ready_replicas, $this->translate('Available Replicas') => $this->replicaSet->available_replicas, - $this->translate('Icinga State') => (new HtmlDocument())->addHtml( - new StateBall($this->replicaSet->icinga_state, StateBall::SIZE_MEDIUM), - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - Text::create($this->replicaSet->icinga_state) - ) - ), + $this->translate('Icinga State') => new DetailState($this->replicaSet->icinga_state), $this->translate('Icinga State Reason') => new IcingaStateReason( $this->replicaSet->icinga_state_reason ) diff --git a/library/Kubernetes/Web/StatefulSetDetail.php b/library/Kubernetes/Web/StatefulSetDetail.php index 3a0ac51b..d01ee35e 100644 --- a/library/Kubernetes/Web/StatefulSetDetail.php +++ b/library/Kubernetes/Web/StatefulSetDetail.php @@ -22,7 +22,6 @@ use ipl\I18n\Translation; use ipl\Stdlib\Filter; use ipl\Web\Widget\Icon; -use ipl\Web\Widget\StateBall; class StatefulSetDetail extends BaseHtmlElement { @@ -73,14 +72,7 @@ protected function assemble(): void $this->translate('Updated Replicas') => $this->statefulSet->updated_replicas, $this->translate('Ready Replicas') => $this->statefulSet->ready_replicas, $this->translate('Available Replicas') => $this->statefulSet->available_replicas, - $this->translate('Icinga State') => (new HtmlDocument())->addHtml( - new StateBall($this->statefulSet->icinga_state, StateBall::SIZE_MEDIUM), - new HtmlElement( - 'span', - new Attributes(['class' => 'icinga-state-text']), - new Text(' ' . $this->statefulSet->icinga_state) - ) - ), + $this->translate('Icinga State') => new DetailState($this->statefulSet->icinga_state), $this->translate('Icinga State Reason') => new IcingaStateReason( $this->statefulSet->icinga_state_reason ) diff --git a/public/css/common.less b/public/css/common.less index 2ed15dfe..445ed111 100644 --- a/public/css/common.less +++ b/public/css/common.less @@ -13,14 +13,16 @@ pre { } .state-ball { - margin-right: .2em; - // Main use case is the event list, which also contains informational events. &.state-none { border: 1px solid @gray-light; } } +.margin-to-ball { + margin-left: .2em; +} + .container-list > .list-item > .visual > .state-ball, .init-container-list > .list-item > .visual > .state-ball, .container-detail > .details > .horizontal-key-value > .value > .state-ball { From 2d6244e994220eecaa6e0d13f3cab92c19465e4c Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 2 Jan 2025 13:19:57 +0100 Subject: [PATCH 23/37] Use own action list --- configuration.php | 5 +- library/Kubernetes/Common/BaseItemList.php | 2 +- public/css/action-list.less | 2 +- public/js/action-list.js | 63 ++++++++++------------ 4 files changed, 32 insertions(+), 40 deletions(-) diff --git a/configuration.php b/configuration.php index 197af29a..e4e084b0 100644 --- a/configuration.php +++ b/configuration.php @@ -284,10 +284,7 @@ $this->translate('Restrict access to the resources that match the filter') ); -if (! Module::exists('icingadb')) { - $this->provideJsFile('action-list.js'); -} - +$this->provideJsFile('action-list.js'); $this->provideJsFile('vendor/chart.umd.js'); $this->provideCssFile('action-list.less'); diff --git a/library/Kubernetes/Common/BaseItemList.php b/library/Kubernetes/Common/BaseItemList.php index 34e5716b..847225a2 100644 --- a/library/Kubernetes/Common/BaseItemList.php +++ b/library/Kubernetes/Common/BaseItemList.php @@ -75,7 +75,7 @@ protected function assemble(): void $this->addAttributes(['class' => $this->viewMode]); foreach ($this->query as $item) { if (! $detailUrlAdded) { - $this->addAttributes(['class' => 'action-list'] + [ + $this->addAttributes(['class' => 'action-list-kubernetes'] + [ 'data-icinga-detail-url' => Url::fromPath( 'kubernetes/' . str_replace('_', '-', $item->getTableAlias()) ) diff --git a/public/css/action-list.less b/public/css/action-list.less index be0f2a21..8ea92d39 100644 --- a/public/css/action-list.less +++ b/public/css/action-list.less @@ -1,6 +1,6 @@ /* Icinga for Kubernetes Web | (c) 2024 Icinga GmbH | AGPLv3 */ -.action-list { +.action-list-kubernetes { [data-action-item].active { background-color: @tr-active-color; } diff --git a/public/js/action-list.js b/public/js/action-list.js index d4873904..6e7a4b81 100644 --- a/public/js/action-list.js +++ b/public/js/action-list.js @@ -1,27 +1,20 @@ -/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */ +/* Icinga for Kubernetes Web | (c) 2025 Icinga GmbH | AGPLv3 */ -;(function (Icinga) { +(function (Icinga) { "use strict"; - try { - var notjQuery = require('icinga/icinga-php-library/notjQuery'); - } catch (e) { - console.warn('Unable to provide input enrichments. Libraries not available:', e); - return; - } - Icinga.Behaviors = Icinga.Behaviors || {}; class ActionList extends Icinga.EventListener { constructor(icinga) { super(icinga); - this.on('click', '.action-list [data-action-item]:not(.page-separator), .action-list [data-action-item] a[href]', this.onClick, this); - this.on('close-column', '#main > #col2', this.onColumnClose, this); + this.on('click', '.action-list-kubernetes [data-action-item]:not(.page-separator), .action-list-kubernetes [data-action-item] a[href]', this.onClick, this); + this.on('close-column', '#main > #col2.module-kubernetes', this.onColumnClose, this); this.on('column-moved', this.onColumnMoved, this); - this.on('rendered', '#main .container', this.onRendered, this); + this.on('rendered', '#main .container.module-kubernetes:has(.action-list-kubernetes)', this.onRendered, this); this.on('keydown', '#body', this.onKeyDown, this); this.on('click', '.load-more[data-no-icinga-ajax] a', this.onLoadMoreClick, this); @@ -71,6 +64,10 @@ let _this = event.data.self; let target = event.currentTarget; + if (event.target.matches('.favorite-checkbox') || event.target.matches('.favorite-checkbox-label')) { + return true + } + if (target.matches('a') && (! target.matches('.subject') || event.ctrlKey || event.metaKey)) { return true; } @@ -80,7 +77,7 @@ event.stopPropagation(); let item = target.closest('[data-action-item]'); - let list = target.closest('.action-list'); + let list = target.closest('.action-list-kubernetes'); let activeItems = _this.getActiveItems(list); let toActiveItems = [], toDeactivateItems = []; @@ -101,7 +98,7 @@ let allItems = _this.getAllItems(list); let startIndex = allItems.indexOf(item); - if(startIndex < 0) { + if (startIndex < 0) { startIndex = 0; } @@ -169,8 +166,8 @@ if (footer === null) { footer = notjQuery.render( '' + '
' + + '' ) list.closest('.container').appendChild(footer); @@ -198,7 +195,7 @@ } /** - * Key navigation for .action-list + * Key navigation for .action-list-kubernetes * * Only for primary lists (dashboard or lists in detail view are not taken into account) * @@ -228,15 +225,15 @@ || focusedElement.matches('#body')) ) { let activeItem = document.querySelector( - '#main > .container > .content > .action-list [data-action-item].active' + '#main > .container > .content > .action-list-kubernetes [data-action-item].active' ); if (activeItem) { - list = activeItem.closest('.action-list'); + list = activeItem.closest('.action-list-kubernetes'); } else { - list = focusedElement.querySelector('#main > .container > .content > .action-list'); + list = focusedElement.querySelector('#main > .container > .content > .action-list-kubernetes'); } } else if (focusedElement) { - list = focusedElement.closest('.content > .action-list'); + list = focusedElement.closest('.content > .action-list-kubernetes'); } if (! list) { @@ -259,7 +256,7 @@ let allItems = _this.getAllItems(list); let firstListItem = allItems[0]; - let lastListItem = allItems[allItems.length -1]; + let lastListItem = allItems[allItems.length - 1]; let activeItems = _this.getActiveItems(list); let markAsLastActive = null; // initialized only if it is different from toActiveItem let toActiveItem = null; @@ -396,7 +393,7 @@ let allItems = this.getAllItems(list); let activeItems = this.getActiveItems(list); this.setActive(allItems.filter(item => ! activeItems.includes(item))); - this.setLastActivatedItemUrl(allItems[allItems.length -1].dataset.icingaDetailFilter); + this.setLastActivatedItemUrl(allItems[allItems.length - 1].dataset.icingaDetailFilter); this.addSelectionCountToFooter(list); this.loadDetailUrl(list); } @@ -415,7 +412,7 @@ * * @param url */ - setLastActivatedItemUrl (url) { + setLastActivatedItemUrl(url) { this.lastActivatedItemUrl = url; } @@ -441,7 +438,7 @@ } clearDashboardSelections(dashboard, currentList) { - dashboard.querySelectorAll('.action-list').forEach(otherList => { + dashboard.querySelectorAll('.action-list-kubernetes').forEach(otherList => { if (otherList !== currentList) { this.clearSelection(this.getActiveItems(otherList)); } @@ -514,8 +511,7 @@ * * @return array */ - getActiveItems(list) - { + getActiveItems(list) { let items; if (list.tagName.toLowerCase() === 'table') { items = list.querySelectorAll(':scope > tbody > [data-action-item].active'); @@ -533,8 +529,7 @@ * * @return array */ - getAllItems(list) - { + getAllItems(list) { let items; if (list.tagName.toLowerCase() === 'table') { items = list.querySelectorAll(':scope > tbody > [data-action-item]'); @@ -667,7 +662,7 @@ let url = '?' + filters.join('|'); if (withBaseUrl) { - return items[0].closest('.action-list').getAttribute('data-icinga-multiselect-url') + url; + return items[0].closest('.action-list-kubernetes').getAttribute('data-icinga-multiselect-url') + url; } return url; @@ -714,7 +709,7 @@ let _this = event.data.self; if (event.target.id === 'col2' && sourceId === 'col1') { // only for browser-back (col1 shifted to col2) - _this.clearSelection(event.target.querySelectorAll('.action-list .active')); + _this.clearSelection(event.target.querySelectorAll('.action-list-kubernetes .active')); } else if (event.target.id === 'col1' && sourceId === 'col2') { for (const requestNo of Object.keys(_this.activeRequests)) { if (_this.activeRequests[requestNo] === sourceId) { @@ -749,7 +744,7 @@ // no detail view || ignore when already set let actionLists = null; if (! list) { - actionLists = document.querySelectorAll('.action-list'); + actionLists = document.querySelectorAll('.action-list-kubernetes'); } else { actionLists = [list]; } @@ -799,12 +794,12 @@ _this.clearDashboardSelections(dashboard, list); } - _this.clearSelection(_this.getAllItems(list).filter(item => !toActiveItems.includes(item))); + _this.clearSelection(_this.getAllItems(list).filter(item => ! toActiveItems.includes(item))); _this.setActive(toActiveItems); } if (isTopLevelContainer) { - let footerList = list ?? container.querySelector('.content > .action-list'); + let footerList = list ?? container.querySelector('.content > .action-list-kubernetes'); if (footerList) { _this.addSelectionCountToFooter(footerList); } From 0905b2eacff880e03eb8d084fcfca855b7a58475 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 2 Jan 2025 13:22:22 +0100 Subject: [PATCH 24/37] Add model for favorites --- library/Kubernetes/Model/CronJob.php | 4 + library/Kubernetes/Model/DaemonSet.php | 6 +- library/Kubernetes/Model/Deployment.php | 4 + library/Kubernetes/Model/Favorite.php | 80 +++++++++++++++++++ library/Kubernetes/Model/Ingress.php | 4 + library/Kubernetes/Model/Job.php | 4 + library/Kubernetes/Model/NamespaceModel.php | 4 + library/Kubernetes/Model/Node.php | 4 + library/Kubernetes/Model/PersistentVolume.php | 6 +- .../Model/PersistentVolumeClaim.php | 4 + library/Kubernetes/Model/Pod.php | 4 + library/Kubernetes/Model/ReplicaSet.php | 4 + library/Kubernetes/Model/Service.php | 4 + library/Kubernetes/Model/StatefulSet.php | 4 + 14 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 library/Kubernetes/Model/Favorite.php diff --git a/library/Kubernetes/Model/CronJob.php b/library/Kubernetes/Model/CronJob.php index 7b12220e..9f36ce84 100644 --- a/library/Kubernetes/Model/CronJob.php +++ b/library/Kubernetes/Model/CronJob.php @@ -49,6 +49,10 @@ public function createRelations(Relations $relations): void $relations ->belongsToMany('job', Job::class) ->through('job_owner'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/DaemonSet.php b/library/Kubernetes/Model/DaemonSet.php index 7eeb1564..a237eac8 100644 --- a/library/Kubernetes/Model/DaemonSet.php +++ b/library/Kubernetes/Model/DaemonSet.php @@ -50,6 +50,10 @@ public function createRelations(Relations $relations): void ->setTargetForeignKey('owner_uuid') ->setCandidateKey('uuid') ->setForeignKey('pod_uuid'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array @@ -70,7 +74,7 @@ public function getColumnDefinitions(): array 'number_unavailable' => $this->translate('Number Unavailable'), 'icinga_state' => $this->translate('Icinga State'), 'icinga_state_reason' => $this->translate('Icinga State Reason'), - 'yaml' => $this->translate('YAML'), + 'yaml' => $this->translate('YAML'), 'created' => $this->translate('Created At') ]; } diff --git a/library/Kubernetes/Model/Deployment.php b/library/Kubernetes/Model/Deployment.php index eff69cce..4f0a91a7 100644 --- a/library/Kubernetes/Model/Deployment.php +++ b/library/Kubernetes/Model/Deployment.php @@ -58,6 +58,10 @@ public function createRelations(Relations $relations): void $relations ->belongsToMany('annotation', Annotation::class) ->through('deployment_annotation'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/Favorite.php b/library/Kubernetes/Model/Favorite.php new file mode 100644 index 00000000..d69ed3b4 --- /dev/null +++ b/library/Kubernetes/Model/Favorite.php @@ -0,0 +1,80 @@ +add(new Uuid([ + 'resource_uuid' + ])); + } + + public function createRelations(Relations $relations) + { + $relations->belongsTo('cron_job', CronJob::class)->setJoinType('LEFT'); + + $relations->belongsTo('daemon_set', DaemonSet::class)->setJoinType('LEFT'); + + $relations->belongsTo('deployment', Deployment::class)->setJoinType('LEFT'); + + $relations->belongsTo('ingress', Ingress::class)->setJoinType('LEFT'); + + $relations->belongsTo('job', Job::class)->setJoinType('LEFT'); + + $relations->belongsTo('namespace', NamespaceModel::class)->setJoinType('LEFT'); + + $relations->belongsTo('node', Node::class)->setJoinType('LEFT'); + + $relations->belongsTo('persistent_volume', PersistentVolume::class)->setJoinType('LEFT'); + + $relations->belongsTo('pvc', PersistentVolumeClaim::class)->setJoinType('LEFT'); + + $relations->belongsTo('pod', Pod::class)->setJoinType('LEFT'); + + $relations->belongsTo('replica_set', ReplicaSet::class)->setJoinType('LEFT'); + + $relations->belongsTo('service', Service::class)->setJoinType('LEFT'); + + $relations->belongsTo('stateful_set', StatefulSet::class)->setJoinType('LEFT'); + } + + public function getColumnDefinitions(): array + { + return [ + 'resource_uuid' => $this->translate('Resource UUID'), + 'kind' => $this->translate('Resource Kind'), + 'username' => $this->translate('Username'), + ]; + } + + public function getColumns(): array + { + return [ + 'resource_uuid', + 'kind', + 'username', + ]; + } + + public function getKeyName(): array + { + return ['resource_uuid', 'username']; + } + + public function getTableName(): string + { + return 'favorite'; + } +} diff --git a/library/Kubernetes/Model/Ingress.php b/library/Kubernetes/Model/Ingress.php index de19a0f3..d905b6ca 100644 --- a/library/Kubernetes/Model/Ingress.php +++ b/library/Kubernetes/Model/Ingress.php @@ -46,6 +46,10 @@ public function createRelations(Relations $relations): void $relations ->belongsToMany('annotation', Annotation::class) ->through('ingress_annotation'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/Job.php b/library/Kubernetes/Model/Job.php index d9a9edb5..6b364dc2 100644 --- a/library/Kubernetes/Model/Job.php +++ b/library/Kubernetes/Model/Job.php @@ -70,6 +70,10 @@ public function createRelations(Relations $relations): void ->belongsToMany('cron_job', CronJob::class) ->through('job_owner') ->setTargetForeignKey('owner_uuid'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/NamespaceModel.php b/library/Kubernetes/Model/NamespaceModel.php index fd87b152..d79327fb 100644 --- a/library/Kubernetes/Model/NamespaceModel.php +++ b/library/Kubernetes/Model/NamespaceModel.php @@ -42,6 +42,10 @@ public function createRelations(Relations $relations): void $relations ->belongsToMany('annotation', Annotation::class) ->through('namespace_annotation'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/Node.php b/library/Kubernetes/Model/Node.php index 9e533a3f..b0723089 100644 --- a/library/Kubernetes/Model/Node.php +++ b/library/Kubernetes/Model/Node.php @@ -51,6 +51,10 @@ public function createRelations(Relations $relations): void ->hasMany('pod', Pod::class) ->setCandidateKey('name') ->setForeignKey('node_name'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/PersistentVolume.php b/library/Kubernetes/Model/PersistentVolume.php index c491a378..f32e6403 100644 --- a/library/Kubernetes/Model/PersistentVolume.php +++ b/library/Kubernetes/Model/PersistentVolume.php @@ -56,6 +56,10 @@ public function createRelations(Relations $relations): void $relations ->belongsToMany('annotation', Annotation::class) ->through('persistent_volume_annotation'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array @@ -72,7 +76,7 @@ public function getColumnDefinitions(): array 'volume_source_type' => $this->translate('Volume Source Type'), 'storage_class' => $this->translate('Storage Class'), 'reclaim_policy' => $this->translate('Reclaim Policy'), - 'yaml' => $this->translate('YAML'), + 'yaml' => $this->translate('YAML'), 'created' => $this->translate('Created At') ]; } diff --git a/library/Kubernetes/Model/PersistentVolumeClaim.php b/library/Kubernetes/Model/PersistentVolumeClaim.php index b2e79c51..bce597a4 100644 --- a/library/Kubernetes/Model/PersistentVolumeClaim.php +++ b/library/Kubernetes/Model/PersistentVolumeClaim.php @@ -62,6 +62,10 @@ public function createRelations(Relations $relations): void ->setTargetForeignKey('pod_uuid') ->setCandidateKey('name') ->setForeignKey('claim_name'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/Pod.php b/library/Kubernetes/Model/Pod.php index d0ce559e..512190e5 100644 --- a/library/Kubernetes/Model/Pod.php +++ b/library/Kubernetes/Model/Pod.php @@ -109,6 +109,10 @@ public function createRelations(Relations $relations): void ->setCandidateKey('node_name') ->setForeignKey('name') ->setJoinType('LEFT'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/ReplicaSet.php b/library/Kubernetes/Model/ReplicaSet.php index 2c203fc1..5eb6167f 100644 --- a/library/Kubernetes/Model/ReplicaSet.php +++ b/library/Kubernetes/Model/ReplicaSet.php @@ -58,6 +58,10 @@ public function createRelations(Relations $relations): void ->setTargetForeignKey('owner_uuid') ->setCandidateKey('uuid') ->setForeignKey('replica_set_uuid'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/Service.php b/library/Kubernetes/Model/Service.php index ce048d69..9e67e5e6 100644 --- a/library/Kubernetes/Model/Service.php +++ b/library/Kubernetes/Model/Service.php @@ -56,6 +56,10 @@ public function createRelations(Relations $relations): void $relations ->belongsToMany('pod', Pod::class) ->through('service_pod'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array diff --git a/library/Kubernetes/Model/StatefulSet.php b/library/Kubernetes/Model/StatefulSet.php index 208cf69b..8cb8fe7d 100644 --- a/library/Kubernetes/Model/StatefulSet.php +++ b/library/Kubernetes/Model/StatefulSet.php @@ -50,6 +50,10 @@ public function createRelations(Relations $relations): void ->setTargetForeignKey('owner_uuid') ->setCandidateKey('uuid') ->setForeignKey('pod_uuid'); + + $relations->hasMany('favorite', Favorite::class) + ->setForeignKey('resource_uuid') + ->setJoinType('LEFT'); } public function getColumnDefinitions(): array From cd0c34d1f178de321258071c6c7e0ef21974f0ae Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 20 Feb 2025 13:22:03 +0100 Subject: [PATCH 25/37] Add QuickActions --- application/forms/CommandForm.php | 33 ++++++++++++++ configuration.php | 1 + library/Kubernetes/Web/QuickActions.php | 27 ++++++++++++ public/css/quick-actions.less | 58 +++++++++++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 application/forms/CommandForm.php create mode 100644 library/Kubernetes/Web/QuickActions.php create mode 100644 public/css/quick-actions.less diff --git a/application/forms/CommandForm.php b/application/forms/CommandForm.php new file mode 100644 index 00000000..40ccd09b --- /dev/null +++ b/application/forms/CommandForm.php @@ -0,0 +1,33 @@ + 'icinga-form icinga-controls']; + + /** + * Create and add form elements representing the command's options + * + * @return void + */ + abstract protected function assembleElements(): void; + + /** + * Create and add a submit button to the form + * + * @return void + */ + abstract protected function assembleSubmitButton(): void; + + protected function assemble(): void + { + $this->assembleElements(); + $this->assembleSubmitButton(); + + } +} diff --git a/configuration.php b/configuration.php index e4e084b0..dc13ad5c 100644 --- a/configuration.php +++ b/configuration.php @@ -294,5 +294,6 @@ $this->provideCssFile('icons.less'); $this->provideCssFile('labels.less'); $this->provideCssFile('lists.less'); +$this->provideCssFile('quick-actions.less'); $this->provideCssFile('widgets.less'); $this->provideCssFile('environment-widget.less'); diff --git a/library/Kubernetes/Web/QuickActions.php b/library/Kubernetes/Web/QuickActions.php new file mode 100644 index 00000000..cd099f1d --- /dev/null +++ b/library/Kubernetes/Web/QuickActions.php @@ -0,0 +1,27 @@ + 'quick-actions']; + + public function __construct() + { + } + + protected function assemble() + { + } +} diff --git a/public/css/quick-actions.less b/public/css/quick-actions.less new file mode 100644 index 00000000..a997965d --- /dev/null +++ b/public/css/quick-actions.less @@ -0,0 +1,58 @@ +/* Icinga for Kubernetes Web | (c) 2025 Icinga GmbH | AGPLv3 */ + +.quick-actions { + display: flex; + flex-wrap: wrap; + list-style-type: none; + margin: 0 -.5em; + padding: 0; + + a { + text-decoration: none; + } + + a, + button { + padding: .25em; + .rounded-corners(); + display: inline-flex; + align-items: baseline; + + &:hover { + background: @gray-lighter; + } + } + + li { + margin: 0 .25em .5em .25em; + vertical-align: middle; + white-space: nowrap; + } +} + +.controls:not(.default-layout) > .quick-actions:last-child, +.controls > .quick-actions:last-child { + margin-bottom: 0; +} + +#layout.twocols:not(.wide-layout) { + .quick-actions { + justify-content: space-between; + min-width: 100%; + } +} + +#layout.wide-layout .controls { + .quick-actions { + float: left; + } +} + +button.spinner.active > i { + &.far:before { + // far spinner + content: '\f110'; + font-weight: 900; + + } +} From d3c04613e584236f011563a29672dd933ad13358 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 20 Feb 2025 13:35:15 +0100 Subject: [PATCH 26/37] Add quick actions to toggle favorites --- application/controllers/CronjobController.php | 13 +++ .../controllers/DaemonsetController.php | 15 +++- .../controllers/DeploymentController.php | 15 +++- .../controllers/FavoriteController.php | 83 +++++++++++++++++++ application/controllers/IngressController.php | 13 +++ application/controllers/JobController.php | 15 +++- .../controllers/NamespaceController.php | 13 +++ application/controllers/NodeController.php | 15 +++- .../PersistentvolumeController.php | 13 +++ .../PersistentvolumeclaimController.php | 13 +++ application/controllers/PodController.php | 15 +++- .../controllers/ReplicasetController.php | 15 +++- application/controllers/ServiceController.php | 13 +++ .../controllers/StatefulsetController.php | 15 +++- application/forms/FavorForm.php | 36 ++++++++ application/forms/UnfavorForm.php | 36 ++++++++ library/Kubernetes/Common/Links.php | 10 +++ library/Kubernetes/Web/Factory.php | 28 ++++--- library/Kubernetes/Web/QuickActions.php | 29 ++++++- public/css/common.less | 34 ++++++-- 20 files changed, 409 insertions(+), 30 deletions(-) create mode 100644 application/controllers/FavoriteController.php create mode 100644 application/forms/FavorForm.php create mode 100644 application/forms/UnfavorForm.php diff --git a/application/controllers/CronjobController.php b/application/controllers/CronjobController.php index eaed5703..e94087ab 100644 --- a/application/controllers/CronjobController.php +++ b/application/controllers/CronjobController.php @@ -7,8 +7,10 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; use Icinga\Module\Kubernetes\Model\CronJob; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\CronJobDetail; +use Icinga\Module\Kubernetes\Web\QuickActions; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -28,10 +30,21 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($cronJob === null) { $this->httpNotFound($this->translate('Cron Job not found')); } + $this->addControl(new QuickActions($cronJob, $favorite)); + $this->addContent(new CronJobDetail($cronJob)); } } diff --git a/application/controllers/DaemonsetController.php b/application/controllers/DaemonsetController.php index ca0bdcb5..ad5403c7 100644 --- a/application/controllers/DaemonsetController.php +++ b/application/controllers/DaemonsetController.php @@ -7,9 +7,11 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; use Icinga\Module\Kubernetes\Model\DaemonSet; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\DaemonSetDetail; use Icinga\Module\Kubernetes\Web\DaemonSetList; +use Icinga\Module\Kubernetes\Web\QuickActions; use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -30,6 +32,15 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($daemonSet === null) { $this->httpNotFound($this->translate('Daemon Set not found')); } @@ -37,9 +48,11 @@ public function indexAction(): void $this->addControl( (new DaemonSetList([$daemonSet])) ->setActionList(false) - ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_MINIMAL) ); + $this->addControl(new QuickActions($daemonSet, $favorite)); + $this->addContent(new DaemonSetDetail($daemonSet)); } } diff --git a/application/controllers/DeploymentController.php b/application/controllers/DeploymentController.php index 423c1003..0ffff31a 100644 --- a/application/controllers/DeploymentController.php +++ b/application/controllers/DeploymentController.php @@ -7,9 +7,11 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; use Icinga\Module\Kubernetes\Model\Deployment; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\DeploymentDetail; use Icinga\Module\Kubernetes\Web\DeploymentList; +use Icinga\Module\Kubernetes\Web\QuickActions; use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -30,6 +32,15 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($deployment === null) { $this->httpNotFound($this->translate('Deployment not found')); } @@ -37,9 +48,11 @@ public function indexAction(): void $this->addControl( (new DeploymentList([$deployment])) ->setActionList(false) - ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_MINIMAL) ); + $this->addControl(new QuickActions($deployment, $favorite)); + $this->addContent(new DeploymentDetail($deployment)); } } diff --git a/application/controllers/FavoriteController.php b/application/controllers/FavoriteController.php new file mode 100644 index 00000000..305e0779 --- /dev/null +++ b/application/controllers/FavoriteController.php @@ -0,0 +1,83 @@ +on(FavorForm::ON_SUCCESS, function () { + $db = Database::connection(); + $uuid = $this->params->get('uuid'); + $kind = $this->params->get('kind'); + $username = Auth::getInstance()->getUser()->getUsername(); + + try { + $db->insert( + 'favorite', + [ + 'resource_uuid' => $uuid, + 'kind' => $kind, + 'username' => $username, + ] + ); + } catch (Throwable $e) { + Logger::error($e); + Logger::error($e->getTraceAsString()); + + throw $e; + } + }) + ->handleRequest($this->getServerRequest()); + + $this->redirectNow('__REFRESH__'); + } + + /** + * Unfavors a resource by removing it from the database. Throws an exception if the database operation fails. + * + * @return void + */ + public function unfavorAction(): void + { + (new UnfavorForm()) + ->on(FavorForm::ON_SUCCESS, function () { + $db = Database::connection(); + $uuid = $this->params->get('uuid'); + $username = Auth::getInstance()->getUser()->getUsername(); + try { + $db->delete( + 'favorite', + [ + 'resource_uuid = ?' => $uuid, + 'username = ?' => $username, + ] + ); + } catch (Throwable $e) { + Logger::error($e); + Logger::error($e->getTraceAsString()); + + throw $e; + } + }) + ->handleRequest($this->getServerRequest()); + + $this->redirectNow('__REFRESH__'); + } +} diff --git a/application/controllers/IngressController.php b/application/controllers/IngressController.php index c00f072f..24dab20c 100644 --- a/application/controllers/IngressController.php +++ b/application/controllers/IngressController.php @@ -6,9 +6,11 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\Ingress; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\IngressDetail; +use Icinga\Module\Kubernetes\Web\QuickActions; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -28,10 +30,21 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($ingress === null) { $this->httpNotFound($this->translate('Ingress not found')); } + $this->addControl(new QuickActions($ingress, $favorite)); + $this->addContent(new IngressDetail($ingress)); } } diff --git a/application/controllers/JobController.php b/application/controllers/JobController.php index 0aad33f5..90df45af 100644 --- a/application/controllers/JobController.php +++ b/application/controllers/JobController.php @@ -6,10 +6,12 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\Job; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\JobDetail; use Icinga\Module\Kubernetes\Web\JobList; +use Icinga\Module\Kubernetes\Web\QuickActions; use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -30,6 +32,15 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($job === null) { $this->httpNotFound($this->translate('Job not found')); } @@ -37,9 +48,11 @@ public function indexAction(): void $this->addControl( (new JobList([$job])) ->setActionList(false) - ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_MINIMAL) ); + $this->addControl(new QuickActions($job, $favorite)); + $this->addContent(new JobDetail($job)); } } diff --git a/application/controllers/NamespaceController.php b/application/controllers/NamespaceController.php index 97038278..0e67464d 100644 --- a/application/controllers/NamespaceController.php +++ b/application/controllers/NamespaceController.php @@ -6,9 +6,11 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\NamespaceModel; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\NamespaceDetail; +use Icinga\Module\Kubernetes\Web\QuickActions; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -28,10 +30,21 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($namespace === null) { $this->httpNotFound($this->translate('Namespace not found')); } + $this->addControl(new QuickActions($namespace, $favorite)); + $this->addContent(new NamespaceDetail($namespace)); } } diff --git a/application/controllers/NodeController.php b/application/controllers/NodeController.php index 76a902ef..41b2de42 100644 --- a/application/controllers/NodeController.php +++ b/application/controllers/NodeController.php @@ -6,10 +6,12 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\Node; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\NodeDetail; use Icinga\Module\Kubernetes\Web\NodeList; +use Icinga\Module\Kubernetes\Web\QuickActions; use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -30,6 +32,15 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($node === null) { $this->httpNotFound($this->translate('Node not found')); } @@ -37,9 +48,11 @@ public function indexAction(): void $this->addControl( (new NodeList([$node])) ->setActionList(false) - ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_MINIMAL) ); + $this->addControl(new QuickActions($node, $favorite)); + $this->addContent(new NodeDetail($node)); } } diff --git a/application/controllers/PersistentvolumeController.php b/application/controllers/PersistentvolumeController.php index 76269d08..4db486a9 100644 --- a/application/controllers/PersistentvolumeController.php +++ b/application/controllers/PersistentvolumeController.php @@ -6,9 +6,11 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\PersistentVolume; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\PersistentVolumeDetail; +use Icinga\Module\Kubernetes\Web\QuickActions; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -28,10 +30,21 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($persistentVolume === null) { $this->httpNotFound($this->translate('Persistent Volume not found')); } + $this->addControl(new QuickActions($persistentVolume, $favorite)); + $this->addContent(new PersistentVolumeDetail($persistentVolume)); } } diff --git a/application/controllers/PersistentvolumeclaimController.php b/application/controllers/PersistentvolumeclaimController.php index 09087b92..8f457ea8 100644 --- a/application/controllers/PersistentvolumeclaimController.php +++ b/application/controllers/PersistentvolumeclaimController.php @@ -6,9 +6,11 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\PersistentVolumeClaim; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\PersistentVolumeClaimDetail; +use Icinga\Module\Kubernetes\Web\QuickActions; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -28,10 +30,21 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($pvc === null) { $this->httpNotFound($this->translate('Persistent Volume Claim not found')); } + $this->addControl(new QuickActions($pvc, $favorite)); + $this->addContent(new PersistentVolumeClaimDetail($pvc)); } } diff --git a/application/controllers/PodController.php b/application/controllers/PodController.php index d055bba2..45949f3a 100644 --- a/application/controllers/PodController.php +++ b/application/controllers/PodController.php @@ -6,10 +6,12 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\Pod; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\PodDetail; use Icinga\Module\Kubernetes\Web\PodList; +use Icinga\Module\Kubernetes\Web\QuickActions; use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -30,6 +32,15 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($pod === null) { $this->httpNotFound($this->translate('Pod not found')); } @@ -37,9 +48,11 @@ public function indexAction(): void $this->addControl( (new PodList([$pod])) ->setActionList(false) - ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_MINIMAL) ); + $this->addControl(new QuickActions($pod, $favorite)); + $this->addContent(new PodDetail($pod)); } } diff --git a/application/controllers/ReplicasetController.php b/application/controllers/ReplicasetController.php index 3d0f7fb6..fe72cd8e 100644 --- a/application/controllers/ReplicasetController.php +++ b/application/controllers/ReplicasetController.php @@ -6,8 +6,10 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\ReplicaSet; use Icinga\Module\Kubernetes\Web\Controller; +use Icinga\Module\Kubernetes\Web\QuickActions; use Icinga\Module\Kubernetes\Web\ReplicaSetDetail; use Icinga\Module\Kubernetes\Web\ReplicaSetList; use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; @@ -30,6 +32,15 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($replicaSet === null) { $this->httpNotFound($this->translate('Replica Set not found')); } @@ -37,9 +48,11 @@ public function indexAction(): void $this->addControl( (new ReplicaSetList([$replicaSet])) ->setActionList(false) - ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_MINIMAL) ); + $this->addControl(new QuickActions($replicaSet, $favorite)); + $this->addContent(new ReplicaSetDetail($replicaSet)); } } diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index 3b3b4466..aff52c58 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -6,8 +6,10 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\Service; use Icinga\Module\Kubernetes\Web\Controller; +use Icinga\Module\Kubernetes\Web\QuickActions; use Icinga\Module\Kubernetes\Web\ServiceDetail; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -28,10 +30,21 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($service === null) { $this->httpNotFound($this->translate('Service not found')); } + $this->addControl(new QuickActions($service, $favorite)); + $this->addContent(new ServiceDetail($service)); } } diff --git a/application/controllers/StatefulsetController.php b/application/controllers/StatefulsetController.php index 17f023c0..f9d525ac 100644 --- a/application/controllers/StatefulsetController.php +++ b/application/controllers/StatefulsetController.php @@ -6,8 +6,10 @@ use Icinga\Module\Kubernetes\Common\Auth; use Icinga\Module\Kubernetes\Common\Database; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Model\StatefulSet; use Icinga\Module\Kubernetes\Web\Controller; +use Icinga\Module\Kubernetes\Web\QuickActions; use Icinga\Module\Kubernetes\Web\StatefulSetDetail; use Icinga\Module\Kubernetes\Web\StatefulSetList; use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; @@ -30,6 +32,15 @@ public function indexAction(): void ->filter(Filter::equal('uuid', $uuidBytes)) ->first(); + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $uuidBytes), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + if ($statefulSet === null) { $this->httpNotFound($this->translate('Stateful Set not found')); } @@ -37,9 +48,11 @@ public function indexAction(): void $this->addControl( (new StatefulSetList([$statefulSet])) ->setActionList(false) - ->setViewMode(ViewModeSwitcher::VIEW_MODE_DETAILED) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_MINIMAL) ); + $this->addControl(new QuickActions($statefulSet, $favorite)); + $this->addContent(new StatefulSetDetail($statefulSet)); } } diff --git a/application/forms/FavorForm.php b/application/forms/FavorForm.php new file mode 100644 index 00000000..d8ffc8cd --- /dev/null +++ b/application/forms/FavorForm.php @@ -0,0 +1,36 @@ + 'inline']; + + public function __construct() + { + } + + protected function assembleElements(): void + { + } + + protected function assembleSubmitButton(): void + { + $this->addElement( + 'submitButton', + 'btn_submit', + [ + 'class' => ['link-button spinner'], + 'label' => [ + (new Icon('star'))->setStyle('far'), + t('Favor') + ], + 'title' => t('Favor Resource') + ] + ); + } +} diff --git a/application/forms/UnfavorForm.php b/application/forms/UnfavorForm.php new file mode 100644 index 00000000..5cfa02d1 --- /dev/null +++ b/application/forms/UnfavorForm.php @@ -0,0 +1,36 @@ + 'inline']; + + public function __construct() + { + } + + protected function assembleElements(): void + { + } + + protected function assembleSubmitButton(): void + { + $this->addElement( + 'submitButton', + 'btn_submit', + [ + 'class' => ['link-button spinner'], + 'label' => [ + new Icon('star'), + t('Unfavor') + ], + 'title' => t('Unfavor Resource') + ] + ); + } +} diff --git a/library/Kubernetes/Common/Links.php b/library/Kubernetes/Common/Links.php index 114ebcf0..b1278985 100644 --- a/library/Kubernetes/Common/Links.php +++ b/library/Kubernetes/Common/Links.php @@ -131,4 +131,14 @@ public static function statefulset(StatefulSet $statefulSet): Url { return Url::fromPath('kubernetes/statefulset', ['id' => (string) Uuid::fromBytes($statefulSet->uuid)]); } + + public static function favor(string $uuid, $kind): Url + { + return Url::fromPath('kubernetes/favorite/favor', ['uuid' => $uuid, 'kind' => $kind]); + } + + public static function unfavor(string $uuid): Url + { + return Url::fromPath('kubernetes/favorite/unfavor', ['uuid' => $uuid]); + } } diff --git a/library/Kubernetes/Web/Factory.php b/library/Kubernetes/Web/Factory.php index e0b3d69d..f7a6c21d 100644 --- a/library/Kubernetes/Web/Factory.php +++ b/library/Kubernetes/Web/Factory.php @@ -287,19 +287,21 @@ public static function getKindFromModel(Model $model): string { $kind = match (true) { $model instanceof ConfigMap, - $model instanceof CronJob, - $model instanceof DaemonSet, - $model instanceof Deployment, - $model instanceof Ingress, - $model instanceof Job, - $model instanceof PersistentVolume, - $model instanceof PersistentVolumeClaim, - $model instanceof Pod, - $model instanceof ReplicaSet, - $model instanceof Secret, - $model instanceof Service, - $model instanceof StatefulSet => basename(str_replace('\\', '/', get_class($model))), - default => null + $model instanceof CronJob, + $model instanceof DaemonSet, + $model instanceof Deployment, + $model instanceof Ingress, + $model instanceof Job, + $model instanceof Node, + $model instanceof PersistentVolume, + $model instanceof PersistentVolumeClaim, + $model instanceof Pod, + $model instanceof ReplicaSet, + $model instanceof Secret, + $model instanceof Service, + $model instanceof StatefulSet => basename(str_replace('\\', '/', get_class($model))), + $model instanceof NamespaceModel => 'namespace', + default => null }; return strtolower(str_replace(['_', '-'], '', $kind)); diff --git a/library/Kubernetes/Web/QuickActions.php b/library/Kubernetes/Web/QuickActions.php index cd099f1d..43830088 100644 --- a/library/Kubernetes/Web/QuickActions.php +++ b/library/Kubernetes/Web/QuickActions.php @@ -4,24 +4,45 @@ namespace Icinga\Module\Kubernetes\Web; +use Icinga\Module\Kubernetes\Common\Links; use Icinga\Module\Kubernetes\Forms\FavorForm; use Icinga\Module\Kubernetes\Forms\UnfavorForm; use ipl\Html\BaseHtmlElement; +use ipl\Html\Html; use ipl\Orm\Model; class QuickActions extends BaseHtmlElement { - protected Model $item; - protected $tag = 'ul'; protected $defaultAttributes = ['class' => 'quick-actions']; - public function __construct() - { + public function __construct( + protected Model $item, + protected ?Model $favorite = null + ) { } protected function assemble() { + if ($this->favorite !== null) { + $this->add( + Html::tag( + 'li', + (new UnfavorForm())->setAction( + Links::unfavor($this->item->uuid)->getAbsoluteUrl() + ) + ) + ); + } else { + $this->add( + Html::tag( + 'li', + (new FavorForm())->setAction( + Links::favor($this->item->uuid, Factory::getKindFromModel($this->item))->getAbsoluteUrl() + ) + ) + ); + } } } diff --git a/public/css/common.less b/public/css/common.less index 445ed111..0a2386a4 100644 --- a/public/css/common.less +++ b/public/css/common.less @@ -31,7 +31,6 @@ pre { } .controls { - &:not(.no-shadow) { // Copied from Icinga DB Web -moz-box-shadow: 0 0 0 1px var(--gray-lighter, #4b4b4b); @@ -39,11 +38,31 @@ pre { box-shadow: 0 0 0 1px var(--gray-lighter, #4b4b4b); } + &:not(.default-layout) > :not(:only-child) { + margin-bottom: 0.5em; + } + a.subject { cursor: default; pointer-events: none; } + .favorite-toggle { + margin-right: 1em; + float: right; + width: auto; + + .control-group { + margin: 0; + justify-content: flex-end; + max-height: 24px; + + label { + text-align: right; + } + } + } + .limit-control, .view-mode-switcher, .sort-control { @@ -51,16 +70,19 @@ pre { float: right; } - .list-item { - font-size: @font-size-small; - + .item-list .list-item { .main { - padding-bottom: 0.454545em; + padding: 3px 0; + } + + .visual { + // Calculate the padding so that the icon is vertically centered in the minimal view. + padding: ~"calc((24px - (12px * 0.75 * 1.5)) / 2)" 0; + width: 1.2em; } } } - .horizontal-key-value, .vertical-key-value { > .value { From d49f0e3d0820071327643132ff6f4456508880e7 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 20 Feb 2025 14:50:08 +0100 Subject: [PATCH 27/37] Show favorite icon in action list --- application/controllers/FavoriteController.php | 4 ++-- library/Kubernetes/Common/BaseItemList.php | 13 ++++++++++++- library/Kubernetes/Common/BaseListItem.php | 14 ++++++++++++++ .../Kubernetes/Common/DefaultListItemHeader.php | 8 +++++++- public/css/lists.less | 8 ++++++++ 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/application/controllers/FavoriteController.php b/application/controllers/FavoriteController.php index 305e0779..7156f22e 100644 --- a/application/controllers/FavoriteController.php +++ b/application/controllers/FavoriteController.php @@ -46,7 +46,7 @@ public function favorAction(): void }) ->handleRequest($this->getServerRequest()); - $this->redirectNow('__REFRESH__'); + $this->closeModalAndRefreshRemainingViews('__REFRESH__'); } /** @@ -78,6 +78,6 @@ public function unfavorAction(): void }) ->handleRequest($this->getServerRequest()); - $this->redirectNow('__REFRESH__'); + $this->closeModalAndRefreshRemainingViews('__REFRESH__'); } } diff --git a/library/Kubernetes/Common/BaseItemList.php b/library/Kubernetes/Common/BaseItemList.php index 847225a2..bbd876c8 100644 --- a/library/Kubernetes/Common/BaseItemList.php +++ b/library/Kubernetes/Common/BaseItemList.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Kubernetes\Common; +use Icinga\Module\Kubernetes\Model\Favorite; use ipl\Html\BaseHtmlElement; use ipl\I18n\Translation; use ipl\Stdlib\BaseFilter; @@ -83,13 +84,23 @@ protected function assemble(): void $detailUrlAdded = true; } + $favorite = Favorite::on(Database::connection()) + ->filter( + Filter::all( + Filter::equal('resource_uuid', $item->uuid), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + ) + ->first(); + $listItem = (new $itemClass($item, $this)) ->addAttributes([ 'data-action-item' => true, 'data-icinga-detail-filter' => QueryString::render( Filter::equal('id', Uuid::fromBytes($item->uuid)->toString()) ) - ]); + ]) + ->setIsFavorite($favorite !== null); if ($this->viewMode !== null) { $listItem->setViewMode($this->viewMode); diff --git a/library/Kubernetes/Common/BaseListItem.php b/library/Kubernetes/Common/BaseListItem.php index 16cdc140..3f4ab6c5 100644 --- a/library/Kubernetes/Common/BaseListItem.php +++ b/library/Kubernetes/Common/BaseListItem.php @@ -23,6 +23,8 @@ abstract class BaseListItem extends BaseHtmlElement protected $tag = 'li'; + protected bool $isFavorite; + /** * Create a new list item * @@ -47,6 +49,18 @@ protected function init(): void { } + public function isFavorite(): bool + { + return $this->isFavorite; + } + + public function setIsFavorite(bool $isFavorite): self + { + $this->isFavorite = $isFavorite; + + return $this; + } + protected function assemble(): void { $this->add([ diff --git a/library/Kubernetes/Common/DefaultListItemHeader.php b/library/Kubernetes/Common/DefaultListItemHeader.php index b5b786dd..1679b464 100644 --- a/library/Kubernetes/Common/DefaultListItemHeader.php +++ b/library/Kubernetes/Common/DefaultListItemHeader.php @@ -6,6 +6,7 @@ use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; +use ipl\Web\Widget\Icon; use ipl\Web\Widget\TimeAgo; trait DefaultListItemHeader @@ -30,6 +31,11 @@ protected function assembleHeader(BaseHtmlElement $header): void default => null }; - $header->addHtml(new TimeAgo($this->item->created->getTimestamp())); + $span = Html::tag('span', Attributes::create(['class' => 'header-container'])); + if ($this->isFavorite()) { + $span->addHtml(new Icon('star')); + } + $span->addHtml(new TimeAgo($this->item->created->getTimestamp())); + $header->addHtml($span); } } diff --git a/public/css/lists.less b/public/css/lists.less index f3652d69..381df842 100644 --- a/public/css/lists.less +++ b/public/css/lists.less @@ -1,5 +1,13 @@ /* Icinga for Kubernetes Web | (c) 2024 Icinga GmbH | AGPLv3 */ +header .header-container { + white-space: nowrap; + + .icon { + font-size: 10/12em; + } +} + footer { align-items: stretch; height: 1.5em; From c7e8da0a1921a077f0db39b8c9f09e0f3c5132a9 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Tue, 7 Jan 2025 15:57:32 +0100 Subject: [PATCH 28/37] Build data-icinga-detail-url out of names without dashes --- library/Kubernetes/Common/BaseItemList.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Kubernetes/Common/BaseItemList.php b/library/Kubernetes/Common/BaseItemList.php index bbd876c8..9dc336a6 100644 --- a/library/Kubernetes/Common/BaseItemList.php +++ b/library/Kubernetes/Common/BaseItemList.php @@ -78,7 +78,7 @@ protected function assemble(): void if (! $detailUrlAdded) { $this->addAttributes(['class' => 'action-list-kubernetes'] + [ 'data-icinga-detail-url' => Url::fromPath( - 'kubernetes/' . str_replace('_', '-', $item->getTableAlias()) + 'kubernetes/' . str_replace('_', '', $item->getTableAlias()) ) ]); $detailUrlAdded = true; From 7b2e11d6e065f4597160a31de71e291d42ba7970 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Fri, 21 Feb 2025 12:31:10 +0100 Subject: [PATCH 29/37] Remove multi select feature from action list --- public/js/action-list.js | 198 ++------------------------------------- 1 file changed, 8 insertions(+), 190 deletions(-) diff --git a/public/js/action-list.js b/public/js/action-list.js index 6e7a4b81..7f0e3fb0 100644 --- a/public/js/action-list.js +++ b/public/js/action-list.js @@ -79,44 +79,8 @@ let item = target.closest('[data-action-item]'); let list = target.closest('.action-list-kubernetes'); let activeItems = _this.getActiveItems(list); - let toActiveItems = [], - toDeactivateItems = []; - - const isBeingMultiSelected = list.matches('[data-icinga-multiselect-url]') - && (event.ctrlKey || event.metaKey || event.shiftKey); - - if (isBeingMultiSelected) { - if (event.ctrlKey || event.metaKey) { - if (item.classList.contains('active')) { - toDeactivateItems.push(item); - } else { - toActiveItems.push(item); - } - } else { - document.getSelection().removeAllRanges(); - - let allItems = _this.getAllItems(list); - - let startIndex = allItems.indexOf(item); - if (startIndex < 0) { - startIndex = 0; - } - - let endIndex = activeItems.length ? allItems.indexOf(activeItems[0]) : 0; - if (startIndex > endIndex) { - toActiveItems = allItems.slice(endIndex, startIndex + 1); - } else { - endIndex = activeItems.length ? allItems.indexOf(activeItems[activeItems.length - 1]) : 0; - toActiveItems = allItems.slice(startIndex, endIndex + 1); - } - - toDeactivateItems = activeItems.filter(item => ! toActiveItems.includes(item)); - toActiveItems = toActiveItems.filter(item => ! activeItems.includes(item)); - } - } else { - toDeactivateItems = activeItems; - toActiveItems.push(item); - } + let toActiveItems = [item]; + let toDeactivateItems = activeItems; if (activeItems.length === 1 && toActiveItems.length === 0 @@ -144,62 +108,15 @@ _this.clearSelection(toDeactivateItems); _this.setActive(toActiveItems); - _this.addSelectionCountToFooter(list); _this.setLastActivatedItemUrl(lastActivatedUrl); _this.loadDetailUrl(list, target.matches('a') ? target.getAttribute('href') : null); } - /** - * Add the selection count to footer if list allow multi selection - * - * @param list - */ - addSelectionCountToFooter(list) { - if (! list.matches('[data-icinga-multiselect-url]') || list.closest('.dashboard')) { - return; - } - - let activeItemCount = this.getActiveItems(list).length; - let footer = list.closest('.container').querySelector('.footer'); - - // For items that do not have a bottom status bar like Downtimes, Comments... - if (footer === null) { - footer = notjQuery.render( - '' - ) - - list.closest('.container').appendChild(footer); - } - - let selectionCount = footer.querySelector('.selection-count'); - if (selectionCount === null) { - selectionCount = notjQuery.render( - '
' - ); - - footer.prepend(selectionCount); - } - - let selectedItems = selectionCount.querySelector('.selected-items'); - selectedItems.innerText = activeItemCount - ? list.dataset.icingaMultiselectCountLabel.replace('%d', activeItemCount) - : list.dataset.icingaMultiselectHintLabel; - - if (activeItemCount === 0) { - selectedItems.classList.add('hint'); - } else { - selectedItems.classList.remove('hint'); - } - } - /** * Key navigation for .action-list-kubernetes * * Only for primary lists (dashboard or lists in detail view are not taken into account) * - * - `Shift + ArrowUp|ArrowDown` = Multiselect * - `ArrowUp|ArrowDown` = Select next/previous * - `Ctrl|cmd + A` = Select all on currect page * @@ -240,18 +157,6 @@ return; } - let isMultiSelectableList = list.matches('[data-icinga-multiselect-url]'); - - if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'a') { - if (! isMultiSelectableList) { - return; - } - - event.preventDefault(); - _this.selectAll(list); - return; - } - event.preventDefault(); let allItems = _this.getAllItems(list); @@ -278,30 +183,6 @@ if (toActiveItem.classList.contains('load-more')) { toActiveItem = toActiveItem.previousElementSibling; } - } else if (isMultiSelectableList && event.shiftKey) { - if (activeItems.length === 1) { - toActiveItem = directionalNextItem; - } else if (wasAllSelected && ( - (lastActivatedItem !== firstListItem && pressedArrowDownKey) - || (lastActivatedItem !== lastListItem && pressedArrowUpKey) - )) { - if (pressedArrowDownKey) { - toActiveItem = lastActivatedItem === lastListItem ? null : lastListItem; - } else { - toActiveItem = lastActivatedItem === firstListItem ? null : lastListItem; - } - - } else if (directionalNextItem && directionalNextItem.classList.contains('active')) { - // deactivate last activated by down to up select - _this.clearSelection([lastActivatedItem]); - if (wasAllSelected) { - _this.scrollItemIntoView(lastActivatedItem, event.key); - } - - toActiveItem = directionalNextItem; - } else { - [toActiveItem, markAsLastActive] = _this.findToActiveItem(lastActivatedItem, event.key); - } } else { toActiveItem = directionalNextItem ?? lastActivatedItem; @@ -328,7 +209,6 @@ markAsLastActive ? markAsLastActive.dataset.icingaDetailFilter : toActiveItem.dataset.icingaDetailFilter ); _this.scrollItemIntoView(toActiveItem, event.key); - _this.addSelectionCountToFooter(list); _this.loadDetailUrl(list); } @@ -384,20 +264,6 @@ return [toActiveItem, markAsLastActive]; } - /** - * Select All list items - * - * @param list The action list - */ - selectAll(list) { - let allItems = this.getAllItems(list); - let activeItems = this.getActiveItems(list); - this.setActive(allItems.filter(item => ! activeItems.includes(item))); - this.setLastActivatedItemUrl(allItems[allItems.length - 1].dataset.icingaDetailFilter); - this.addSelectionCountToFooter(list); - this.loadDetailUrl(list); - } - /** * Clear the selection by removing .active class * @@ -456,12 +322,8 @@ let activeItems = this.getActiveItems(list); if (url === null) { - if (activeItems.length > 1) { - url = this.createMultiSelectUrl(activeItems); - } else { - let anchor = activeItems[0].querySelector('[href]'); - url = anchor ? anchor.getAttribute('href') : null; - } + let anchor = activeItems[0].querySelector('[href]'); + url = anchor ? anchor.getAttribute('href') : null; } if (url === null) { @@ -560,7 +422,6 @@ this.setActive(toActiveItem); this.setLastActivatedItemUrl(toActiveItem.dataset.icingaDetailFilter); this.scrollItemIntoView(toActiveItem, pressedKey); - this.addSelectionCountToFooter(toActiveItem.parentElement); this.loadDetailUrl(toActiveItem.parentElement); return; } @@ -645,35 +506,11 @@ return req; } - /** - * Create the detail url for multi selectable list - * - * @param items List items - * @param withBaseUrl Default to true - * - * @returns {string} The url - */ - createMultiSelectUrl(items, withBaseUrl = true) { - let filters = []; - items.forEach(item => { - filters.push(item.getAttribute('data-icinga-multiselect-filter')); - }); - - let url = '?' + filters.join('|'); - - if (withBaseUrl) { - return items[0].closest('.action-list-kubernetes').getAttribute('data-icinga-multiselect-url') + url; - } - - return url; - } - onColumnClose(event) { let _this = event.data.self; let list = _this.findDetailUrlActionList(document.getElementById('col1')); - if (list && list.matches('[data-icinga-multiselect-url], [data-icinga-detail-url]')) { + if (list && list.matches('[data-icinga-detail-url]')) { _this.clearSelection(_this.getActiveItems(list)); - _this.addSelectionCountToFooter(list); } } @@ -691,9 +528,7 @@ let detailItem = container.querySelector( '[data-icinga-detail-filter="' - + detailUrl.query.replace('?', '') + '"],' + - '[data-icinga-multiselect-filter="' - + detailUrl.query.split('|', 1).toString().replace('?', '') + '"]' + + detailUrl.query.replace('?', '') + '"]' ); return detailItem ? detailItem.parentElement : null; @@ -764,22 +599,12 @@ } } - if (list && list.matches('[data-icinga-multiselect-url], [data-icinga-detail-url]')) { + if (list && list.matches('[data-icinga-detail-url]')) { let detailUrl = _this.icinga.utils.parseUrl( _this.icinga.history.getCol2State().replace(/^#!/, '') ); let toActiveItems = []; - if (list.dataset.icingaMultiselectUrl === detailUrl.path) { - for (const filter of _this.parseSelectionQuery(detailUrl.query.slice(1))) { - let item = list.querySelector( - '[data-icinga-multiselect-filter="' + filter + '"]' - ); - - if (item) { - toActiveItems.push(item); - } - } - } else if (_this.matchesDetailUrl(list.dataset.icingaDetailUrl, detailUrl.path)) { + if (_this.matchesDetailUrl(list.dataset.icingaDetailUrl, detailUrl.path)) { let item = list.querySelector( '[data-icinga-detail-filter="' + detailUrl.query.slice(1) + '"]' ); @@ -797,13 +622,6 @@ _this.clearSelection(_this.getAllItems(list).filter(item => ! toActiveItems.includes(item))); _this.setActive(toActiveItems); } - - if (isTopLevelContainer) { - let footerList = list ?? container.querySelector('.content > .action-list-kubernetes'); - if (footerList) { - _this.addSelectionCountToFooter(footerList); - } - } } matchesDetailUrl(itemUrl, detailUrl) { From ef40158a6064c750102ec8fd3817c125a112a546 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Fri, 21 Feb 2025 13:44:57 +0100 Subject: [PATCH 30/37] Remove load more feature from action list --- public/js/action-list.js | 120 +-------------------------------------- 1 file changed, 1 insertion(+), 119 deletions(-) diff --git a/public/js/action-list.js b/public/js/action-list.js index 7f0e3fb0..f3aa5ccc 100644 --- a/public/js/action-list.js +++ b/public/js/action-list.js @@ -17,12 +17,8 @@ this.on('rendered', '#main .container.module-kubernetes:has(.action-list-kubernetes)', this.onRendered, this); this.on('keydown', '#body', this.onKeyDown, this); - this.on('click', '.load-more[data-no-icinga-ajax] a', this.onLoadMoreClick, this); - this.on('keypress', '.load-more[data-no-icinga-ajax] a', this.onKeyPress, this); - this.lastActivatedItemUrl = null; this.lastTimeoutId = null; - this.isProcessingLoadMore = false; this.activeRequests = {}; } @@ -130,8 +126,7 @@ let focusedElement = document.activeElement; if ( - _this.isProcessingLoadMore - || ! event.key // input auto-completion is triggered + ! event.key // input auto-completion is triggered || (event.key.toLowerCase() !== 'a' && ! pressedArrowDownKey && ! pressedArrowUpKey) ) { return; @@ -180,19 +175,10 @@ toActiveItem = pressedArrowDownKey ? firstListItem : lastListItem; // reset all on manual page refresh _this.clearSelection(activeItems); - if (toActiveItem.classList.contains('load-more')) { - toActiveItem = toActiveItem.previousElementSibling; - } } else { toActiveItem = directionalNextItem ?? lastActivatedItem; if (toActiveItem) { - if (toActiveItem.classList.contains('load-more')) { - clearTimeout(_this.lastTimeoutId); - _this.handleLoadMoreNavigate(toActiveItem, lastActivatedItem, event.key); - return; - } - _this.clearSelection(activeItems); if (toActiveItem.classList.contains('page-separator')) { toActiveItem = _this.getDirectionalNext(toActiveItem, event.key); @@ -402,110 +388,6 @@ return Array.from(items); } - /** - * Handle the navigation on load-more button - * - * @param loadMoreElement - * @param lastActivatedItem - * @param pressedKey Pressed key (`ArrowUp` or `ArrowDown`) - */ - handleLoadMoreNavigate(loadMoreElement, lastActivatedItem, pressedKey) { - let req = this.loadMore(loadMoreElement.firstChild); - this.isProcessingLoadMore = true; - req.done(() => { - this.isProcessingLoadMore = false; - // list has now new items, so select the lastActivatedItem and then move forward - let toActiveItem = lastActivatedItem.nextElementSibling; - while (toActiveItem) { - if (toActiveItem.hasAttribute('data-action-item')) { - this.clearSelection([lastActivatedItem]); - this.setActive(toActiveItem); - this.setLastActivatedItemUrl(toActiveItem.dataset.icingaDetailFilter); - this.scrollItemIntoView(toActiveItem, pressedKey); - this.loadDetailUrl(toActiveItem.parentElement); - return; - } - - toActiveItem = toActiveItem.nextElementSibling; - } - }); - } - - /** - * Click on load-more button - * - * @param event - * - * @returns {boolean} - */ - onLoadMoreClick(event) { - event.stopPropagation(); - event.preventDefault(); - - event.data.self.loadMore(event.target); - - return false; - } - - onKeyPress(event) { - if (event.key === ' ') { // space - event.data.self.onLoadMoreClick(event); - } - } - - /** - * Load more list items based on the given anchor - * - * @param anchor - * - * @returns {*|{getAllResponseHeaders: function(): *|null, abort: function(*): this, setRequestHeader: function(*, *): this, readyState: number, getResponseHeader: function(*): null|*, overrideMimeType: function(*): this, statusCode: function(*): this}|jQuery|boolean} - */ - loadMore(anchor) { - let showMore = anchor.parentElement; - var progressTimer = this.icinga.timer.register(function () { - var label = anchor.innerText; - - var dots = label.substr(-3); - if (dots.slice(0, 1) !== '.') { - dots = '. '; - } else { - label = label.slice(0, -3); - if (dots === '...') { - dots = '. '; - } else if (dots === '.. ') { - dots = '...'; - } else if (dots === '. ') { - dots = '.. '; - } - } - - anchor.innerText = label + dots; - }, null, 250); - - let url = anchor.getAttribute('href'); - let req = this.icinga.loader.loadUrl( - // Add showCompact, we don't want controls in paged results - this.icinga.utils.addUrlFlag(url, 'showCompact'), - $(showMore.parentElement), - undefined, - undefined, - 'append', - false, - progressTimer - ); - req.addToHistory = false; - req.done(function () { - showMore.remove(); - - // Set data-icinga-url to make it available for Icinga.History.getCurrentState() - req.$target.closest('.container').data('icingaUrl', url); - - this.icinga.history.replaceCurrentState(); - }); - - return req; - } - onColumnClose(event) { let _this = event.data.self; let list = _this.findDetailUrlActionList(document.getElementById('col1')); From 1dfb03d3a9749d578cbc506ea56bce28c4120ad6 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Mon, 24 Feb 2025 08:42:35 +0100 Subject: [PATCH 31/37] Add priority column to favorites When inserting a new favorite, the new favorite gets the priority + 1 of the favorite with the currently highest priority. If no favorite is stored for the kind the new favorite gets the priority 0. When deleting a favorite, all favorites with higher priority are decremented by 1. --- .../controllers/FavoriteController.php | 51 +++++++++++++++++++ library/Kubernetes/Model/Favorite.php | 2 + 2 files changed, 53 insertions(+) diff --git a/application/controllers/FavoriteController.php b/application/controllers/FavoriteController.php index 7156f22e..95b4c8f6 100644 --- a/application/controllers/FavoriteController.php +++ b/application/controllers/FavoriteController.php @@ -9,7 +9,10 @@ use Icinga\Module\Kubernetes\Common\Database; use Icinga\Module\Kubernetes\Forms\FavorForm; use Icinga\Module\Kubernetes\Forms\UnfavorForm; +use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Web\Controller; +use ipl\Sql\Expression; +use ipl\Stdlib\Filter; use Throwable; class FavoriteController extends Controller @@ -29,12 +32,24 @@ public function favorAction(): void $username = Auth::getInstance()->getUser()->getUsername(); try { + $highestPriorityFavorite = Favorite::on($db) + ->columns('priority') + ->filter( + Filter::all( + Filter::equal('kind', $kind), + Filter::equal('username', $username) + ) + ) + ->orderBy('priority', SORT_DESC) + ->first(); + $db->insert( 'favorite', [ 'resource_uuid' => $uuid, 'kind' => $kind, 'username' => $username, + 'priority' => ($highestPriorityFavorite?->priority ?? -1) + 1, ] ); } catch (Throwable $e) { @@ -62,6 +77,19 @@ public function unfavorAction(): void $uuid = $this->params->get('uuid'); $username = Auth::getInstance()->getUser()->getUsername(); try { + $transactionStarted = false; + if (! $db->inTransaction()) { + $transactionStarted = true; + $db->beginTransaction(); + } + + $favoriteToDelete = Favorite::on($db) + ->filter(Filter::all( + Filter::equal('resource_uuid', $uuid), + Filter::equal('username', $username) + )) + ->first(); + $db->delete( 'favorite', [ @@ -69,6 +97,29 @@ public function unfavorAction(): void 'username = ?' => $username, ] ); + + $affectedFavorites = Favorite::on($db) + ->columns(['resource_uuid', 'username']) + ->filter( + Filter::all( + Filter::equal('kind', $favoriteToDelete->kind), + Filter::equal('username', $username), + Filter::greaterThan('priority', $favoriteToDelete->priority) + ) + ) + ->orderBy('priority', SORT_ASC); + + foreach ($affectedFavorites as $favorite) { + $db->update( + 'favorite', + ['priority' => new Expression('priority - 1')], + ['resource_uuid = ?' => $favorite->resource_uuid, 'username = ?' => $favorite->username] + ); + } + + if ($transactionStarted) { + $db->commitTransaction(); + } } catch (Throwable $e) { Logger::error($e); Logger::error($e->getTraceAsString()); diff --git a/library/Kubernetes/Model/Favorite.php b/library/Kubernetes/Model/Favorite.php index d69ed3b4..9d152afd 100644 --- a/library/Kubernetes/Model/Favorite.php +++ b/library/Kubernetes/Model/Favorite.php @@ -56,6 +56,7 @@ public function getColumnDefinitions(): array 'resource_uuid' => $this->translate('Resource UUID'), 'kind' => $this->translate('Resource Kind'), 'username' => $this->translate('Username'), + 'priority' => $this->translate('Priority'), ]; } @@ -65,6 +66,7 @@ public function getColumns(): array 'resource_uuid', 'kind', 'username', + 'priority', ]; } From b340f9b8f6f71e15ee7ca2d4e57921293e12764e Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 27 Feb 2025 09:35:52 +0100 Subject: [PATCH 32/37] Add toggle to show only favorites --- .../controllers/ConfigmapsController.php | 5 ++ .../controllers/CronjobsController.php | 5 ++ .../controllers/DaemonsetsController.php | 5 ++ .../controllers/DeploymentsController.php | 5 ++ application/controllers/EventsController.php | 5 ++ .../controllers/IngressesController.php | 5 ++ application/controllers/JobsController.php | 5 ++ .../controllers/NamespacesController.php | 5 ++ application/controllers/NodesController.php | 5 ++ .../PersistentvolumeclaimsController.php | 5 ++ .../PersistentvolumesController.php | 5 ++ application/controllers/PodsController.php | 5 ++ .../controllers/ReplicasetsController.php | 5 ++ application/controllers/SecretsController.php | 5 ++ .../controllers/ServicesController.php | 5 ++ .../controllers/StatefulsetsController.php | 5 ++ library/Kubernetes/Web/FavoriteToggle.php | 57 ++++++++++++++++ library/Kubernetes/Web/ListController.php | 67 ++++++++++++++++++- public/css/common.less | 14 ++-- public/css/widgets.less | 1 - 20 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 library/Kubernetes/Web/FavoriteToggle.php diff --git a/application/controllers/ConfigmapsController.php b/application/controllers/ConfigmapsController.php index a20876af..ec84d246 100644 --- a/application/controllers/ConfigmapsController.php +++ b/application/controllers/ConfigmapsController.php @@ -47,4 +47,9 @@ protected function getIgnoredViewModes(): array { return [ViewModeSwitcher::VIEW_MODE_COMMON, ViewModeSwitcher::VIEW_MODE_DETAILED]; } + + protected function getFavorable(): bool + { + return false; + } } diff --git a/application/controllers/CronjobsController.php b/application/controllers/CronjobsController.php index 77a3d3dd..a62d9c3a 100644 --- a/application/controllers/CronjobsController.php +++ b/application/controllers/CronjobsController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_CRON_JOBS; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/DaemonsetsController.php b/application/controllers/DaemonsetsController.php index 59edd19f..6013c4be 100644 --- a/application/controllers/DaemonsetsController.php +++ b/application/controllers/DaemonsetsController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_DAEMON_SETS; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/DeploymentsController.php b/application/controllers/DeploymentsController.php index 8ec8d9f4..9db1f412 100644 --- a/application/controllers/DeploymentsController.php +++ b/application/controllers/DeploymentsController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_DEPLOYMENTS; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/EventsController.php b/application/controllers/EventsController.php index b5600d63..67b13920 100644 --- a/application/controllers/EventsController.php +++ b/application/controllers/EventsController.php @@ -57,4 +57,9 @@ protected function getIgnoredViewModes(): array { return [ViewModeSwitcher::VIEW_MODE_DETAILED]; } + + protected function getFavorable(): bool + { + return false; + } } diff --git a/application/controllers/IngressesController.php b/application/controllers/IngressesController.php index 430c69a8..98c2b082 100644 --- a/application/controllers/IngressesController.php +++ b/application/controllers/IngressesController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_INGRESSES; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/JobsController.php b/application/controllers/JobsController.php index 5451c7dc..a4bef2f6 100644 --- a/application/controllers/JobsController.php +++ b/application/controllers/JobsController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_JOBS; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/NamespacesController.php b/application/controllers/NamespacesController.php index fe421176..cc3bb4f8 100644 --- a/application/controllers/NamespacesController.php +++ b/application/controllers/NamespacesController.php @@ -40,4 +40,9 @@ protected function getPermission(): string { return Auth::SHOW_NAMESPACES; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/NodesController.php b/application/controllers/NodesController.php index 39e68740..1b7fa7f0 100644 --- a/application/controllers/NodesController.php +++ b/application/controllers/NodesController.php @@ -40,4 +40,9 @@ protected function getPermission(): string { return Auth::SHOW_NODES; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/PersistentvolumeclaimsController.php b/application/controllers/PersistentvolumeclaimsController.php index 1890abc6..5ba11ff9 100644 --- a/application/controllers/PersistentvolumeclaimsController.php +++ b/application/controllers/PersistentvolumeclaimsController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_PERSISTENT_VOLUME_CLAIMS; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/PersistentvolumesController.php b/application/controllers/PersistentvolumesController.php index b3d9b738..8148c8d8 100644 --- a/application/controllers/PersistentvolumesController.php +++ b/application/controllers/PersistentvolumesController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_PERSISTENT_VOLUMES; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/PodsController.php b/application/controllers/PodsController.php index d65861a2..99d6fc1b 100644 --- a/application/controllers/PodsController.php +++ b/application/controllers/PodsController.php @@ -43,4 +43,9 @@ protected function getPermission(): string { return Auth::SHOW_PODS; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/ReplicasetsController.php b/application/controllers/ReplicasetsController.php index e46a0862..9014076d 100644 --- a/application/controllers/ReplicasetsController.php +++ b/application/controllers/ReplicasetsController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_REPLICA_SETS; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/SecretsController.php b/application/controllers/SecretsController.php index ba2226e5..2cbc04c2 100644 --- a/application/controllers/SecretsController.php +++ b/application/controllers/SecretsController.php @@ -47,4 +47,9 @@ protected function getIgnoredViewModes(): array { return [ViewModeSwitcher::VIEW_MODE_DETAILED]; } + + protected function getFavorable(): bool + { + return false; + } } diff --git a/application/controllers/ServicesController.php b/application/controllers/ServicesController.php index da904c81..f476ac79 100644 --- a/application/controllers/ServicesController.php +++ b/application/controllers/ServicesController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_SERVICES; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/application/controllers/StatefulsetsController.php b/application/controllers/StatefulsetsController.php index 7a7e639f..6143b1a0 100644 --- a/application/controllers/StatefulsetsController.php +++ b/application/controllers/StatefulsetsController.php @@ -41,4 +41,9 @@ protected function getPermission(): string { return Auth::SHOW_STATEFUL_SETS; } + + protected function getFavorable(): bool + { + return true; + } } diff --git a/library/Kubernetes/Web/FavoriteToggle.php b/library/Kubernetes/Web/FavoriteToggle.php new file mode 100644 index 00000000..c2589098 --- /dev/null +++ b/library/Kubernetes/Web/FavoriteToggle.php @@ -0,0 +1,57 @@ +favoriteParam; + } + + /** + * Set the name of the URL parameter which stores whether to show the favorites + * + * @param string $favoriteParam + * + * @return $this + */ + public function setFavoriteParam($favoriteParam): self + { + $this->favoriteParam = $favoriteParam; + + return $this; + } + + protected function assemble(): void + { + $this->addAttributes(['class' => 'favorite-toggle inline']); + + $this->addElement( + 'checkbox', + self::DEFAULT_FAVORITE_PARAM, + [ + 'label' => 'Favorites Only', + 'class' => 'autosubmit', + ] + ); + } +} diff --git a/library/Kubernetes/Web/ListController.php b/library/Kubernetes/Web/ListController.php index efba4f37..6833205c 100644 --- a/library/Kubernetes/Web/ListController.php +++ b/library/Kubernetes/Web/ListController.php @@ -60,17 +60,25 @@ public function indexAction(): void $q->filter(Filter::equal('cluster_uuid', Uuid::fromString($clusterUuid)->getBytes())); } + if ($this->getFavorable()) { + $favoriteToggle = $this->createFavoriteToggle($q); + } + $limitControl = $this->createLimitControl(); - $sortControl = $this->createSortControl($q, $this->getSortColumns()); + $sortControl = $this->createSortControl( + $q, + $this->getSortColumns() + + ($favoriteToggleActive ? ['favorite.priority desc' => 'Custom Order'] : []) + ); $paginationControl = $this->createPaginationControl($q); - $viewModeSwitcher = $this->createViewModeSwitcher($paginationControl, $limitControl); $searchBar = $this->createSearchBar($q, [ $limitControl->getLimitParam(), $sortControl->getSortParam(), $viewModeSwitcher->getViewModeParam(), - 'columns' + (isset($favoriteToggle) ? $favoriteToggle->getFavoriteParam() : ''), + 'columns', ]); if ($searchBar->hasBeenSent() && ! $searchBar->isValid()) { @@ -92,6 +100,9 @@ public function indexAction(): void $this->addControl($sortControl); $this->addControl($limitControl); $this->addControl($viewModeSwitcher); + if ($this->getFavorable()) { + $this->addControl($favoriteToggle); + } $this->addControl($searchBar); $contentClass = $this->getContentClass(); @@ -110,6 +121,8 @@ abstract protected function getContentClass(): string; abstract protected function getPermission(): string; + abstract protected function getFavorable(): bool; + protected function getIgnoredViewModes(): array { return []; @@ -285,4 +298,52 @@ function (ViewModeSwitcher $viewModeSwitcher) use ( return $viewModeSwitcher; } + + /** + * Create and return the FavoriteToggle + * + * This automatically shifts the favorite URL parameter from {@link $params}. + * + * @param Query $query + * + * @return FavoriteToggle + */ + public function createFavoriteToggle( + Query $query + ): FavoriteToggle { + $favoriteToggle = new FavoriteToggle(); + $defaultFavoriteParam = $favoriteToggle->getFavoriteParam(); + $favoriteParam = $this->params->shift($defaultFavoriteParam); + $favoriteToggle->populate([ + $defaultFavoriteParam => $favoriteParam + ]); + + $favoriteToggle->on(FavoriteToggle::ON_SUCCESS, function (FavoriteToggle $favoriteToggle) use ( + $query, + $defaultFavoriteParam + ) { + $favoriteParam = $favoriteToggle->getValue($defaultFavoriteParam); + + $requestUrl = Url::fromRequest(); + + // Redirect if favorite param has changed to update the URL + if (isset($favoriteParam) && $requestUrl->getParam($defaultFavoriteParam) !== $favoriteParam) { + $requestUrl->setParam($defaultFavoriteParam, $favoriteParam); + if ( + $favoriteParam === 'n' + && $requestUrl->getParam(SortControl::DEFAULT_SORT_PARAM) === 'favorite.priority desc' + ) { + $requestUrl->remove(SortControl::DEFAULT_SORT_PARAM); + } + + $this->redirectNow($requestUrl); + } + })->handleRequest($this->getServerRequest()); + + if ($favoriteToggle->getValue($defaultFavoriteParam) === 'y') { + $query->with('favorite')->filter(Filter::equal('favorite.username', Auth::getInstance()->getUser()->getUsername())); + } + + return $favoriteToggle; + } } diff --git a/public/css/common.less b/public/css/common.less index 0a2386a4..8f2ffa05 100644 --- a/public/css/common.less +++ b/public/css/common.less @@ -48,8 +48,6 @@ pre { } .favorite-toggle { - margin-right: 1em; - float: right; width: auto; .control-group { @@ -59,17 +57,25 @@ pre { label { text-align: right; + margin-right: 0; } } } .limit-control, .view-mode-switcher, - .sort-control { - margin-left: .5em; + .sort-control, + .favorite-toggle { + margin-left: 1em; float: right; } + .limit-control, + .view-mode-switcher, + .favorite-toggle { + margin-right: 0; + } + .item-list .list-item { .main { padding: 3px 0; diff --git a/public/css/widgets.less b/public/css/widgets.less index b155549b..65423b66 100644 --- a/public/css/widgets.less +++ b/public/css/widgets.less @@ -100,7 +100,6 @@ .view-mode-switcher { list-style-type: none; - margin: 0 0 0.25em 0; padding: 0; display: flex; From 40992197326e2085117fde41e40f0902b1abbb86 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 27 Feb 2025 15:48:57 +0100 Subject: [PATCH 33/37] Add reordering via drag & drop --- library/Kubernetes/Common/BaseListItem.php | 16 ++ .../Kubernetes/Common/DefaultListItemMain.php | 18 +++ library/Kubernetes/Common/Links.php | 6 + library/Kubernetes/Web/Factory.php | 1 + library/Kubernetes/Web/ListController.php | 36 ++++- library/Kubernetes/Web/MoveFavoriteForm.php | 138 ++++++++++++++++++ public/css/action-list.less | 12 ++ public/css/common.less | 32 ++++ public/js/action-list.js | 55 +++++++ 9 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 library/Kubernetes/Web/MoveFavoriteForm.php diff --git a/library/Kubernetes/Common/BaseListItem.php b/library/Kubernetes/Common/BaseListItem.php index 3f4ab6c5..b12479d8 100644 --- a/library/Kubernetes/Common/BaseListItem.php +++ b/library/Kubernetes/Common/BaseListItem.php @@ -4,9 +4,12 @@ namespace Icinga\Module\Kubernetes\Common; +use Icinga\Module\Kubernetes\Web\Factory; +use Icinga\Module\Kubernetes\Web\MoveFavoriteForm; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; use ipl\Html\HtmlElement; +use Ramsey\Uuid\Uuid; /** * Base class for list items @@ -63,6 +66,19 @@ public function setIsFavorite(bool $isFavorite): self protected function assemble(): void { + if (isset($this->item->favorite->priority)) { + $this->add( + (new MoveFavoriteForm()) + ->setAction( + Links::moveFavorite(Factory::canonicalizeKind($this->item->getTableAlias()))->getAbsoluteUrl() + ) + ->populate([ + 'uuid' => Uuid::fromBytes($this->item->uuid)->toString(), + 'priority' => $this->item->favorite->priority, + ]) + ->addAttributes(['data-base-target' => '_self']), + ); + } $this->add([ $this->createVisual(), $this->createMain() diff --git a/library/Kubernetes/Common/DefaultListItemMain.php b/library/Kubernetes/Common/DefaultListItemMain.php index 55bf0236..17a02a7f 100644 --- a/library/Kubernetes/Common/DefaultListItemMain.php +++ b/library/Kubernetes/Common/DefaultListItemMain.php @@ -3,7 +3,10 @@ namespace Icinga\Module\Kubernetes\Common; use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; +use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; +use ipl\Html\Html; +use ipl\Web\Widget\Icon; trait DefaultListItemMain { @@ -18,5 +21,20 @@ protected function assembleMain(BaseHtmlElement $main): void if ($this->viewMode !== ViewModeSwitcher::VIEW_MODE_MINIMAL) { $main->addHtml($this->createFooter()); } + + if (isset($this->item->favorite->priority)) { + // Add background span with same color as the main background to ensure correct + // coloring in both dark and light mode. + $reorderHandle = Html::tag( + 'span', + Attributes::create(['class' => 'reorder-handle-background']), + Html::tag( + 'span', + Attributes::create(['class' => 'reorder-handle-container']), + new Icon('bars', Attributes::create(['data-drag-initiator' => ''])) + ) + ); + $this->addHtml($reorderHandle); + } } } diff --git a/library/Kubernetes/Common/Links.php b/library/Kubernetes/Common/Links.php index b1278985..8ba08731 100644 --- a/library/Kubernetes/Common/Links.php +++ b/library/Kubernetes/Common/Links.php @@ -23,6 +23,7 @@ use Icinga\Module\Kubernetes\Model\Service; use Icinga\Module\Kubernetes\Model\SidecarContainer; use Icinga\Module\Kubernetes\Model\StatefulSet; +use Icinga\Module\Kubernetes\Web\Factory; use ipl\Web\Url; use Ramsey\Uuid\Uuid; @@ -141,4 +142,9 @@ public static function unfavor(string $uuid): Url { return Url::fromPath('kubernetes/favorite/unfavor', ['uuid' => $uuid]); } + + public static function moveFavorite(string $kind): Url + { + return Url::fromPath(Factory::createListUrl($kind) . '/move-favorite'); + } } diff --git a/library/Kubernetes/Web/Factory.php b/library/Kubernetes/Web/Factory.php index f7a6c21d..e496eed3 100644 --- a/library/Kubernetes/Web/Factory.php +++ b/library/Kubernetes/Web/Factory.php @@ -40,6 +40,7 @@ public static function canonicalizeKind(string $kind): string if ($kind === 'pvc') { return 'persistentvolumeclaim'; } + return strtolower(str_replace(['_', '-'], '', $kind)); } diff --git a/library/Kubernetes/Web/ListController.php b/library/Kubernetes/Web/ListController.php index 6833205c..be6cd6ef 100644 --- a/library/Kubernetes/Web/ListController.php +++ b/library/Kubernetes/Web/ListController.php @@ -9,8 +9,10 @@ use Icinga\Application\Config; use Icinga\Application\Logger; use Icinga\Data\ConfigObject; +use Icinga\Exception\Http\HttpMethodNotAllowedException; use Icinga\Exception\Json\JsonDecodeException; use Icinga\Module\Kubernetes\Common\Auth; +use Icinga\Module\Kubernetes\Common\Database; use Icinga\Module\Kubernetes\TBD\ObjectSuggestions; use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; @@ -60,8 +62,10 @@ public function indexAction(): void $q->filter(Filter::equal('cluster_uuid', Uuid::fromString($clusterUuid)->getBytes())); } + $favoriteToggleActive = false; if ($this->getFavorable()) { $favoriteToggle = $this->createFavoriteToggle($q); + $favoriteToggleActive = $favoriteToggle->getValue($favoriteToggle->getFavoriteParam()) === 'y'; } $limitControl = $this->createLimitControl(); @@ -96,9 +100,19 @@ public function indexAction(): void $q->filter($filter); + if ($sortControl->getValue($sortControl->getSortParam()) === 'favorite.priority desc') { + $this->content->addAttributes(['class' => 'custom-sortable']); + } + + if ($favoriteToggleActive) { + $paginationControl->setDefaultPageSize(1000); + } + $this->addControl($paginationControl); $this->addControl($sortControl); - $this->addControl($limitControl); + if (! $favoriteToggleActive) { + $this->addControl($limitControl); + } $this->addControl($viewModeSwitcher); if ($this->getFavorable()) { $this->addControl($favoriteToggle); @@ -113,6 +127,26 @@ public function indexAction(): void } } + /** + * Handle the reordering via drag & drop. + * + * @return void + * + * @throws HttpMethodNotAllowedException + */ + public function moveFavoriteAction(): void + { + $this->assertHttpMethod('POST'); + + (new MoveFavoriteForm(Database::connection())) + ->on(MoveFavoriteForm::ON_SUCCESS, function () { + // Suppress handling XHR response and disable view rendering, + // so we can use the form in the list without the page reloading. + $this->getResponse()->setHeader('X-Icinga-Container', 'ignore', true); + $this->_helper->viewRenderer->setNoRender(); + })->handleRequest($this->getServerRequest()); + } + abstract protected function getTitle(): string; abstract protected function getSortColumns(): array; diff --git a/library/Kubernetes/Web/MoveFavoriteForm.php b/library/Kubernetes/Web/MoveFavoriteForm.php new file mode 100644 index 00000000..187ed766 --- /dev/null +++ b/library/Kubernetes/Web/MoveFavoriteForm.php @@ -0,0 +1,138 @@ + true]; + + protected $method = 'POST'; + + /** @var Connection */ + protected $db; + + /** @var string */ + protected $kind; + + /** + * Create a new MoveFavoriteForm + * + * @param ?Connection $db + */ + public function __construct(Connection $db = null) + { + $this->db = $db; + } + + /** + * Get the kind + * + * @return string + */ + public function getKind(): string + { + if ($this->kind === null) { + throw new LogicException('The form must be successfully submitted first'); + } + + return $this->kind; + } + + protected function assemble(): void + { + $this->addElement('hidden', 'uuid', ['required' => true]); + $this->addElement('hidden', 'priority', ['required' => true]); + } + + protected function onSuccess(): void + { + $favoriteUuid = Uuid::fromString($this->getValue('uuid'))->getBytes(); + $newPriority = $this->getValue('priority'); + + /** @var ?Favorite $favorite */ + $favorite = Favorite::on($this->db) + ->columns(['kind', 'priority']) + ->filter(Filter::all( + Filter::equal('resource_uuid', $favoriteUuid), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + )) + ->first(); + if ($favorite === null) { + throw new HttpNotFoundException('Favorite not found'); + } + + $transactionStarted = ! $this->db->inTransaction(); + if ($transactionStarted) { + $this->db->beginTransaction(); + } + + $this->kind = $favorite->kind; + + // Free up the current priority used by the favorite in question + $this->db->update('favorite', ['priority' => null], ['resource_uuid = ?' => $favoriteUuid]); + + // Update the priorities of the favorites that are affected by the move + if ($newPriority < $favorite->priority) { + $affectedFavorites = $this->db->select( + (new Select()) + ->columns('resource_uuid') + ->from('favorite') + ->where([ + 'kind = ?' => $favorite->kind, + 'priority >= ?' => $newPriority, + 'priority < ?' => $favorite->priority + ]) + ->orderBy('priority', SORT_DESC) + ); + foreach ($affectedFavorites as $affectedFavorite) { + $this->db->update( + 'favorite', + ['priority' => new Expression('priority + 1')], + ['resource_uuid = ?' => $affectedFavorite->resource_uuid] + ); + } + } elseif ($newPriority > $favorite->priority) { + $affectedFavorites = $this->db->select( + (new Select()) + ->columns('resource_uuid') + ->from('favorite') + ->where([ + 'kind = ?' => $favorite->kind, + 'priority > ?' => $favorite->priority, + 'priority <= ?' => $newPriority + ]) + ->orderBy('priority ASC') + ); + foreach ($affectedFavorites as $affectedFavorite) { + $this->db->update( + 'favorite', + ['priority' => new Expression('priority - 1')], + ['resource_uuid = ?' => $affectedFavorite->resource_uuid] + ); + } + } + + // Now insert the favorite at the new priority + $this->db->update('favorite', ['priority' => $newPriority], ['resource_uuid = ?' => $favoriteUuid]); + + if ($transactionStarted) { + $this->db->commitTransaction(); + } + } +} diff --git a/public/css/action-list.less b/public/css/action-list.less index 8ea92d39..5e53ce39 100644 --- a/public/css/action-list.less +++ b/public/css/action-list.less @@ -1,6 +1,10 @@ /* Icinga for Kubernetes Web | (c) 2024 Icinga GmbH | AGPLv3 */ .action-list-kubernetes { + [data-action-item] { + position: relative; + } + [data-action-item].active { background-color: @tr-active-color; } @@ -10,3 +14,11 @@ cursor: pointer; } } + +.custom-sortable [data-action-item]:hover .reorder-handle-background { + display: block; +} + +.sortable-drag { + background-color: @menu-active-bg-color !important; +} diff --git a/public/css/common.less b/public/css/common.less index 8f2ffa05..b1feddb8 100644 --- a/public/css/common.less +++ b/public/css/common.less @@ -132,3 +132,35 @@ pre { .pvc-phase-lost { color: @color-critical; } + +.reorder-handle-background { + position: absolute; + right: 0; + bottom: 0.25em; + + display: none; + + height: ~"calc(100% - 0.5em)"; + width: 3em; + background-color: @body-bg-color; +} + +.reorder-handle-container { + display: flex; + justify-content: center; + align-items: center; + + width: 100%; + height: 100%; + + border-left: 1px solid @gray-light; + background-color: @tr-hover-color; + + .icon { + cursor: grab; + + &:active { + cursor: grabbing; + } + } +} diff --git a/public/js/action-list.js b/public/js/action-list.js index f3aa5ccc..64c3fc5c 100644 --- a/public/js/action-list.js +++ b/public/js/action-list.js @@ -4,6 +4,13 @@ "use strict"; + try { + var Sortable = require('icinga/icinga-php-library/vendor/Sortable'); + } catch (e) { + console.warn('Unable to provide Drag&Drop in the favorite lists. Libraries not available:', e); + return; + } + Icinga.Behaviors = Icinga.Behaviors || {}; class ActionList extends Icinga.EventListener { @@ -17,6 +24,9 @@ this.on('rendered', '#main .container.module-kubernetes:has(.action-list-kubernetes)', this.onRendered, this); this.on('keydown', '#body', this.onKeyDown, this); + this.on('rendered', '#main .container.module-kubernetes:has(.action-list-kubernetes)', this.onRenderedReorder, this); + this.on('end', '.action-list-kubernetes', this.onDropReorder, this) + this.lastActivatedItemUrl = null; this.lastTimeoutId = null; this.activeRequests = {}; @@ -514,6 +524,51 @@ // The slash is used to avoid false positives (e.g. icingadb/hostgroup and icingadb/host) return detailUrl.startsWith(itemUrl + '/'); } + + onRenderedReorder(event) { + if (event.target !== event.currentTarget) { + return; // Nested containers are not of interest + } + + const favoriteList = event.target.querySelector('.action-list-kubernetes'); + if (! favoriteList) { + return; + } + + Sortable.create(favoriteList, { + scroll: true, + direction: 'vertical', + draggable: '.list-item', + handle: '[data-drag-initiator]', + }); + } + + onDropReorder(event) { + event = event.originalEvent; + if (event.to === event.from && event.newIndex === event.oldIndex) { + // The user dropped the rotation at its previous position + return; + } + + const nextRow = event.item.nextSibling; + + let newPriority; + if (event.oldIndex > event.newIndex) { + // The rotation was moved up + newPriority = Number(nextRow.querySelector(':scope > form').priority.value); + } else { + // The rotation was moved down + if (nextRow !== null && nextRow.matches('.list-item')) { + newPriority = Number(nextRow.querySelector(':scope > form').priority.value) + 1; + } else { + newPriority = '0'; + } + } + + const form = event.item.querySelector(':scope > form'); + form.priority.value = newPriority; + form.requestSubmit(); + } } Icinga.Behaviors.ActionList = ActionList; From 593900d9b0c56bb49115ca7342ffbf796a1e7d6e Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Mon, 3 Mar 2025 12:00:38 +0100 Subject: [PATCH 34/37] Dashboard to show all favorites --- .../controllers/FavoritesController.php | 59 ++++++++++++++++ configuration.php | 9 +++ library/Kubernetes/Web/Factory.php | 25 ++++++- library/Kubernetes/Web/FavoriteDashboard.php | 30 +++++++++ library/Kubernetes/Web/FavoriteDashlet.php | 67 +++++++++++++++++++ public/css/common.less | 28 ++++++++ public/js/action-list.js | 2 +- 7 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 application/controllers/FavoritesController.php create mode 100644 library/Kubernetes/Web/FavoriteDashboard.php create mode 100644 library/Kubernetes/Web/FavoriteDashlet.php diff --git a/application/controllers/FavoritesController.php b/application/controllers/FavoritesController.php new file mode 100644 index 00000000..cbcc54a1 --- /dev/null +++ b/application/controllers/FavoritesController.php @@ -0,0 +1,59 @@ +addTitleTab('Favorites'); + $dashboard = new Dashboard(); + $pane = (new Pane('favorites'))->setTitle('Favorites'); + $dashboard->addPane($pane); + + foreach (self::FAVORABLE_KINDS as $kind) { + $hasFavorites = Favorite::on(Database::connection())->filter( + Filter::all( + Filter::equal('kind', $kind), + Filter::equal('username', Auth::getInstance()->getUser()->getUsername()) + ) + )->first() !== null; + if ($hasFavorites) { + $dashlet = new Dashlet(Factory::createTitle($kind), Factory::createListUrl($kind) . '?view=minimal&show-favorites=y&sort=favorite.priority desc', $pane); + $pane->addDashlet($dashlet); + } + } + + $dashboard->activate('favorites'); + $this->addContent(new FavoriteDashboard($dashboard)); + } +} diff --git a/configuration.php b/configuration.php index dc13ad5c..76970955 100644 --- a/configuration.php +++ b/configuration.php @@ -17,6 +17,15 @@ $priority = 0; +$section->add( + N_('All Favorites'), + [ + 'description' => $this->translate('All Favorites'), + 'url' => 'kubernetes/favorites', + 'priority' => $priority++ + ] +); + $section->add( N_('Cluster Services'), [ diff --git a/library/Kubernetes/Web/Factory.php b/library/Kubernetes/Web/Factory.php index e496eed3..8a13558c 100644 --- a/library/Kubernetes/Web/Factory.php +++ b/library/Kubernetes/Web/Factory.php @@ -41,7 +41,7 @@ public static function canonicalizeKind(string $kind): string return 'persistentvolumeclaim'; } - return strtolower(str_replace(['_', '-'], '', $kind)); + return strtolower(str_replace([' ', '_', '-'], '', $kind)); } public static function createIcon(string $kind): ?ValidHtml @@ -284,6 +284,29 @@ public static function createListUrl(string $kind): ?Url return null; } + public static function createTitle(string $kind): string + { + return match ($kind) { + 'configmap' => 'Config Maps', + 'cronjob' => 'Cron Jobs', + 'daemonset' => 'Daemon Sets', + 'deployment' => 'Deployments', + 'event' => 'Events', + 'ingress' => 'Ingresses', + 'job' => 'Jobs', + 'namespace' => 'Namespaces', + 'node' => 'Nodes', + 'persistentvolume' => 'Persistent Volumes', + 'persistentvolumeclaim' => 'Persistent Volume Claims', + 'pod' => 'Pods', + 'replicaset' => 'Replica Sets', + 'secret' => 'Secrets', + 'service' => 'Services', + 'statefulset' => 'Stateful Sets', + default => null, + }; + } + public static function getKindFromModel(Model $model): string { $kind = match (true) { diff --git a/library/Kubernetes/Web/FavoriteDashboard.php b/library/Kubernetes/Web/FavoriteDashboard.php new file mode 100644 index 00000000..a442e0e6 --- /dev/null +++ b/library/Kubernetes/Web/FavoriteDashboard.php @@ -0,0 +1,30 @@ + 'favorite-dashboard']; + + public function __construct(Dashboard $dashboard) + { + $this->dashboard = $dashboard; + } + + public function assemble() + { + foreach ($this->dashboard->getActivePane()->getDashlets() as $dashlet) { + $this->add(new FavoriteDashlet($dashlet)); + } + } +} diff --git a/library/Kubernetes/Web/FavoriteDashlet.php b/library/Kubernetes/Web/FavoriteDashlet.php new file mode 100644 index 00000000..bcfb04eb --- /dev/null +++ b/library/Kubernetes/Web/FavoriteDashlet.php @@ -0,0 +1,67 @@ + 'container', + 'data-last-update' => -1, + 'data-icinga-refresh' => 60 + ]; + + public function __construct(Dashlet $dashlet) + { + $this->dashlet = $dashlet; + } + + public function assemble() + { + $url = $this->dashlet->getUrl()->setParam('showCompact'); + $fullUrl = $url->getUrlWithout(['showCompact', 'view']); + $tooltip = sprintf('Show %s', $this->dashlet->getTitle()); + $progressLabel = $this->dashlet->getProgressLabe(); + + $this->addAttributes(['data-icinga-url' => $url]); + + $this->addHtml( + Html::tag( + 'h1', + null, + Html::tag( + 'a', + Attributes::create([ + 'href' => $fullUrl, + 'aria-label' => $tooltip, + 'title' => $tooltip, + 'data-base-target' => 'col1' + ]), + $this->dashlet->getName() + ) + ), + Html::tag( + 'p', + Attributes::create(['class' => 'progress-label']), + [ + $progressLabel, + Html::tag('span', null, '.'), + Html::tag('span', null, '.'), + Html::tag('span', null, '.') + ] + ), + Html::tag('div', Attributes::create(['class' => 'content'])) + ); + } +} diff --git a/public/css/common.less b/public/css/common.less index b1feddb8..793df467 100644 --- a/public/css/common.less +++ b/public/css/common.less @@ -164,3 +164,31 @@ pre { } } } + +.favorite-dashboard { + display: flex; + flex-wrap: wrap; + gap: 1em; + + .container { + padding: 1em; + width: 100%; + + > .content { + padding: 0; + } + + > .progress-label { + margin: 0; + + span { + font-size: 0.75em; + } + } + } +} + +#layout.wide-layout:not(.twocols) .favorite-dashboard > .container:not(:only-child), +#layout.default-layout:not(.twocols) .favorite-dashboard > .container:not(:only-child) { + width: ~"calc(50% - 0.5em)"; +} diff --git a/public/js/action-list.js b/public/js/action-list.js index 64c3fc5c..33108119 100644 --- a/public/js/action-list.js +++ b/public/js/action-list.js @@ -98,7 +98,7 @@ return; } - let dashboard = list.closest('.dashboard'); + let dashboard = list.closest('.dashboard') || list.closest('.favorite-dashboard'); if (dashboard) { _this.clearDashboardSelections(dashboard, list); } From 32197b7d7480a3dd77c35c099b3856d1fb8bdc95 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Thu, 27 Feb 2025 09:35:52 +0100 Subject: [PATCH 35/37] Add toggle to show only favorites --- library/Kubernetes/Web/FavoriteToggle.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/Kubernetes/Web/FavoriteToggle.php b/library/Kubernetes/Web/FavoriteToggle.php index c2589098..ba988bea 100644 --- a/library/Kubernetes/Web/FavoriteToggle.php +++ b/library/Kubernetes/Web/FavoriteToggle.php @@ -43,7 +43,11 @@ public function setFavoriteParam($favoriteParam): self protected function assemble(): void { +<<<<<<< HEAD $this->addAttributes(['class' => 'favorite-toggle inline']); +======= + $this->addAttributes(['class' => 'favorite-toggle']); +>>>>>>> 3c8fb14 (Add toggle to show only favorites) $this->addElement( 'checkbox', From a63a8dd7add793815712ae25cd445b90ed7ca6c0 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Mon, 3 Mar 2025 12:13:28 +0100 Subject: [PATCH 36/37] Add icinga state for services --- application/controllers/ServiceController.php | 8 ++++++++ library/Kubernetes/Model/Service.php | 4 ++++ library/Kubernetes/Web/ServiceDetail.php | 6 +++++- library/Kubernetes/Web/ServiceListItem.php | 16 ++++------------ 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index aff52c58..0adb4573 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -11,6 +11,8 @@ use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\QuickActions; use Icinga\Module\Kubernetes\Web\ServiceDetail; +use Icinga\Module\Kubernetes\Web\ServiceList; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -43,6 +45,12 @@ public function indexAction(): void $this->httpNotFound($this->translate('Service not found')); } + $this->addControl( + (new ServiceList([$service])) + ->setActionList(false) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_MINIMAL) + ); + $this->addControl(new QuickActions($service, $favorite)); $this->addContent(new ServiceDetail($service)); diff --git a/library/Kubernetes/Model/Service.php b/library/Kubernetes/Model/Service.php index 9e67e5e6..b3a9e9a2 100644 --- a/library/Kubernetes/Model/Service.php +++ b/library/Kubernetes/Model/Service.php @@ -83,6 +83,8 @@ public function getColumnDefinitions(): array 'allocate_load_balancer_node_ports' => $this->translate('Allocated Load Balancer Node Ports'), 'load_balancer_class' => $this->translate('Load Balancer Class'), 'internal_traffic_policy' => $this->translate('Internal Traffic Policy'), + 'icinga_state' => $this->translate('Icinga State'), + 'icinga_state_reason' => $this->translate('Icinga State Reason'), 'yaml' => $this->translate('YAML'), 'created' => $this->translate('Created At') ]; @@ -110,6 +112,8 @@ public function getColumns(): array 'allocate_load_balancer_node_ports', 'load_balancer_class', 'internal_traffic_policy', + 'icinga_state', + 'icinga_state_reason', 'yaml', 'created' ]; diff --git a/library/Kubernetes/Web/ServiceDetail.php b/library/Kubernetes/Web/ServiceDetail.php index 3ef97936..99699f20 100644 --- a/library/Kubernetes/Web/ServiceDetail.php +++ b/library/Kubernetes/Web/ServiceDetail.php @@ -71,7 +71,11 @@ protected function assemble(): void ), $this->translate('Load Balancer Class') => $this->service->load_balancer_class ?? new EmptyState($this->translate('None')), - $this->translate('Internal Traffic Policy') => $this->service->internal_traffic_policy + $this->translate('Internal Traffic Policy') => $this->service->internal_traffic_policy, + $this->translate('Icinga State') => new DetailState($this->service->icinga_state), + $this->translate('Icinga State Reason') => new IcingaStateReason( + $this->service->icinga_state_reason + ) ])), new Labels($this->service->label), new Annotations($this->service->annotation), diff --git a/library/Kubernetes/Web/ServiceListItem.php b/library/Kubernetes/Web/ServiceListItem.php index d88f1c01..efbbe064 100644 --- a/library/Kubernetes/Web/ServiceListItem.php +++ b/library/Kubernetes/Web/ServiceListItem.php @@ -5,8 +5,10 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemCaption; use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; use Icinga\Module\Kubernetes\Common\DefaultListItemMain; +use Icinga\Module\Kubernetes\Common\DefaultListItemVisual; use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; @@ -16,19 +18,14 @@ use ipl\I18n\Translation; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; class ServiceListItem extends BaseListItem { use Translation; use DefaultListItemHeader; + use DefaultListItemCaption; use DefaultListItemMain; - - protected function assembleCaption(BaseHtmlElement $caption): void - { - // TODO add state reason then replace function by DefaultListItemCaption trait - $caption->addHtml(new Text('Placeholder for Icinga State Reason')); - } + use DefaultListItemVisual; protected function assembleFooter(BaseHtmlElement $footer): void { @@ -58,9 +55,4 @@ protected function assembleTitle(BaseHtmlElement $title): void ) ); } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - $visual->addHtml(new StateBall('none', StateBall::SIZE_MEDIUM)); - } } From cdda68478e57af162961e222f2e55ef310e74608 Mon Sep 17 00:00:00 2001 From: Johannes Rauh Date: Mon, 3 Mar 2025 12:16:22 +0100 Subject: [PATCH 37/37] Add icinga state for cron jobs --- application/controllers/CronjobController.php | 8 ++++++++ library/Kubernetes/Model/CronJob.php | 4 ++++ library/Kubernetes/Web/CronJobDetail.php | 6 +++++- library/Kubernetes/Web/CronJobListItem.php | 17 ++++------------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/application/controllers/CronjobController.php b/application/controllers/CronjobController.php index e94087ab..63e65b10 100644 --- a/application/controllers/CronjobController.php +++ b/application/controllers/CronjobController.php @@ -10,7 +10,9 @@ use Icinga\Module\Kubernetes\Model\Favorite; use Icinga\Module\Kubernetes\Web\Controller; use Icinga\Module\Kubernetes\Web\CronJobDetail; +use Icinga\Module\Kubernetes\Web\CronJobList; use Icinga\Module\Kubernetes\Web\QuickActions; +use Icinga\Module\Kubernetes\Web\ViewModeSwitcher; use ipl\Stdlib\Filter; use Ramsey\Uuid\Uuid; @@ -43,6 +45,12 @@ public function indexAction(): void $this->httpNotFound($this->translate('Cron Job not found')); } + $this->addControl( + (new CronJobList([$cronJob])) + ->setActionList(false) + ->setViewMode(ViewModeSwitcher::VIEW_MODE_MINIMAL) + ); + $this->addControl(new QuickActions($cronJob, $favorite)); $this->addContent(new CronJobDetail($cronJob)); diff --git a/library/Kubernetes/Model/CronJob.php b/library/Kubernetes/Model/CronJob.php index 9f36ce84..17fe1758 100644 --- a/library/Kubernetes/Model/CronJob.php +++ b/library/Kubernetes/Model/CronJob.php @@ -72,6 +72,8 @@ public function getColumnDefinitions(): array 'active' => $this->translate('Active'), 'last_schedule_time' => $this->translate('Last Schedule Time'), 'last_successful_time' => $this->translate('Last Successful Time'), + 'icinga_state' => $this->translate('Icinga State'), + 'icinga_state_reason' => $this->translate('Icinga State Reason'), 'yaml' => $this->translate('YAML'), 'created' => $this->translate('Created At') ]; @@ -95,6 +97,8 @@ public function getColumns(): array 'active', 'last_schedule_time', 'last_successful_time', + 'icinga_state', + 'icinga_state_reason', 'yaml', 'created' ]; diff --git a/library/Kubernetes/Web/CronJobDetail.php b/library/Kubernetes/Web/CronJobDetail.php index e5e9d7ea..cbe0c488 100644 --- a/library/Kubernetes/Web/CronJobDetail.php +++ b/library/Kubernetes/Web/CronJobDetail.php @@ -56,7 +56,11 @@ protected function assemble(): void $this->translate('Successful Jobs History Limit') => $this->cronJob->successful_jobs_history_limit, $this->translate('Failed Jobs History Limit') => $this->cronJob->failed_jobs_history_limit, $this->translate('Last Successful Time') => $lastSuccessfulTime, - $this->translate('Last Schedule Time') => $lastScheduleTime + $this->translate('Last Schedule Time') => $lastScheduleTime, + $this->translate('Icinga State') => new DetailState($this->cronJob->icinga_state), + $this->translate('Icinga State Reason') => new IcingaStateReason( + $this->cronJob->icinga_state_reason + ) ])), new Labels($this->cronJob->label), new Annotations($this->cronJob->annotation), diff --git a/library/Kubernetes/Web/CronJobListItem.php b/library/Kubernetes/Web/CronJobListItem.php index 4791d617..2253737a 100644 --- a/library/Kubernetes/Web/CronJobListItem.php +++ b/library/Kubernetes/Web/CronJobListItem.php @@ -5,8 +5,10 @@ namespace Icinga\Module\Kubernetes\Web; use Icinga\Module\Kubernetes\Common\BaseListItem; +use Icinga\Module\Kubernetes\Common\DefaultListItemCaption; use Icinga\Module\Kubernetes\Common\DefaultListItemHeader; use Icinga\Module\Kubernetes\Common\DefaultListItemMain; +use Icinga\Module\Kubernetes\Common\DefaultListItemVisual; use Icinga\Module\Kubernetes\Common\Icons; use Icinga\Module\Kubernetes\Common\Links; use ipl\Html\Attributes; @@ -17,19 +19,14 @@ use ipl\I18n\Translation; use ipl\Web\Widget\HorizontalKeyValue; use ipl\Web\Widget\Link; -use ipl\Web\Widget\StateBall; class CronJobListItem extends BaseListItem { use Translation; use DefaultListItemHeader; + use DefaultListItemCaption; use DefaultListItemMain; - - protected function assembleCaption(BaseHtmlElement $caption): void - { - // TODO add state reason then replace function by DefaultListItemCaption trait - $caption->addHtml(new Text('Placeholder for Icinga State Reason')); - } + use DefaultListItemVisual; protected function assembleFooter(BaseHtmlElement $footer): void { @@ -73,10 +70,4 @@ protected function assembleTitle(BaseHtmlElement $title): void ) ); } - - protected function assembleVisual(BaseHtmlElement $visual): void - { - // TODO add icinga state then replace function by DefaultListItemVisual trait - $visual->addHtml(new StateBall('none', StateBall::SIZE_MEDIUM)); - } }