Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Favorites feature #125

Open
wants to merge 13 commits into
base: viewmodes
Choose a base branch
from
5 changes: 5 additions & 0 deletions application/controllers/ConfigmapsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,9 @@ protected function getIgnoredViewModes(): array
{
return [ViewModeSwitcher::VIEW_MODE_COMMON, ViewModeSwitcher::VIEW_MODE_DETAILED];
}

protected function getFavorable(): bool
{
return false;
}
}
13 changes: 13 additions & 0 deletions application/controllers/CronjobController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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));
}
}
5 changes: 5 additions & 0 deletions application/controllers/CronjobsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ protected function getPermission(): string
{
return Auth::SHOW_CRON_JOBS;
}

protected function getFavorable(): bool
{
return true;
}
}
15 changes: 14 additions & 1 deletion application/controllers/DaemonsetController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,16 +32,27 @@ 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'));
}

$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));
}
}
5 changes: 5 additions & 0 deletions application/controllers/DaemonsetsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ protected function getPermission(): string
{
return Auth::SHOW_DAEMON_SETS;
}

protected function getFavorable(): bool
{
return true;
}
}
15 changes: 14 additions & 1 deletion application/controllers/DeploymentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,16 +32,27 @@ 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'));
}

$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));
}
}
5 changes: 5 additions & 0 deletions application/controllers/DeploymentsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ protected function getPermission(): string
{
return Auth::SHOW_DEPLOYMENTS;
}

protected function getFavorable(): bool
{
return true;
}
}
5 changes: 5 additions & 0 deletions application/controllers/EventsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,9 @@ protected function getIgnoredViewModes(): array
{
return [ViewModeSwitcher::VIEW_MODE_DETAILED];
}

protected function getFavorable(): bool
{
return false;
}
}
134 changes: 134 additions & 0 deletions application/controllers/FavoriteController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php

/* Icinga for Kubernetes Web | (c) 2025 Icinga GmbH | AGPLv3 */

namespace Icinga\Module\Kubernetes\Controllers;

use Icinga\Application\Logger;
use Icinga\Module\Kubernetes\Common\Auth;
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
{
/**
* Favors a resource by adding it into the database. Throws an exception if the database operation fails.
*
* @return void
*/
public function favorAction(): void
{
(new FavorForm())
->on(FavorForm::ON_SUCCESS, function () {
$db = Database::connection();
$uuid = $this->params->get('uuid');
$kind = $this->params->get('kind');
$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) {
Logger::error($e);
Logger::error($e->getTraceAsString());

throw $e;
}
})
->handleRequest($this->getServerRequest());

$this->closeModalAndRefreshRemainingViews('__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 {
$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',
[
'resource_uuid = ?' => $uuid,
'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());

throw $e;
}
})
->handleRequest($this->getServerRequest());

$this->closeModalAndRefreshRemainingViews('__REFRESH__');
}
}
59 changes: 59 additions & 0 deletions application/controllers/FavoritesController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/* Icinga for Kubernetes Web | (c) 2025 Icinga GmbH | AGPLv3 */

namespace Icinga\Module\Kubernetes\Controllers;

use Icinga\Module\Kubernetes\Common\Auth;
use Icinga\Module\Kubernetes\Common\Database;
use Icinga\Module\Kubernetes\Model\Favorite;
use Icinga\Module\Kubernetes\Web\Controller;
use Icinga\Module\Kubernetes\Web\Factory;
use Icinga\Module\Kubernetes\Web\FavoriteDashboard;
use Icinga\Web\Widget\Dashboard;
use Icinga\Web\Widget\Dashboard\Dashlet;
use Icinga\Web\Widget\Dashboard\Pane;
use ipl\Stdlib\Filter;

class FavoritesController extends Controller
{
const array FAVORABLE_KINDS = [
'cronjob',
'daemonset',
'deployment',
'ingress',
'job',
'namespace',
'node',
'persistentvolumeclaim',
'persistentvolume',
'pod',
'replicaset',
'service',
'statefulset'
];

public function indexAction(): void
{
$this->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));
}
}
13 changes: 13 additions & 0 deletions application/controllers/IngressController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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));
}
}
Loading