mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-10 08:44:58 +00:00
Compare commits
15 Commits
2.21.0
...
68-feature
Author | SHA1 | Date | |
---|---|---|---|
2fc6e18d0f | |||
|
80ea4bbdd2 | ||
|
801c693ef9 | ||
|
c1c9562e67 | ||
|
b9e580af9a | ||
|
790c7f6724 | ||
|
1be91bb392 | ||
|
93f39ebe5b | ||
|
176c3c0e27 | ||
|
59cd8466be | ||
|
ef9e872394 | ||
|
51a46ab5d7 | ||
|
191b416c6c | ||
6028efdc7c | |||
|
60c9e037a6 |
@@ -31,7 +31,9 @@
|
|||||||
"typescript": "^4.7.2",
|
"typescript": "^4.7.2",
|
||||||
"vue-loader": "^17.0.0",
|
"vue-loader": "^17.0.0",
|
||||||
"webpack": "^5.75.0",
|
"webpack": "^5.75.0",
|
||||||
"webpack-cli": "^5.0.1"
|
"webpack-cli": "^5.0.1",
|
||||||
|
"chart.js": "^4.2.1",
|
||||||
|
"vue-chartjs": "^5.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fullcalendar/core": "^6.1.4",
|
"@fullcalendar/core": "^6.1.4",
|
||||||
|
@@ -32,6 +32,7 @@ use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
|
|||||||
use Chill\MainBundle\Service\EntityInfo\ViewEntityInfoProviderInterface;
|
use Chill\MainBundle\Service\EntityInfo\ViewEntityInfoProviderInterface;
|
||||||
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
|
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
|
||||||
use Chill\MainBundle\Templating\UI\NotificationCounterInterface;
|
use Chill\MainBundle\Templating\UI\NotificationCounterInterface;
|
||||||
|
use Chill\MainBundle\Widget\WidgetHandlerInterface;
|
||||||
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
|
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
@@ -62,9 +63,10 @@ class ChillMainBundle extends Bundle
|
|||||||
->addTag('chill_main.workflow_handler');
|
->addTag('chill_main.workflow_handler');
|
||||||
$container->registerForAutoconfiguration(CronJobInterface::class)
|
$container->registerForAutoconfiguration(CronJobInterface::class)
|
||||||
->addTag('chill_main.cron_job');
|
->addTag('chill_main.cron_job');
|
||||||
|
$container->registerForAutoconfiguration(WidgetHandlerInterface::class)
|
||||||
|
->addTag('chill_main.widget_handler');
|
||||||
$container->registerForAutoconfiguration(ViewEntityInfoProviderInterface::class)
|
$container->registerForAutoconfiguration(ViewEntityInfoProviderInterface::class)
|
||||||
->addTag('chill_main.entity_info_provider');
|
->addTag('chill_main.entity_info_provider');
|
||||||
|
|
||||||
$container->addCompilerPass(new SearchableServicesCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
|
$container->addCompilerPass(new SearchableServicesCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
|
||||||
$container->addCompilerPass(new ConfigConsistencyCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
|
$container->addCompilerPass(new ConfigConsistencyCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
|
||||||
$container->addCompilerPass(new TimelineCompilerClass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
|
$container->addCompilerPass(new TimelineCompilerClass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
|
||||||
|
@@ -0,0 +1,133 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||||
|
use Chill\MainBundle\Repository\UserRepository;
|
||||||
|
use Chill\MainBundle\Serializer\Model\Collection;
|
||||||
|
use Chill\MainBundle\Widget\WidgetHandlerManager;
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
use PHPUnit\Util\Json;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
|
use Symfony\Component\Serializer\Serializer;
|
||||||
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{_locale}/dashboard")
|
||||||
|
*/
|
||||||
|
class DashboardHomepageController extends AbstractController{
|
||||||
|
|
||||||
|
private WidgetHandlerManager $widgetHandlerManager;
|
||||||
|
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
|
private UserRepository $userRepository;
|
||||||
|
|
||||||
|
private EntityManagerInterface $em;
|
||||||
|
|
||||||
|
private LoggerInterface $logger;
|
||||||
|
|
||||||
|
private SerializerInterface $serializer;
|
||||||
|
|
||||||
|
private PaginatorFactory $paginatorFactory;
|
||||||
|
public function __construct(
|
||||||
|
//AccompanyingPeriodRepository $accompanyingPeriodRepository,
|
||||||
|
WidgetHandlerManager $widgetHandlerManager,
|
||||||
|
Security $security,
|
||||||
|
UserRepository $userRepository,
|
||||||
|
EntityManagerInterface $em,
|
||||||
|
LoggerInterface $logger,
|
||||||
|
SerializerInterface $serializer,
|
||||||
|
PaginatorFactory $paginatorFactory,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//$this->accompanyingPeriodRepository = $accompanyingPeriodRepository;
|
||||||
|
$this->widgetHandlerManager = $widgetHandlerManager;
|
||||||
|
$this->security = $security;
|
||||||
|
$this->userRepository = $userRepository;
|
||||||
|
$this->em = $em;
|
||||||
|
$this->logger = $logger;
|
||||||
|
$this->serializer = $serializer;
|
||||||
|
$this->paginatorFactory = $paginatorFactory;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/raw_data", name="chill_main_widget_raw_data")
|
||||||
|
* @return JsonResponse
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function index(): JsonResponse
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
||||||
|
|
||||||
|
if (!$this->security->getUser() instanceof User) {
|
||||||
|
throw new AccessDeniedHttpException('You must be authenticated and a user to see the dashboard');
|
||||||
|
}
|
||||||
|
// --------------Bar---------------------
|
||||||
|
$config = [
|
||||||
|
'alias' => 'bar',
|
||||||
|
];
|
||||||
|
|
||||||
|
$context = [
|
||||||
|
//'user' => $this->security->getUser(),
|
||||||
|
//Hardcoder pour resultat
|
||||||
|
'user' => 19,
|
||||||
|
'what' => 'accompanying_period_by_month',
|
||||||
|
];
|
||||||
|
// --------------Number------------------
|
||||||
|
/*$config = [
|
||||||
|
'alias' => 'number',
|
||||||
|
];
|
||||||
|
|
||||||
|
$context = [
|
||||||
|
'user' => $this->security->getUser(),
|
||||||
|
//'what' => 'notification_unread',
|
||||||
|
'what' => 'notification_sender',
|
||||||
|
];*/
|
||||||
|
$data = $this->widgetHandlerManager->getDataForWidget($config, $context);
|
||||||
|
|
||||||
|
return new JsonResponse($data,Response::HTTP_OK,[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/widget/{context}", name="chill_main_widget_get_data")
|
||||||
|
*/
|
||||||
|
public function getDataForWidget(Request $request, string $context): JsonResponse
|
||||||
|
{
|
||||||
|
//Retrieve data from request in vue component
|
||||||
|
$requestData = json_decode($request->getContent(), true);
|
||||||
|
dump($requestData);
|
||||||
|
// Process the widget data using the WidgetHandlerManager
|
||||||
|
//$handler = $this->widgetHandlerManager->getHandler($requestData);
|
||||||
|
//dump($handler);
|
||||||
|
|
||||||
|
// Return the widget data in JSON response
|
||||||
|
//return new JsonResponse($this->getData($requestData));
|
||||||
|
|
||||||
|
return new JsonResponse($requestData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||||
|
|
||||||
|
class SavedExportApiController extends ApiController
|
||||||
|
{
|
||||||
|
}
|
@@ -20,6 +20,7 @@ use Chill\MainBundle\Controller\LanguageController;
|
|||||||
use Chill\MainBundle\Controller\LocationController;
|
use Chill\MainBundle\Controller\LocationController;
|
||||||
use Chill\MainBundle\Controller\LocationTypeController;
|
use Chill\MainBundle\Controller\LocationTypeController;
|
||||||
use Chill\MainBundle\Controller\RegroupmentController;
|
use Chill\MainBundle\Controller\RegroupmentController;
|
||||||
|
use Chill\MainBundle\Controller\SavedExportApiController;
|
||||||
use Chill\MainBundle\Controller\UserController;
|
use Chill\MainBundle\Controller\UserController;
|
||||||
use Chill\MainBundle\Controller\UserJobApiController;
|
use Chill\MainBundle\Controller\UserJobApiController;
|
||||||
use Chill\MainBundle\Controller\UserJobController;
|
use Chill\MainBundle\Controller\UserJobController;
|
||||||
@@ -54,6 +55,7 @@ use Chill\MainBundle\Entity\Language;
|
|||||||
use Chill\MainBundle\Entity\Location;
|
use Chill\MainBundle\Entity\Location;
|
||||||
use Chill\MainBundle\Entity\LocationType;
|
use Chill\MainBundle\Entity\LocationType;
|
||||||
use Chill\MainBundle\Entity\Regroupment;
|
use Chill\MainBundle\Entity\Regroupment;
|
||||||
|
use Chill\MainBundle\Entity\SavedExport;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Entity\UserJob;
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
use Chill\MainBundle\Form\CenterType;
|
use Chill\MainBundle\Form\CenterType;
|
||||||
@@ -228,7 +230,7 @@ class ChillMainExtension extends Extension implements
|
|||||||
$twigConfig = [
|
$twigConfig = [
|
||||||
'globals' => [
|
'globals' => [
|
||||||
'installation' => [
|
'installation' => [
|
||||||
'name' => $config['installation_name'], ],
|
'name' => $config['installation_name'],],
|
||||||
'available_languages' => $config['available_languages'],
|
'available_languages' => $config['available_languages'],
|
||||||
'add_address' => $config['add_address'],
|
'add_address' => $config['add_address'],
|
||||||
],
|
],
|
||||||
@@ -327,9 +329,9 @@ class ChillMainExtension extends Extension implements
|
|||||||
* Load parameter for configuration and set parameters for api.
|
* Load parameter for configuration and set parameters for api.
|
||||||
*/
|
*/
|
||||||
protected function configureCruds(
|
protected function configureCruds(
|
||||||
ContainerBuilder $container,
|
ContainerBuilder $container,
|
||||||
array $crudConfig,
|
array $crudConfig,
|
||||||
array $apiConfig,
|
array $apiConfig,
|
||||||
Loader\YamlFileLoader $loader
|
Loader\YamlFileLoader $loader
|
||||||
): void {
|
): void {
|
||||||
if (0 === \count($crudConfig)) {
|
if (0 === \count($crudConfig)) {
|
||||||
@@ -767,7 +769,28 @@ class ChillMainExtension extends Extension implements
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
[
|
||||||
|
'class' => SavedExport::class,
|
||||||
|
'controller' => SavedExportApiController::class,
|
||||||
|
'name' => 'saved_export',
|
||||||
|
'base_path' => '/api/1.0/main/saved-export',
|
||||||
|
'base_role' => 'ROLE_USER',
|
||||||
|
'actions' => [
|
||||||
|
'_index' => [
|
||||||
|
'methods' => [
|
||||||
|
Request::METHOD_GET => true,
|
||||||
|
Request::METHOD_HEAD => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'_entity' => [
|
||||||
|
'methods' => [
|
||||||
|
Request::METHOD_GET => true,
|
||||||
|
Request::METHOD_HEAD => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,7 @@ use Doctrine\ORM\Mapping as ORM;
|
|||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use Ramsey\Uuid\UuidInterface;
|
use Ramsey\Uuid\UuidInterface;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity
|
* @ORM\Entity
|
||||||
@@ -35,6 +36,7 @@ class SavedExport implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||||
*
|
*
|
||||||
* @Assert\NotBlank
|
* @Assert\NotBlank
|
||||||
|
* @Groups({"read"})
|
||||||
*/
|
*/
|
||||||
private string $description = '';
|
private string $description = '';
|
||||||
|
|
||||||
@@ -49,11 +51,13 @@ class SavedExport implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
* @ORM\Column(name="id", type="uuid", unique="true")
|
* @ORM\Column(name="id", type="uuid", unique="true")
|
||||||
*
|
*
|
||||||
* @ORM\GeneratedValue(strategy="NONE")
|
* @ORM\GeneratedValue(strategy="NONE")
|
||||||
|
* @Groups({"read"})
|
||||||
*/
|
*/
|
||||||
private UuidInterface $id;
|
private UuidInterface $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="json", nullable=false, options={"default": "[]"})
|
* @ORM\Column(type="json", nullable=false, options={"default": "[]"})
|
||||||
|
* @Groups({"read"})
|
||||||
*/
|
*/
|
||||||
private array $options = [];
|
private array $options = [];
|
||||||
|
|
||||||
@@ -61,11 +65,13 @@ class SavedExport implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||||
*
|
*
|
||||||
* @Assert\NotBlank
|
* @Assert\NotBlank
|
||||||
|
* @Groups({"read"})
|
||||||
*/
|
*/
|
||||||
private string $title = '';
|
private string $title = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity=User::class)
|
* @ORM\ManyToOne(targetEntity=User::class)
|
||||||
|
* @Groups({"read"})
|
||||||
*/
|
*/
|
||||||
private User $user;
|
private User $user;
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<span v-if="noResults" class="chill-no-data-statement">{{ $t('no_dashboard') }}</span>
|
<span v-if="noResults" class="chill-no-data-statement">{{ $t('no_dashboard') }}</span>
|
||||||
<div v-else id="dashboards" class="row g-3" data-masonry='{"percentPosition": true }'>
|
<div v-else id="dashboards" class="row g-3" data-masonry='{"percentPosition": true }'>
|
||||||
|
|
||||||
<div class="mbloc col col-sm-6 col-lg-4">
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
<div class="custom1">
|
<div class="custom1">
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
@@ -38,39 +38,33 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
<!--
|
<div class="custom2">
|
||||||
<div class="mbloc col col-sm-6 col-lg-4">
|
<MyWidget/>
|
||||||
<div class="custom2">
|
</div>
|
||||||
Mon dashboard personnalisé
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mbloc col col-sm-6 col-lg-4">
|
|
||||||
<div class="custom3">
|
|
||||||
Mon dashboard personnalisé
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mbloc col col-sm-6 col-lg-4">
|
|
||||||
<div class="custom4">
|
|
||||||
Mon dashboard personnalisé
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
import MyWidget from './MyWidget.vue'
|
||||||
import { mapGetters } from "vuex";
|
import { mapGetters } from "vuex";
|
||||||
import Masonry from 'masonry-layout/masonry';
|
import Masonry from 'masonry-layout/masonry';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MyCustoms",
|
name: "MyCustoms",
|
||||||
|
components:{
|
||||||
|
MyWidget
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
counterClass: {
|
counterClass: {
|
||||||
counter: true //hack to pass class 'counter' in i18n-t
|
counter: true //hack to pass class 'counter' in i18n-t
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -82,8 +76,8 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
const elem = document.querySelector('#dashboards');
|
const elem = document.querySelector('#dashboards');
|
||||||
const masonry = new Masonry(elem, {});
|
const masonry = new Masonry(elem, {});
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -98,4 +92,4 @@ span.counter {
|
|||||||
background-color: unset;
|
background-color: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<Bar v-if="loaded_bar" :data="chartData" :options="chartOptions"/>
|
||||||
|
<span v-if="loaded_number">{{ number }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
BarElement,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale
|
||||||
|
} from 'chart.js'
|
||||||
|
import {Bar} from 'vue-chartjs'
|
||||||
|
import {defineComponent} from 'vue'
|
||||||
|
import {makeFetch} from "../../lib/api/apiMethods";
|
||||||
|
|
||||||
|
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'MyWidget',
|
||||||
|
components: {
|
||||||
|
Bar,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loaded_bar: false,
|
||||||
|
loaded_number: false,
|
||||||
|
chartData: null,
|
||||||
|
chartOptions: null,
|
||||||
|
number: "",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
this.loaded_bar = false;
|
||||||
|
this.loaded_number = false;
|
||||||
|
const url = '/fr/dashboard/raw_data';
|
||||||
|
try {
|
||||||
|
const response: { data: any, options: any, type: any } = await makeFetch("GET", url);
|
||||||
|
this.chartData = response.data;
|
||||||
|
this.chartOptions = response.options;
|
||||||
|
if (response.type == 'bar') {
|
||||||
|
this.loaded_bar = true;
|
||||||
|
} else {
|
||||||
|
this.loaded_number = true
|
||||||
|
this.number = response.data.datasets[0].data[0] + " "+ response.data.labels[0];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/*methods: {
|
||||||
|
async makeNumberWidget() {
|
||||||
|
let body = {
|
||||||
|
config: {
|
||||||
|
alias: 'number'
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
what: 'notification_unread',
|
||||||
|
user: 19 //Ne rien mettre ou via les refs
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const response: {
|
||||||
|
data: any,
|
||||||
|
options: any,
|
||||||
|
type: any
|
||||||
|
} = await makeFetch('POST', '/{_locale}//{_locale}/dashboard/widget/number', body)
|
||||||
|
this.chartData = response.data;
|
||||||
|
this.chartOptions = response.options;
|
||||||
|
this.loaded_number = true;
|
||||||
|
this.number = response.data.datasets[0].data[0] + response.data.labels[0];
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
}*/
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
span {
|
||||||
|
font-size: x-large;
|
||||||
|
color: #0a53be;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -0,0 +1,28 @@
|
|||||||
|
export const data = {
|
||||||
|
labels: [
|
||||||
|
'January',
|
||||||
|
'February',
|
||||||
|
'March',
|
||||||
|
'April',
|
||||||
|
'May',
|
||||||
|
'June',
|
||||||
|
'July',
|
||||||
|
'August',
|
||||||
|
'September',
|
||||||
|
'October',
|
||||||
|
'November',
|
||||||
|
'December'
|
||||||
|
],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Data One',
|
||||||
|
backgroundColor: '#f87979',
|
||||||
|
data: [40, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const options = {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false
|
||||||
|
}
|
18
src/Bundle/ChillMainBundle/Widget/WidgetHandlerInterface.php
Normal file
18
src/Bundle/ChillMainBundle/Widget/WidgetHandlerInterface.php
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Widget;
|
||||||
|
|
||||||
|
interface WidgetHandlerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Return true if the handler supports the handling for this widget.
|
||||||
|
*/
|
||||||
|
public function supports(array $config,array $context = []): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array which will be passed as data for the chart in the Vue element.
|
||||||
|
*/
|
||||||
|
public function getDataForWidget(array $config,array $context = []): array;
|
||||||
|
}
|
36
src/Bundle/ChillMainBundle/Widget/WidgetHandlerManager.php
Normal file
36
src/Bundle/ChillMainBundle/Widget/WidgetHandlerManager.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Widget;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Widget\WidgetHandlerInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
|
||||||
|
|
||||||
|
final class WidgetHandlerManager
|
||||||
|
{
|
||||||
|
private iterable $handlers;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
iterable $handlers
|
||||||
|
) {
|
||||||
|
$this->handlers = $handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHandler(array $config,): WidgetHandlerInterface
|
||||||
|
{
|
||||||
|
foreach ($this->handlers as $widget) {
|
||||||
|
if ($widget->supports($config)) {
|
||||||
|
return $widget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle unsupported context
|
||||||
|
throw new \InvalidArgumentException('Unsupported widget.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataForWidget(array $config, array $context=[]): array
|
||||||
|
{
|
||||||
|
return $this->getHandler($config)->getDataForWidget($config,$context);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Widget\Widgets\DataFetcher;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\Query\ResultSetMapping;
|
||||||
|
|
||||||
|
class WidgetBarDataFetcher
|
||||||
|
{
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $entityManager)
|
||||||
|
{
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function fetchDataForWidget(int $userId): array
|
||||||
|
{
|
||||||
|
$sql = "
|
||||||
|
SELECT DATE_TRUNC('month', ap.openingdate) AS month,
|
||||||
|
COUNT(ap.id) AS count
|
||||||
|
FROM chill_person_accompanying_period ap
|
||||||
|
WHERE ap.user_id = :userId
|
||||||
|
GROUP BY DATE_TRUNC('month', ap.openingdate)
|
||||||
|
ORDER BY DATE_TRUNC('month', ap.openingdate) ASC
|
||||||
|
";
|
||||||
|
|
||||||
|
$rsm = new ResultSetMapping();
|
||||||
|
$rsm->addScalarResult('month', 'month');
|
||||||
|
$rsm->addScalarResult('count', 'count');
|
||||||
|
|
||||||
|
$query = $this->entityManager->createNativeQuery($sql, $rsm);
|
||||||
|
$query->setParameter('userId', $userId);
|
||||||
|
|
||||||
|
$results = $query->getResult();
|
||||||
|
|
||||||
|
|
||||||
|
$counts = [];
|
||||||
|
$months =[] ;
|
||||||
|
foreach ($results as $result) {
|
||||||
|
$date = new \DateTime($result['month']);
|
||||||
|
$formattedMonth = $date->format('Y-m');
|
||||||
|
|
||||||
|
$months[] = $formattedMonth;
|
||||||
|
$counts[] = $result['count'];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'months'=>$months,
|
||||||
|
'counts'=>$counts,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
105
src/Bundle/ChillMainBundle/Widget/Widgets/WidgetBar.php
Normal file
105
src/Bundle/ChillMainBundle/Widget/Widgets/WidgetBar.php
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Widget\Widgets;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Repository\NotificationRepository;
|
||||||
|
use Chill\MainBundle\Widget\WidgetHandlerInterface;
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
use Chill\MainBundle\Widget\Widgets\DataFetcher\WidgetBarDataFetcher;
|
||||||
|
|
||||||
|
class WidgetBar implements WidgetHandlerInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
|
//private AccompanyingPeriodRepository $acpRepository;
|
||||||
|
|
||||||
|
private WidgetBarDataFetcher $dataFetcher;
|
||||||
|
|
||||||
|
//private NotificationRepository $notificationRepository;
|
||||||
|
|
||||||
|
//private EntityManagerInterface $em;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
// AccompanyingPeriodRepository $accompanyingPeriodRepository,
|
||||||
|
Security $security,
|
||||||
|
// NotificationRepository $notificationRepository,
|
||||||
|
// EntityManagerInterface $em,
|
||||||
|
WidgetBarDataFetcher $dataFetcher
|
||||||
|
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// $this->acpRepository = $accompanyingPeriodRepository;
|
||||||
|
$this->security = $security;
|
||||||
|
// $this->notificationRepository = $notificationRepository;
|
||||||
|
// $this->em = $em;
|
||||||
|
$this->dataFetcher = $dataFetcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(array $config, array $context = []): bool
|
||||||
|
{
|
||||||
|
// Check if the context is "bar"
|
||||||
|
return $config['alias'] === 'bar';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function getDataForWidget(array $config, array $context = []): array
|
||||||
|
{
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
//$userId = $user->getId();
|
||||||
|
//Hardcoder pour résultat
|
||||||
|
$userId = 19;
|
||||||
|
$dataForWidget = [];
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new AccessDeniedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($context !== []) {
|
||||||
|
switch ($context['what']) {
|
||||||
|
case 'accompanying_period_by_month':
|
||||||
|
|
||||||
|
$data = $this->dataFetcher->fetchDataForWidget($userId);
|
||||||
|
$dataForWidget = [
|
||||||
|
'labels' => $data['months'],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => 'Number of accompanying periods opened',
|
||||||
|
'backgroundColor' => ['#41B883'],
|
||||||
|
'data' => $data['counts']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException('Invalid Context.');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'data' => $dataForWidget,
|
||||||
|
'options' => [
|
||||||
|
|
||||||
|
'responsive' => 'true',
|
||||||
|
'maintainAspectRatio' => 'false',
|
||||||
|
'position' => 'relative'
|
||||||
|
|
||||||
|
],
|
||||||
|
'type' => 'bar',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
104
src/Bundle/ChillMainBundle/Widget/Widgets/WidgetNumber.php
Normal file
104
src/Bundle/ChillMainBundle/Widget/Widgets/WidgetNumber.php
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Widget\Widgets;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Repository\NotificationRepository;
|
||||||
|
use Chill\MainBundle\Widget\WidgetHandlerInterface;
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
|
use Chill\PersonBundle\Repository\Person;
|
||||||
|
use DateInterval;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
class WidgetNumber implements WidgetHandlerInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
|
//private AccompanyingPeriodRepository $acpRepository;
|
||||||
|
|
||||||
|
private NotificationRepository $notificationRepository;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
// AccompanyingPeriodRepository $accompanyingPeriodRepository,
|
||||||
|
Security $security,
|
||||||
|
NotificationRepository $notificationRepository,
|
||||||
|
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// $this->acpRepository = $accompanyingPeriodRepository;
|
||||||
|
$this->security = $security;
|
||||||
|
$this->notificationRepository = $notificationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supports(array $config, array $context = []): bool
|
||||||
|
{
|
||||||
|
return $config['alias'] === 'number';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getDataForWidget(array $config, array $context = []): array
|
||||||
|
{
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
$dataForWidget = [];
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new AccessDeniedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($context !== []) {
|
||||||
|
switch ($context['what']) {
|
||||||
|
|
||||||
|
/*case 'accompanying_period_history' :
|
||||||
|
//Send back a data that need to be serialize in order to see
|
||||||
|
$since = (new DateTimeImmutable('now'))->sub(new DateInterval('P1Y'));
|
||||||
|
$data = $this->acpRepository->countByRecentUserHistory($user, $since);
|
||||||
|
$what = $this->acpRepository->findConfirmedByUser($user);
|
||||||
|
break;*/
|
||||||
|
case 'notification_sender':
|
||||||
|
//Count the number of notification the sender send
|
||||||
|
$countSend = $this->notificationRepository->countAllForSender($user);
|
||||||
|
$dataForWidget = [
|
||||||
|
'labels' => ['notification(s) envoyée(s)'],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'data' => [$countSend]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'notification_unread':
|
||||||
|
//Count the number of unread notification by the current User
|
||||||
|
$countUnread = $this->notificationRepository->countUnreadByUser($user);
|
||||||
|
$dataForWidget = [
|
||||||
|
'labels' => ['notification(s) non lue(s)'],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'data' => [$countUnread]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
default : throw new \InvalidArgumentException('Invalid Context.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'data' => $dataForWidget,
|
||||||
|
'type' => 'number',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -10,6 +10,22 @@ servers:
|
|||||||
|
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
|
SavedExport:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
user_id:
|
||||||
|
type: integer
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
exportalias:
|
||||||
|
type: string
|
||||||
|
options:
|
||||||
|
type: string #TODO -> je pense que c'est object
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
|
||||||
User:
|
User:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -791,7 +807,7 @@ paths:
|
|||||||
/1.0/main/civility.json:
|
/1.0/main/civility.json:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- civility
|
- civility
|
||||||
summary: Return all civility types
|
summary: Return all civility types
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
@@ -843,3 +859,27 @@ paths:
|
|||||||
403:
|
403:
|
||||||
description: "Unauthorized"
|
description: "Unauthorized"
|
||||||
|
|
||||||
|
/1.0/main/saved-export/{id}.json:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- export
|
||||||
|
summary: Return a specific saved export who is saved by an existing user.
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The saved export id
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "ok"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/SavedExport'
|
||||||
|
403:
|
||||||
|
description: "Unauthorized"
|
||||||
|
@@ -115,6 +115,24 @@ services:
|
|||||||
autowire: true
|
autowire: true
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
|
|
||||||
|
Chill\MainBundle\Widget\:
|
||||||
|
resource: '../Widget/'
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
Chill\MainBundle\Widget\WidgetHandlerManager:
|
||||||
|
arguments:
|
||||||
|
$handlers: !tagged_iterator chill_main.widget_handler
|
||||||
|
|
||||||
|
Chill\MainBundle\Widget\Widgets\WidgetNumber:
|
||||||
|
autoconfigure: true
|
||||||
|
autowire: true
|
||||||
|
|
||||||
|
Chill\MainBundle\Widget\Widgets\WidgetBar:
|
||||||
|
autoconfigure: true
|
||||||
|
autowire: true
|
||||||
|
|
||||||
|
|
||||||
Chill\MainBundle\Cron\CronManager:
|
Chill\MainBundle\Cron\CronManager:
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
autowire: true
|
autowire: true
|
||||||
|
@@ -112,4 +112,17 @@ final class AccompanyingPeriodRepository implements ObjectRepository
|
|||||||
|
|
||||||
return $qb;
|
return $qb;
|
||||||
}
|
}
|
||||||
|
public function countByUserGroupedByMonth(User $user): array
|
||||||
|
{
|
||||||
|
$qb = $this->createQueryBuilder('a');
|
||||||
|
|
||||||
|
$qb->select()
|
||||||
|
->addSelect('COUNT(a.id) AS count')
|
||||||
|
->andWhere('a.user = :user')
|
||||||
|
->setParameter('user', $user)
|
||||||
|
->groupBy('month')
|
||||||
|
->orderBy('month', 'ASC');
|
||||||
|
|
||||||
|
return $qb->getQuery()->getResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user