add grid like view to the available apps
This commit is contained in:
parent
8aa1dfbfff
commit
e0d2457e26
|
|
@ -5,8 +5,9 @@ export default class extends Controller {
|
|||
static values = {
|
||||
application: String,
|
||||
organization: String,
|
||||
user: Number,
|
||||
}
|
||||
static targets = ['hidden', 'submitBtn']
|
||||
static targets = ['hidden', 'submitBtn', 'appList']
|
||||
|
||||
connect() {
|
||||
// Map each editor to its toolbar and hidden field
|
||||
|
|
@ -40,6 +41,9 @@ export default class extends Controller {
|
|||
hiddenTarget.value = quill.root.innerHTML
|
||||
})
|
||||
}
|
||||
if(this.userValue){
|
||||
this.loadApplications();
|
||||
}
|
||||
}
|
||||
|
||||
handleAuthorizeSubmit(event) {
|
||||
|
|
@ -107,4 +111,59 @@ export default class extends Controller {
|
|||
alert('Erreur lors de l\'action');
|
||||
});
|
||||
}
|
||||
|
||||
async loadApplications() {
|
||||
if (!this.userValue) return;
|
||||
|
||||
try {
|
||||
// Note: Ensure the URL matches your route prefix (e.g. /application/user/123)
|
||||
// Adjust the base path below if your controller route is prefixed!
|
||||
const response = await fetch(`/application/user/${this.userValue}`);
|
||||
|
||||
if (!response.ok) throw new Error("Failed to load apps");
|
||||
|
||||
const apps = await response.json();
|
||||
this.renderApps(apps);
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.appListTarget.innerHTML = `<span class="text-danger small">Erreur</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
renderApps(apps) {
|
||||
if (apps.length === 0) {
|
||||
// Span 2 columns if empty so the message is centered
|
||||
this.appListTarget.innerHTML = `<span class="text-muted small" style="grid-column: span 2; text-align: center;">Aucune application</span>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const html = apps.map(app => {
|
||||
const url = `https://${app.subDomain}.solutions-easy.moi`;
|
||||
|
||||
// Check for logo string vs object
|
||||
const logoSrc = (typeof app.logoMiniUrl === 'string') ? app.logoMiniUrl : '';
|
||||
|
||||
// Render Icon (Image or Fallback)
|
||||
const iconHtml = logoSrc
|
||||
? `<img src="${logoSrc}" style="width:32px; height:32px; object-fit:contain; margin-bottom: 5px;">`
|
||||
: `<i class="bi bi-box-arrow-up-right text-primary" style="font-size: 24px; margin-bottom: 5px;"></i>`;
|
||||
|
||||
// Return a Card-like block
|
||||
return `
|
||||
<a href="${url}" target="_blank"
|
||||
class="d-flex flex-column align-items-center justify-content-center p-3 rounded text-decoration-none text-dark bg-light-hover"
|
||||
style="transition: background 0.2s; height: 100%;">
|
||||
|
||||
${iconHtml}
|
||||
|
||||
<span class="fw-bold text-center text-truncate w-100" style="font-size: 0.85rem;">
|
||||
${app.name}
|
||||
</span>
|
||||
</a>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
this.appListTarget.innerHTML = html;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,17 +4,20 @@ namespace App\Controller;
|
|||
|
||||
use App\Entity\Apps;
|
||||
use App\Entity\Organizations;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Service\ActionService;
|
||||
use App\Service\ApplicationService;
|
||||
use App\Service\LoggerService;
|
||||
use App\Service\UserOrganizationAppService;
|
||||
use App\Service\UserService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
|
||||
|
||||
use Symfony\Component\Asset\Packages;
|
||||
#[Route(path: '/application', name: 'application_')]
|
||||
|
||||
class ApplicationController extends AbstractController
|
||||
|
|
@ -23,7 +26,10 @@ class ApplicationController extends AbstractController
|
|||
private readonly UserService $userService,
|
||||
private readonly ActionService $actionService,
|
||||
private readonly LoggerService $loggerService,
|
||||
private readonly ApplicationService $applicationService)
|
||||
private readonly ApplicationService $applicationService,
|
||||
private readonly UserRepository $userRepository,
|
||||
private Packages $assetsManager,
|
||||
private readonly UserOrganizationAppService $userOrganizationAppService)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -172,4 +178,30 @@ class ApplicationController extends AbstractController
|
|||
|
||||
return new Response('', Response::HTTP_OK);
|
||||
}
|
||||
|
||||
#[Route(path:'/user/{id}', name: 'user', methods: ['GET'])]
|
||||
public function getApplicationUsers(int $id): JSONResponse
|
||||
{
|
||||
$user = $this->userRepository->find($id);
|
||||
$actingUser = $this->userService->getUserByIdentifier($this->getUser()->getUserIdentifier());
|
||||
if (!$user) {
|
||||
$this->loggerService->logEntityNotFound('User', ['message'=> 'User not found for application list'], $actingUser->getId());
|
||||
return new JsonResponse(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$applications = $this->entityManager->getRepository(Apps::class)->findAll();
|
||||
}else{
|
||||
$applications = $this->userOrganizationAppService->getUserApplications($user);
|
||||
|
||||
}
|
||||
$data = array_map(function($app) {
|
||||
return [
|
||||
'name' => $app->getName(),
|
||||
'subDomain' => $app->getSubDomain(),
|
||||
'logoMiniUrl' => $this->assetsManager->getUrl($app->getLogoMiniUrl()),
|
||||
];
|
||||
}, $applications);
|
||||
|
||||
return new JsonResponse($data, Response::HTTP_OK);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,4 +248,26 @@ class UserOrganizationAppService
|
|||
$uoaAdmin->setIsActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get users applications links for a given user
|
||||
*
|
||||
* @param User $user
|
||||
* @return Apps[]
|
||||
*/
|
||||
public function getUserApplications(User $user): array
|
||||
{
|
||||
$uos = $this->entityManager->getRepository(UsersOrganizations::class)->findBy(['users' => $user]);
|
||||
$apps = [];
|
||||
foreach ($uos as $uo) {
|
||||
$uoas = $this->entityManager->getRepository(UserOrganizatonApp::class)->findBy(['userOrganization' => $uo, 'isActive' => true]);
|
||||
foreach ($uoas as $uoa) {
|
||||
$app = $uoa->getApplication();
|
||||
if (!in_array($app, $apps, true)) {
|
||||
$apps[] = $app;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $apps;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,35 @@
|
|||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item dropdown nav-notif"
|
||||
data-controller="application"
|
||||
data-application-user-value="{{ app.user.id }}"
|
||||
>
|
||||
<a id="applicationDropdown"
|
||||
class="nav-link count-indicator dropdown-toggle m-auto"
|
||||
href="#"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
data-action="click->application#loadApps">
|
||||
<i class="mx-0">{{ ux_icon('bi:grid-3x3-gap', {height: '20px', width: '20px'}) }}</i>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right navbar-dropdown preview-list"
|
||||
aria-labelledby="applicationDropdown"
|
||||
style="max-height: 400px; overflow-y: auto; min-width: 320px;">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center px-3 py-2 border-bottom">
|
||||
<p class="mb-0 font-weight-normal dropdown-header text-bold">Applications</p>
|
||||
</div>
|
||||
|
||||
<div class="px-3 py-2">
|
||||
<div data-application-target="appList"
|
||||
style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||
<span class="text-muted small">Chargement...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item dropdown nav-profile">
|
||||
<a id="profileDropdown" class="nav-link count-indicator dropdown-toggle m-auto" href="#" data-bs-toggle="dropdown">
|
||||
<div id="profil" class="rounded-circle bg-secondary d-flex">
|
||||
|
|
@ -85,25 +114,14 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right navbar-dropdown px-2" aria-labelledby="profileDropdown" data-bs-popper="static">
|
||||
<div class="dropdown-menu dropdown-menu-right navbar-dropdown px-2"
|
||||
aria-labelledby="profileDropdown"
|
||||
data-bs-popper="static">
|
||||
|
||||
<a class="dropdown-item border-bottom" style="padding-left: 8px;" href="{{ path('user_show', {'id': app.user.id}) }}">
|
||||
<i class="me-2">{{ ux_icon('bi:gear', {height: '20px', width: '20px'}) }}</i>
|
||||
Profil
|
||||
</a>
|
||||
<div style="padding:8px 0;" class="row border-bottom">
|
||||
<div class="col-2 m-auto">
|
||||
<i >{{ ux_icon('bi:menu-up', {height: '20px', width: '20px'}) }}</i>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<a href="http://client.solutions-easy.moi"> Client </a>
|
||||
{# <select class="form-control">
|
||||
<option>Exploit</options>
|
||||
<option>Monithor</options>
|
||||
<option>Check</options>
|
||||
<option>Access</options>
|
||||
</select> #}
|
||||
</div>
|
||||
</div>
|
||||
<a class="dropdown-item" style="padding-left: 8px;" href="{{ path('sso_logout') }}">
|
||||
<i class="me-2">{{ ux_icon('material-symbols:logout', {height: '20px', width: '20px'}) }}</i>
|
||||
Deconnexion
|
||||
|
|
|
|||
Loading…
Reference in New Issue