Merge branch 'master' into testing

This commit is contained in:
2022-09-06 15:33:27 +02:00
351 changed files with 13755 additions and 10201 deletions

View File

@@ -22,6 +22,7 @@ use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Repository\LocationRepository;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Privacy\PrivacyEvent;
@@ -57,6 +58,8 @@ final class ActivityController extends AbstractController
private ActivityTypeRepository $activityTypeRepository;
private CenterResolverManagerInterface $centerResolver;
private EntityManagerInterface $entityManager;
private EventDispatcherInterface $eventDispatcher;
@@ -86,7 +89,8 @@ final class ActivityController extends AbstractController
EventDispatcherInterface $eventDispatcher,
LoggerInterface $logger,
SerializerInterface $serializer,
UserRepositoryInterface $userRepository
UserRepositoryInterface $userRepository,
CenterResolverManagerInterface $centerResolver
) {
$this->activityACLAwareRepository = $activityACLAwareRepository;
$this->activityTypeRepository = $activityTypeRepository;
@@ -101,6 +105,7 @@ final class ActivityController extends AbstractController
$this->logger = $logger;
$this->serializer = $serializer;
$this->userRepository = $userRepository;
$this->centerResolver = $centerResolver;
}
/**
@@ -203,7 +208,7 @@ final class ActivityController extends AbstractController
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
$form = $this->createForm(ActivityType::class, $entity, [
'center' => $entity->getCenters()[0] ?? null,
'center' => $this->centerResolver->resolveCenters($entity)[0] ?? null,
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
'activityType' => $entity->getActivityType(),
'accompanyingPeriod' => $accompanyingPeriod,
@@ -431,7 +436,7 @@ final class ActivityController extends AbstractController
$this->denyAccessUnlessGranted(ActivityVoter::CREATE, $entity);
$form = $this->createForm(ActivityType::class, $entity, [
'center' => $entity->getCenter(),
'center' => $this->centerResolver->resolveCenters($entity)[0] ?? null,
'role' => new Role('CHILL_ACTIVITY_CREATE'),
'activityType' => $entity->getActivityType(),
'accompanyingPeriod' => $accompanyingPeriod,

View File

@@ -306,14 +306,14 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
* get the center
* center is extracted from person.
*/
public function getCenters(): array
public function getCenters(): iterable
{
if ($this->person instanceof Person) {
return [$this->person->getCenter()];
}
if ($this->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
return $this->getAccompanyingPeriod()->getCenters();
return $this->getAccompanyingPeriod()->getCenters() ?? [];
}
return [];

View File

@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class BySocialActionAggregator implements AggregatorInterface
{
private SocialActionRender $actionRender;
private SocialActionRepository $actionRepository;
public function __construct(
SocialActionRender $actionRender,
SocialActionRepository $actionRepository
) {
$this->actionRender = $actionRender;
$this->actionRepository = $actionRepository;
}
public function getLabels($key, array $values, $data)
{
return function($value) {
if ('_header' === $value) {
return 'Social action';
}
$sa = $this->actionRepository->find($value);
return $this->actionRender->renderString($sa, []);
};
}
public function getQueryKeys($data): array
{
return ['socialaction_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group activity by linked socialaction';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
if(!in_array('socialaction', $qb->getAllAliases())) {
$qb->join('activity.socialActions', 'socialaction');
}
$qb->addSelect('socialaction.id AS socialaction_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('socialaction_aggregator');
} else {
$qb->groupBy('socialaction_aggregator');
}
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class BySocialIssueAggregator implements AggregatorInterface
{
private SocialIssueRepository $issueRepository;
private SocialIssueRender $issueRender;
public function __construct(
SocialIssueRepository $issueRepository,
SocialIssueRender $issueRender
) {
$this->issueRepository = $issueRepository;
$this->issueRender = $issueRender;
}
public function getLabels($key, array $values, $data)
{
return function ($value): string {
if ($value === '_header') {
return 'Social issues';
}
$i = $this->issueRepository->find($value);
return $this->issueRender->renderString($i, []);
};
}
public function getQueryKeys($data): array
{
return ['socialissue_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group activity by linked socialissue';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('socialissue', $qb->getAllAliases())) {
$qb->join('activity.socialIssues', 'socialissue');
}
$qb->addSelect('socialissue.id AS socialissue_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('socialissue_aggregator');
} else {
$qb->groupBy('socialissue_aggregator');
}
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class ByThirdpartyAggregator implements AggregatorInterface
{
private ThirdPartyRepository $thirdPartyRepository;
private ThirdPartyRender $thirdPartyRender;
public function __construct(
ThirdPartyRepository $thirdPartyRepository,
ThirdPartyRender $thirdPartyRender
) {
$this->thirdPartyRepository = $thirdPartyRepository;
$this->thirdPartyRender = $thirdPartyRender;
}
public function getLabels($key, array $values, $data)
{
return function ($value): string {
if ($value === '_header') {
return 'Accepted thirdparty';
}
$tp = $this->thirdPartyRepository->find($value);
return $this->thirdPartyRender->renderString($tp, []);
};
}
public function getQueryKeys($data): array
{
return ['thirdparty_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group activity by linked thirdparties';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('thirdparty', $qb->getAllAliases())) {
$qb->join('activity.thirdParties', 'thirdparty');
}
$qb->addSelect('thirdparty.id AS thirdparty_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('thirdparty_aggregator');
} else {
$qb->groupBy('thirdparty_aggregator');
}
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Templating\Entity\UserRender;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class ByUserAggregator implements AggregatorInterface
{
private UserRepository $userRepository;
private UserRender $userRender;
public function __construct(
UserRepository $userRepository,
UserRender $userRender
) {
$this->userRepository = $userRepository;
$this->userRender = $userRender;
}
public function getLabels($key, array $values, $data)
{
return function ($value): string {
if ($value === '_header') {
return 'Accepted users';
}
$u = $this->userRepository->find($value);
return $this->userRender->renderString($u, []);
};
}
public function getQueryKeys($data): array
{
return ['users_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group activity by linked users';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('user', $qb->getAllAliases())) {
$qb->join('activity.users', 'user');
}
$qb->addSelect('user.id AS users_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('users_aggregator');
} else {
$qb->groupBy('users_aggregator');
}
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,129 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Closure;
use Doctrine\ORM\QueryBuilder;
use RuntimeException;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class DateAggregator implements AggregatorInterface
{
private const CHOICES = [
'by month' => 'month',
'by week' => 'week',
'by year' => 'year',
];
private CONST DEFAULT_CHOICE = 'year';
private TranslatorInterface $translator;
public function __construct(
TranslatorInterface $translator
) {
$this->translator = $translator;
}
public function getLabels($key, array $values, $data)
{
return function ($value) use ($data): string {
if ($value === '_header') {
return 'by '. $data['frequency'];
}
switch ($data['frequency']) {
case 'month':
$month = \DateTime::createFromFormat('!m', $value);
return sprintf(
"%02d (%s)",
$value,
$month->format('M')
);
case 'week':
//return $this->translator->trans('for week') .' '. $value ;
case 'year':
//return $this->translator->trans('in year') .' '. $value ;
default:
return $value;
}
};
}
public function getQueryKeys($data): array
{
return ['date_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('frequency', ChoiceType::class, [
'choices' => self::CHOICES,
'multiple' => false,
'expanded' => true,
'empty_data' => self::DEFAULT_CHOICE,
'data' => self::DEFAULT_CHOICE,
]);
}
public function getTitle(): string
{
return 'Group activity by date';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$order = null;
switch ($data['frequency']) {
case 'month':
$fmt = 'MM'; break;
case 'week':
$fmt = 'IW'; break;
case 'year':
$fmt = 'YYYY'; $order = 'DESC'; break;
default:
throw new RuntimeException(sprintf("The frequency data '%s' is invalid.", $data['frequency']));
}
$qb->addSelect(sprintf("TO_CHAR(activity.date, '%s') AS date_aggregator", $fmt));
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('date_aggregator');
} else {
$qb->groupBy('date_aggregator');
}
$orderBy = $qb->getDQLPart('orderBy');
if (!empty($orderBy)) {
$qb->addOrderBy('date_aggregator', $order);
} else {
$qb->orderBy('date_aggregator', $order);
}
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\LocationTypeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class LocationTypeAggregator implements AggregatorInterface
{
private LocationTypeRepository $locationTypeRepository;
private TranslatableStringHelper $translatableStringHelper;
public function __construct(
LocationTypeRepository $locationTypeRepository,
TranslatableStringHelper $translatableStringHelper
) {
$this->locationTypeRepository = $locationTypeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function getLabels($key, array $values, $data)
{
return function ($value): string {
if ($value === '_header') {
return 'Accepted locationtype';
}
$lt = $this->locationTypeRepository->find($value);
return $this->translatableStringHelper->localize(
$lt->getTitle()
);
};
}
public function getQueryKeys($data): array
{
return ['locationtype_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group activity by locationtype';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('location', $qb->getAllAliases())) {
$qb->join('activity.location', 'location');
}
$qb->addSelect('IDENTITY(location.locationType) AS locationtype_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('locationtype_aggregator');
} else {
$qb->groupBy('locationtype_aggregator');
}
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class UserScopeAggregator implements AggregatorInterface
{
private ScopeRepository $scopeRepository;
private TranslatableStringHelper $translatableStringHelper;
public function __construct(
ScopeRepository $scopeRepository,
TranslatableStringHelper $translatableStringHelper
) {
$this->scopeRepository = $scopeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function getLabels($key, array $values, $data)
{
return function ($value): string {
if ($value === '_header') {
return 'Scope';
}
$s = $this->scopeRepository->find($value);
return $this->translatableStringHelper->localize(
$s->getName()
);
};
}
public function getQueryKeys($data): array
{
return ['userscope_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group activity by userscope';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('user', $qb->getAllAliases())) {
$qb->join('activity.user', 'user');
}
$qb->addSelect('IDENTITY(user.mainScope) AS userscope_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('userscope_aggregator');
} else {
$qb->groupBy('userscope_aggregator');
}
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AggregatorInterface;
@@ -44,16 +45,24 @@ class ActivityTypeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
// add select element
$qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY));
if (!in_array('type', $qb->getAllAliases())) {
$qb->join('activity.activityType', 'type');
}
// add the "group by" part
$qb->addGroupBy(self::KEY);
$qb->addSelect(sprintf('IDENTITY(activity.activityType) AS %s', self::KEY));
$groupby = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy(self::KEY);
} else {
$qb->groupBy(self::KEY);
}
}
public function applyOn()
public function applyOn(): string
{
return 'activity';
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)

View File

@@ -11,9 +11,11 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Templating\Entity\UserRender;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
@@ -25,10 +27,14 @@ class ActivityUserAggregator implements AggregatorInterface
private UserRepository $userRepository;
private UserRender $userRender;
public function __construct(
UserRepository $userRepository
UserRepository $userRepository,
UserRender $userRender
) {
$this->userRepository = $userRepository;
$this->userRender = $userRender;
}
public function addRole()
@@ -47,7 +53,7 @@ class ActivityUserAggregator implements AggregatorInterface
public function applyOn(): string
{
return 'activity';
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
@@ -62,10 +68,12 @@ class ActivityUserAggregator implements AggregatorInterface
return function ($value) {
if ('_header' === $value) {
return 'activity user';
return 'Activity user';
}
return $this->userRepository->find($value)->getUsername();
$u = $this->userRepository->find($value);
return $this->userRender->renderString($u, []);
};
}

View File

@@ -9,8 +9,9 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator;
namespace Chill\ActivityBundle\Export\Aggregator\PersonAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
@@ -104,9 +105,9 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
}
}
public function applyOn()
public function applyOn(): string
{
return 'activity';
return Declarations::ACTIVITY_PERSON;
}
public function buildForm(FormBuilderInterface $builder)

View File

@@ -0,0 +1,24 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export;
/**
* This class declare constants used for the export framework.
*/
abstract class Declarations
{
public const ACTIVITY = 'activity';
public const ACTIVITY_ACP = "activity_linked_to_acp";
public const ACTIVITY_PERSON = "activity_linked_to_person";
}

View File

@@ -0,0 +1,103 @@
<?php
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Closure;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class AvgActivityDuration implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
public function __construct(
EntityManagerInterface $em
) {
$this->repository = $em->getRepository(Activity::class);
}
public function buildForm(FormBuilderInterface $builder)
{
// TODO: Implement buildForm() method.
}
public function getTitle(): string
{
return 'Average activity linked to an accompanying period duration';
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'Average activities linked to an accompanying period duration by various parameters.';
}
public function getLabels($key, array $values, $data)
{
if ('export_avg_activity_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period duration' : $value;
}
public function getQueryKeys($data): array
{
return ['export_avg_activity_duration'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getType(): string
{
return Declarations::ACTIVITY;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'acp')
;
$qb->select('AVG(activity.durationTime) as export_avg_activity_duration');
return $qb;
}
public function requiredRole(): Role
{
return new Role(ActivityStatsVoter::STATS);
}
public function supportsModifiers(): array
{
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
//PersonDeclarations::ACP_TYPE,
];
}
public function getGroup(): string
{
return 'Exports of activities linked to an accompanying period';
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Closure;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
public function __construct(
EntityManagerInterface $em
) {
$this->repository = $em->getRepository(Activity::class);
}
public function buildForm(FormBuilderInterface $builder)
{
// TODO: Implement buildForm() method.
}
public function getTitle(): string
{
return 'Average activity linked to an accompanying period visit duration';
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'Average activities linked to an accompanying period visit duration by various parameters.';
}
public function getLabels($key, array $values, $data)
{
if ('export_avg_activity_visit_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period visit duration' : $value;
}
public function getQueryKeys($data): array
{
return ['export_avg_activity_visit_duration'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getType(): string
{
return Declarations::ACTIVITY;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'acp')
;
$qb->select('AVG(activity.travelTime) as export_avg_activity_visit_duration');
return $qb;
}
public function requiredRole(): Role
{
return new Role(ActivityStatsVoter::STATS);
}
public function supportsModifiers(): array
{
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
//PersonDeclarations::ACP_TYPE,
];
}
public function getGroup(): string
{
return 'Exports of activities linked to an accompanying period';
}
}

View File

@@ -0,0 +1,110 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class CountActivity implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
public function __construct(
EntityManagerInterface $em
) {
$this->repository = $em->getRepository(Activity::class);
}
public function buildForm(FormBuilderInterface $builder)
{
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'Count activities linked to an accompanying period by various parameters.';
}
public function getLabels($key, array $values, $data)
{
if ('export_count_activity' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Number of activities linked to an accompanying period' : $value;
}
public function getQueryKeys($data): array
{
return ['export_count_activity'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'Count activities linked to an accompanying period';
}
public function getType(): string
{
return Declarations::ACTIVITY;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'acp')
;
$qb->select('COUNT(activity.id) as export_count_activity');
return $qb;
}
public function requiredRole(): Role
{
return new Role(ActivityStatsVoter::STATS);
}
public function supportsModifiers(): array
{
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
//PersonDeclarations::ACP_TYPE,
];
}
public function getGroup(): string
{
return 'Exports of activities linked to an accompanying period';
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Closure;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class SumActivityDuration implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
public function __construct(
EntityManagerInterface $em
) {
$this->repository = $em->getRepository(Activity::class);
}
public function buildForm(FormBuilderInterface $builder)
{
// TODO: Implement buildForm() method.
}
public function getTitle(): string
{
return 'Sum activity linked to an accompanying period duration';
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'Sum activities linked to an accompanying period duration by various parameters.';
}
public function getLabels($key, array $values, $data)
{
if ('export_sum_activity_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period duration' : $value;
}
public function getQueryKeys($data): array
{
return ['export_sum_activity_duration'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getType(): string
{
return Declarations::ACTIVITY;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'acp')
;
$qb->select('SUM(activity.durationTime) as export_sum_activity_duration');
return $qb;
}
public function requiredRole(): Role
{
return new Role(ActivityStatsVoter::STATS);
}
public function supportsModifiers(): array
{
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
//PersonDeclarations::ACP_TYPE,
];
}
public function getGroup(): string
{
return 'Exports of activities linked to an accompanying period';
}
}

View File

@@ -0,0 +1,102 @@
<?php
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Closure;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class SumActivityVisitDuration implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
public function __construct(
EntityManagerInterface $em
) {
$this->repository = $em->getRepository(Activity::class);
}
public function buildForm(FormBuilderInterface $builder)
{
// TODO: Implement buildForm() method.
}
public function getTitle(): string
{
return 'Sum activity linked to an accompanying period visit duration';
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'Sum activities linked to an accompanying period visit duration by various parameters.';
}
public function getLabels($key, array $values, $data)
{
if ('export_sum_activity_visit_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period visit duration' : $value;
}
public function getQueryKeys($data): array
{
return ['export_sum_activity_visit_duration'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getType(): string
{
return Declarations::ACTIVITY;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'acp')
;
$qb->select('SUM(activity.travelTime) as export_sum_activity_visit_duration');
return $qb;
}
public function requiredRole(): Role
{
return new Role(ActivityStatsVoter::STATS);
}
public function supportsModifiers(): array
{
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
//PersonDeclarations::ACP_TYPE,
];
}
public function getGroup(): string
{
return 'Exports of activities linked to an accompanying period';
}
}

View File

@@ -9,18 +9,21 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export;
namespace Chill\ActivityBundle\Export\Export\LinkedToPerson;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\ActivityBundle\Export\Declarations;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class CountActivity implements ExportInterface
class CountActivity implements ExportInterface, GroupedExportInterface
{
protected ActivityRepository $activityRepository;
@@ -41,7 +44,7 @@ class CountActivity implements ExportInterface
public function getDescription()
{
return 'Count activities by various parameters.';
return 'Count activities linked to a person by various parameters.';
}
public function getLabels($key, array $values, $data)
@@ -50,7 +53,7 @@ class CountActivity implements ExportInterface
throw new LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Number of activities' : $value;
return static fn ($value) => '_header' === $value ? 'Number of activities linked to a person' : $value;
}
public function getQueryKeys($data)
@@ -65,27 +68,28 @@ class CountActivity implements ExportInterface
public function getTitle()
{
return 'Count activities';
return 'Count activities linked to a person';
}
public function getType()
public function getType(): string
{
return 'activity';
return Declarations::ACTIVITY;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this
->activityRepository
->createQueryBuilder('activity')
->select('COUNT(activity.id) as export_count_activity')
->join('activity.person', 'person');
$qb = $this->activityRepository->createQueryBuilder('activity')
->join('activity.person', 'person')
;
$qb->select('COUNT(activity.id) as export_count_activity');
$qb
->where($qb->expr()->in('person.center', ':centers'))
->setParameter('centers', $centers);
->setParameter('centers', $centers)
;
return $qb;
}
@@ -97,6 +101,15 @@ class CountActivity implements ExportInterface
public function supportsModifiers()
{
return ['person', 'activity'];
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_PERSON,
//PersonDeclarations::PERSON_TYPE,
];
}
public function getGroup(): string
{
return 'Exports of activities linked to a person';
}
}

View File

@@ -9,12 +9,13 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export;
namespace Chill\ActivityBundle\Export\Export\LinkedToPerson;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use DateTime;
@@ -27,12 +28,14 @@ use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Chill\ActivityBundle\Export\Declarations;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use function array_key_exists;
use function count;
use function in_array;
class ListActivity implements ListInterface
class ListActivity implements ListInterface, GroupedExportInterface
{
protected EntityManagerInterface $entityManager;
@@ -94,7 +97,7 @@ class ListActivity implements ListInterface
public function getDescription()
{
return 'List activities';
return 'List activities linked to a person description';
}
public function getLabels($key, array $values, $data)
@@ -180,12 +183,12 @@ class ListActivity implements ListInterface
public function getTitle()
{
return 'List activities';
return 'List activity linked to a person';
}
public function getType()
public function getType(): string
{
return 'activity';
return Declarations::ACTIVITY;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
@@ -274,6 +277,15 @@ class ListActivity implements ListInterface
public function supportsModifiers()
{
return ['activity', 'person'];
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_PERSON,
//PersonDeclarations::PERSON_TYPE,
];
}
public function getGroup(): string
{
return 'Exports of activities linked to a person';
}
}

View File

@@ -9,12 +9,16 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export;
namespace Chill\ActivityBundle\Export\Export\LinkedToPerson;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Chill\ActivityBundle\Export\Declarations;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
@@ -25,7 +29,7 @@ use Symfony\Component\Security\Core\Role\Role;
*
* The desired stat must be given in constructor.
*/
class StatActivityDuration implements ExportInterface
class StatActivityDuration implements ExportInterface, GroupedExportInterface
{
public const SUM = 'sum';
@@ -59,7 +63,7 @@ class StatActivityDuration implements ExportInterface
public function getDescription()
{
if (self::SUM === $this->action) {
return 'Sum activities duration by various parameters.';
return 'Sum activities linked to a person duration by various parameters.';
}
}
@@ -69,7 +73,7 @@ class StatActivityDuration implements ExportInterface
throw new LogicException(sprintf('The key %s is not used by this export', $key));
}
$header = self::SUM === $this->action ? 'Sum of activities duration' : false;
$header = self::SUM === $this->action ? 'Sum activities linked to a person duration' : false;
return static fn (string $value) => '_header' === $value ? $header : $value;
}
@@ -87,19 +91,19 @@ class StatActivityDuration implements ExportInterface
public function getTitle()
{
if (self::SUM === $this->action) {
return 'Sum activity duration';
return 'Sum activity linked to a person duration';
}
}
public function getType()
public function getType(): string
{
return 'activity';
return Declarations::ACTIVITY;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(
static fn (array $el): string => $el['center'],
static fn (array $el): Center => $el['center'],
$acl
);
@@ -125,6 +129,15 @@ class StatActivityDuration implements ExportInterface
public function supportsModifiers()
{
return ['person', 'activity'];
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_PERSON,
//PersonDeclarations::PERSON_TYPE,
];
}
public function getGroup(): string
{
return 'Exports of activities linked to a person';
}
}

View File

@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\MainBundle\Export\FilterInterface;
use Chill\ActivityBundle\Export\Declarations;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class BySocialActionFilter implements FilterInterface
{
private SocialActionRender $actionRender;
public function __construct(SocialActionRender $actionRender)
{
$this->actionRender = $actionRender;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_socialactions', EntityType::class, [
'class' => SocialAction::class,
'choice_label' => function (SocialAction $sa) {
return $this->actionRender->renderString($sa, []);
},
'multiple' => true,
'expanded' => true,
]);
}
public function getTitle(): string
{
return 'Filter activity by linked socialaction';
}
public function describeAction($data, $format = 'string'): array
{
$actions = [];
foreach ($data['accepted_socialactions'] as $sa) {
$actions[] = $this->actionRender->renderString($sa, []);
}
return ['Filtered activity by linked socialaction: only %actions%', [
'%actions%' => implode(", ou ", $actions)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
if (!in_array('socialaction', $qb->getAllAliases())) {
$qb->join('activity.socialActions', 'socialaction');
}
$clause = $qb->expr()->in('socialaction.id', ':socialactions');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('socialactions', $data['accepted_socialactions']);
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\MainBundle\Export\FilterInterface;
use Chill\ActivityBundle\Export\Declarations;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class BySocialIssueFilter implements FilterInterface
{
private SocialIssueRender $issueRender;
public function __construct(SocialIssueRender $issueRender)
{
$this->issueRender = $issueRender;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_socialissues', EntityType::class, [
'class' => SocialIssue::class,
'choice_label' => function(SocialIssue $si) {
return $this->issueRender->renderString($si, []);
},
'multiple' => true,
'expanded' => true,
]);
}
public function getTitle(): string
{
return 'Filter activity by linked socialissue';
}
public function describeAction($data, $format = 'string'): array
{
$issues = [];
foreach ($data['accepted_socialissues'] as $si) {
$issues[] = $this->issueRender->renderString($si, []);
}
return ['Filtered activity by linked socialissue: only %issues%', [
'%issues%' => implode(", ou ", $issues)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
if (!in_array('socialissue', $qb->getAllAliases())) {
$qb->join('activity.socialIssues', 'socialissue');
}
$clause = $qb->expr()->in('socialissue.id', ':socialissues');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('socialissues', $data['accepted_socialissues']);
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\FilterInterface;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Templating\Entity\UserRender;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class ByUserFilter implements FilterInterface
{
private UserRender $userRender;
public function __construct(UserRender $userRender)
{
$this->userRender = $userRender;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_users', EntityType::class, [
'class' => User::class,
'choice_label' => function (User $u) {
return $this->userRender->renderString($u, []);
},
'multiple' => true,
'expanded' => true,
]);
}
public function getTitle(): string
{
return 'Filter activity by linked users';
}
public function describeAction($data, $format = 'string'): array
{
$users = [];
foreach ($data['accepted_users'] as $u) {
$users[] = $this->userRender->renderString($u, []);
}
return ['Filtered activity by linked users: only %users%', [
'%users%' => implode(", ou ", $users)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
if (!in_array('user', $qb->getAllAliases())) {
$qb->join('activity.users', 'user');
}
$clause = $qb->expr()->in('user.id', ':users');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('users', $data['accepted_users']);
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\MainBundle\Export\FilterInterface;
use Chill\ActivityBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class EmergencyFilter implements FilterInterface
{
private const CHOICES = [
'activity is emergency' => true,
'activity is not emergency' => false,
];
private CONST DEFAULT_CHOICE = false;
private TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_emergency', ChoiceType::class, [
'choices' => self::CHOICES,
'multiple' => false,
'expanded' => true,
'empty_data' => self::DEFAULT_CHOICE,
'data' => self::DEFAULT_CHOICE,
]);
}
public function getTitle(): string
{
return 'Filter activity by emergency';
}
public function describeAction($data, $format = 'string'): array
{
foreach (self::CHOICES as $k => $v) {
if ($v === $data['accepted_emergency']) {
$choice = $k;
}
}
return ['Filtered activity by emergency: only %emergency%', [
'%emergency%' => $this->translator->trans($choice)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->eq('activity.emergency', ':emergency');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('emergency', $data['accepted_emergency']);
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\MainBundle\Entity\LocationType;
use Chill\MainBundle\Export\FilterInterface;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class LocationTypeFilter implements FilterInterface
{
private TranslatableStringHelper $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_locationtype', EntityType::class, [
'class' => LocationType::class,
'choice_label' => function(LocationType $type) {
return $this->translatableStringHelper->localize($type->getTitle());
},
'multiple' => true,
'expanded' => true,
]);
}
public function getTitle(): string
{
return 'Filter activity by locationtype';
}
public function describeAction($data, $format = 'string'): array
{
$types = [];
foreach ($data['accepted_locationtype'] as $type) {
$types[] = $this->translatableStringHelper->localize(
$type->getTitle()
);
}
return ['Filtered activity by locationtype: only %types%', [
'%types%' => implode(", ou ", $types)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('location', $qb->getAllAliases())) {
$qb->join('activity.location', 'location');
}
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('location.locationType', ':locationtype');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('locationtype', $data['accepted_locationtype']);
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\Export\FilterInterface;
use Chill\ActivityBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class SentReceivedFilter implements FilterInterface
{
private const CHOICES = [
'is sent' => Activity::SENTRECEIVED_SENT,
'is received' => Activity::SENTRECEIVED_RECEIVED,
];
private CONST DEFAULT_CHOICE = Activity::SENTRECEIVED_SENT;
private TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_sentreceived', ChoiceType::class, [
'choices' => self::CHOICES,
'multiple' => false,
'expanded' => true,
'empty_data' => self::DEFAULT_CHOICE,
'data' => self::DEFAULT_CHOICE,
]);
}
public function getTitle(): string
{
return 'Filter activity by sentreceived';
}
public function describeAction($data, $format = 'string'): array
{
$sentreceived = array_flip(self::CHOICES)[$data['accepted_sentreceived']];
return ['Filtered activity by sentreceived: only %sentreceived%', [
'%sentreceived%' => $this->translator->trans($sentreceived)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->eq('activity.sentReceived', ':sentreceived');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('sentreceived', $data['accepted_sentreceived']);
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\FilterInterface;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Templating\Entity\UserRender;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class UserFilter implements FilterInterface
{
private UserRender $userRender;
public function __construct(UserRender $userRender)
{
$this->userRender = $userRender;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_users', EntityType::class, [
'class' => User::class,
'choice_label' => function (User $u) {
return $this->userRender->renderString($u, []);
},
'multiple' => true,
'expanded' => true,
'label' => 'Creators'
]);
}
public function getTitle(): string
{
return 'Filter activity by user';
}
public function describeAction($data, $format = 'string'): array
{
$users = [];
foreach ($data['accepted_users'] as $u) {
$users[] = $this->userRender->renderString($u, []);
}
return ['Filtered activity by user: only %users%', [
'%users%' => implode(", ou ", $users)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('activity.user', ':users');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('users', $data['accepted_users']);
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -0,0 +1,89 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Export\FilterInterface;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class UserScopeFilter implements FilterInterface
{
private TranslatableStringHelper $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_userscope', EntityType::class, [
'class' => Scope::class,
'choice_label' => function (Scope $s) {
return $this->translatableStringHelper->localize(
$s->getName()
);
},
'multiple' => true,
'expanded' => true
]);
}
public function getTitle(): string
{
return 'Filter activity by userscope';
}
public function describeAction($data, $format = 'string'): array
{
$scopes = [];
foreach ($data['accepted_userscope'] as $s) {
$scopes[] = $this->translatableStringHelper->localize(
$s->getName()
);
}
return ['Filtered activity by userscope: only %scopes%', [
'%scopes%' => implode(", ou ", $scopes)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('user', $qb->getAllAliases())) {
$qb->join('activity.user', 'user');
}
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('user.mainScope', ':userscope');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('userscope', $data['accepted_userscope']);
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
}

View File

@@ -11,12 +11,13 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\Export\FilterType;
use DateTime;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
@@ -57,36 +58,23 @@ class ActivityDateFilter implements FilterInterface
$qb->setParameter('date_to', $data['date_to']);
}
public function applyOn()
public function applyOn(): string
{
return 'activity';
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add(
'date_from',
DateType::class,
[
$builder
->add('date_from', ChillDateType::class, [
'label' => 'Activities after this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
]
);
$builder->add(
'date_to',
DateType::class,
[
])
->add('date_to', ChillDateType::class, [
'label' => 'Activities before this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
]
);
])
;
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
/** @var \Symfony\Component\Form\FormInterface $filterForm */

View File

@@ -12,6 +12,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
@@ -49,7 +50,7 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('activity.type', ':selected_activity_types');
$clause = $qb->expr()->in('activity.activityType', ':selected_activity_types');
if ($where instanceof Expr\Andx) {
$where->add($clause);
@@ -61,39 +62,33 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
$qb->setParameter('selected_activity_types', $data['types']);
}
public function applyOn()
public function applyOn(): string
{
return 'activity';
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add(
'types',
EntityType::class,
[
'class' => ActivityType::class,
'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
'multiple' => true,
'expanded' => false,
]
);
$builder->add('types', EntityType::class, [
'class' => ActivityType::class,
'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
'group_by' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getCategory()->getName()),
'multiple' => true,
'expanded' => false,
]);
}
public function describeAction($data, $format = 'string')
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
fn (ActivityType $t): string => '"' . $this->translatableStringHelper->localize($t->getName()) . '"',
fn (ActivityType $t): string => $this->translatableStringHelper->localize($t->getName()),
$this->activityTypeRepository->findBy(['id' => $data['types']->toArray()])
);
return [
'Filtered by activity type: only %list%',
[
'%list%' => implode(', ', $reasonsNames),
],
];
return ['Filtered by activity type: only %list%', [
'%list%' => implode(', ou ', $reasonsNames),
]];
}
public function getTitle()

View File

@@ -9,9 +9,10 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter;
namespace Chill\ActivityBundle\Export\Filter\PersonFilters;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
@@ -79,9 +80,9 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
$qb->setParameter('selected_activity_reasons', $data['reasons']);
}
public function applyOn()
public function applyOn(): string
{
return 'activity';
return Declarations::ACTIVITY_PERSON;
}
public function buildForm(FormBuilderInterface $builder)

View File

@@ -9,7 +9,7 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter;
namespace Chill\ActivityBundle\Export\Filter\PersonFilters;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
@@ -102,7 +102,7 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
$qb->setParameter('person_having_activity_reasons', $data['reasons']);
}
public function applyOn()
public function applyOn(): string
{
return Declarations::PERSON_IMPLIED_IN;
}

View File

@@ -3,26 +3,48 @@ services:
autowire: true
autoconfigure: true
chill.activity.export.count_activity:
class: Chill\ActivityBundle\Export\Export\CountActivity
## Indicators
chill.activity.export.count_activity_linked_to_person:
class: Chill\ActivityBundle\Export\Export\LinkedToPerson\CountActivity
tags:
- { name: chill.export, alias: 'count_activity' }
- { name: chill.export, alias: 'count_activity_linked_to_person' }
chill.activity.export.sum_activity_duration:
class: Chill\ActivityBundle\Export\Export\StatActivityDuration
chill.activity.export.sum_activity_duration_linked_to_person:
class: Chill\ActivityBundle\Export\Export\LinkedToPerson\StatActivityDuration
tags:
- { name: chill.export, alias: 'sum_activity_duration' }
- { name: chill.export, alias: 'sum_activity_duration_linked_to_person' }
chill.activity.export.list_activity:
class: Chill\ActivityBundle\Export\Export\ListActivity
chill.activity.export.list_activity_linked_to_person:
class: Chill\ActivityBundle\Export\Export\LinkedToPerson\ListActivity
tags:
- { name: chill.export, alias: 'list_activity' }
- { name: chill.export, alias: 'list_activity_linked_to_person' }
chill.activity.export.reason_filter:
class: Chill\ActivityBundle\Export\Filter\ActivityReasonFilter
chill.activity.export.count_activity_linked_to_acp:
class: Chill\ActivityBundle\Export\Export\LinkedToACP\CountActivity
tags:
- { name: chill.export_filter, alias: 'activity_reason_filter' }
- { name: chill.export, alias: 'count_activity_linked_to_acp' }
chill.activity.export.sum_activity_duration_linked_to_acp:
class: Chill\ActivityBundle\Export\Export\LinkedToACP\SumActivityDuration
tags:
- { name: chill.export, alias: 'sum_activity_duration_linked_to_acp' }
chill.activity.export.sum_activity_visit_duration_linked_to_acp:
class: Chill\ActivityBundle\Export\Export\LinkedToACP\SumActivityVisitDuration
tags:
- { name: chill.export, alias: 'sum_activity_visit_duration_linked_to_acp' }
chill.activity.export.avg_activity_duration_linked_to_acp:
class: Chill\ActivityBundle\Export\Export\LinkedToACP\AvgActivityDuration
tags:
- { name: chill.export, alias: 'avg_activity_duration_linked_to_acp' }
chill.activity.export.avg_activity_visit_duration_linked_to_acp:
class: Chill\ActivityBundle\Export\Export\LinkedToACP\AvgActivityVisitDuration
tags:
- { name: chill.export, alias: 'avg_activity_visit_duration_linked_to_acp' }
## Filters
chill.activity.export.type_filter:
class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter
tags:
@@ -33,15 +55,61 @@ services:
tags:
- { name: chill.export_filter, alias: 'activity_date_filter' }
chill.activity.export.reason_filter:
class: Chill\ActivityBundle\Export\Filter\PersonFilters\ActivityReasonFilter
tags:
- { name: chill.export_filter, alias: 'activity_reason_filter' }
chill.activity.export.person_having_an_activity_between_date_filter:
class: Chill\ActivityBundle\Export\Filter\PersonHavingActivityBetweenDateFilter
class: Chill\ActivityBundle\Export\Filter\PersonFilters\PersonHavingActivityBetweenDateFilter
tags:
- #0 register as a filter
name: chill.export_filter
alias: 'activity_person_having_ac_bw_date_filter'
chill.activity.export.locationtype_filter:
class: Chill\ActivityBundle\Export\Filter\ACPFilters\LocationTypeFilter
tags:
- { name: chill.export_filter, alias: 'activity_locationtype_filter' }
chill.activity.export.byuser_filter: # TMS (M2M)
class: Chill\ActivityBundle\Export\Filter\ACPFilters\ByUserFilter
tags:
- { name: chill.export_filter, alias: 'activity_byuser_filter' }
chill.activity.export.emergency_filter:
class: Chill\ActivityBundle\Export\Filter\ACPFilters\EmergencyFilter
tags:
- { name: chill.export_filter, alias: 'activity_emergency_filter' }
chill.activity.export.sentreceived_filter:
class: Chill\ActivityBundle\Export\Filter\ACPFilters\SentReceivedFilter
tags:
- { name: chill.export_filter, alias: 'activity_sentreceived_filter' }
chill.activity.export.bysocialaction_filter:
class: Chill\ActivityBundle\Export\Filter\ACPFilters\BySocialActionFilter
tags:
- { name: chill.export_filter, alias: 'activity_bysocialaction_filter' }
chill.activity.export.bysocialissue_filter:
class: Chill\ActivityBundle\Export\Filter\ACPFilters\BySocialIssueFilter
tags:
- { name: chill.export_filter, alias: 'activity_bysocialissue_filter' }
chill.activity.export.user_filter: # Creator (M2O)
class: Chill\ActivityBundle\Export\Filter\ACPFilters\UserFilter
tags:
- { name: chill.export_filter, alias: 'activity_user_filter' }
chill.activity.export.userscope_filter:
class: Chill\ActivityBundle\Export\Filter\ACPFilters\UserScopeFilter
tags:
- { name: chill.export_filter, alias: 'activity_userscope_filter' }
## Aggregators
chill.activity.export.reason_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
class: Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator
tags:
- { name: chill.export_aggregator, alias: activity_reason_aggregator }
@@ -54,3 +122,38 @@ services:
class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
tags:
- { name: chill.export_aggregator, alias: activity_user_aggregator }
chill.activity.export.locationtype_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\LocationTypeAggregator
tags:
- { name: chill.export_aggregator, alias: activity_locationtype_aggregator }
chill.activity.export.date_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\DateAggregator
tags:
- { name: chill.export_aggregator, alias: activity_date_aggregator }
chill.activity.export.byuser_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByUserAggregator
tags:
- { name: chill.export_aggregator, alias: activity_byuser_aggregator }
chill.activity.export.bythirdparty_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByThirdpartyAggregator
tags:
- { name: chill.export_aggregator, alias: activity_bythirdparty_aggregator }
chill.activity.export.bysocialaction_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\BySocialActionAggregator
tags:
- { name: chill.export_aggregator, alias: activity_bysocialaction_aggregator }
chill.activity.export.bysocialissue_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\BySocialIssueAggregator
tags:
- { name: chill.export_aggregator, alias: activity_bysocialissue_aggregator }
chill.activity.export.userscope_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\UserScopeAggregator
tags:
- { name: chill.export_aggregator, alias: activity_userscope_aggregator }

View File

@@ -203,18 +203,39 @@ Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr d
The activity has been successfully removed.: L'activité a été supprimée.
# exports
Count activities: Nombre d'activités
Count activities by various parameters.: Compte le nombre d'activités enregistrées en fonction de différents paramètres.
Sum activity duration: Total de la durée des activités
Sum activities duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
List activities: Liste les activités
Number of activities: Nombre d'activités
Exports of activities linked to a person: Exports des activités liées à une personne
Number of activities linked to a person: Nombre d'activités liées à une personne
Count activities linked to a person: Nombre d'activités
Count activities linked to a person by various parameters.: Compte le nombre d'activités enregistrées et liées à une personne en fonction de différents paramètres.
Sum activity linked to a person duration: Durée des activités
Sum activities linked to a person duration: Durée des activités liés à un usager
Sum activities linked to a person duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
List activity linked to a person: Liste les activités
List activities linked to a person: Liste des activités liés à un usager
List activities linked to a person description: Crée la liste des activités en fonction de différents paramètres.
Exports of activities linked to an accompanying period: Exports des activités liées à un parcours
Number of activities linked to an accompanying period: Nombre d'activités liées à un parcours
Count activities linked to an accompanying period: Nombre d'activités
Count activities linked to an accompanying period by various parameters.: Compte le nombre d'activités enregistrées et liées à un parcours en fonction de différents paramètres.
Sum activity linked to an accompanying period duration: Somme de la durée des activités
Sum activities linked to an accompanying period duration: Somme de la durée des activités liées à un parcours
Sum activities linked to an accompanying period duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
Sum activity linked to an accompanying period visit duration: Somme de la durée de déplacement des activités
Sum activities linked to an accompanying period visit duration: Somme de la durée de déplacement des activités liées à un parcours
Sum activities linked to an accompanying period visit duration by various parameters.: Additionne la durée de déplacement des activités en fonction de différents paramètres.
Average activity linked to an accompanying period duration: Moyenne de la durée des activités
Average activities linked to an accompanying period duration: Moyenne de la durée des activités liées à un parcours
Average activities linked to an accompanying period duration by various parameters.: Moyenne de la durée des activités en fonction de différents paramètres.
Average activity linked to an accompanying period visit duration: Moyenne de la durée de déplacement des activités
Average activities linked to an accompanying period visit duration: Moyenne de la durée de déplacement des activités liées à un parcours
Average activities linked to an accompanying period visit duration by various parameters.: Moyenne de la durée de déplacement des activités en fonction de différents paramètres.
#filters
Filter by reason: Filtrer par sujet d'activité
Filter by reason: Filtrer les activités par sujet
'Filtered by reasons: only %list%': 'Filtré par sujet: seulement %list%'
'Filtered by activity type: only %list%': "Filtré par type d'activity: seulement %list%"
Filtered by date activity: Filtrer par date d'activité
'Filtered by activity type: only %list%': "Filtré par type d'activité: uniquement %list%"
Filtered by date activity: Filtrer les activités par date
Activities after this date: Activités après cette date
Activities before this date: Activités avant cette date
"Filtered by date of activity: only between %date_from% and %date_to%": "Filtré par date de l'activité: uniquement entre %date_from% et %date_to%"
@@ -226,18 +247,59 @@ Implied in an activity before this date: Impliqué dans une activité avant cett
Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Filtré par personnes associées à une activité entre %date_from% et %date_to% avec les sujets %reasons_name%
Activity reasons for those activities: Sujets de ces activités
Filter by activity type: Filtrer par type d'activité
Filter by activity type: Filtrer les activités par type
Filter activity by locationtype: Filtrer les activités par type de localisation
'Filtered activity by locationtype: only %types%': "Filtré par type de localisation: uniquement %types%"
Accepted locationtype: Types de localisation
Filter activity by linked users: Filtrer les activités par TMS
'Filtered activity by linked users: only %users%': "Filtré par TMS: uniquement %users%"
Accepted users: TMS(s)
Filter activity by emergency: Filtrer les activités par urgence
'Filtered activity by emergency: only %emergency%': "Filtré par urgence: uniquement si %emergency%"
activity is emergency: l'activité est urgente
activity is not emergency: l'activité n'est pas urgente
Filter activity by sentreceived: Filtrer les activités par envoyé/reçu
'Filtered activity by sentreceived: only %sentreceived%': "Filtré par envoyé/reçu: uniquement %sentreceived%"
Accepted sentreceived: ''
is sent: envoyé
is received: reçu
Filter activity by linked socialaction: Filtrer les activités par action liée
'Filtered activity by linked socialaction: only %actions%': "Filtré par action liée: uniquement %actions%"
Filter activity by linked socialissue: Filtrer les activités par problématique liée
'Filtered activity by linked socialissue: only %issues%': "Filtré par problématique liée: uniquement %issues%"
Filter activity by user: Filtrer les activités par créateur
'Filtered activity by user: only %users%': "Filtré par créateur: uniquement %users%"
Creators: Créateurs
Filter activity by userscope: Filtrer les activités par service du créateur
'Filtered activity by userscope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
Accepted userscope: Services
#aggregators
Activity type: Type d'activité
Activity user: Utilisateur lié à l'activity
Activity user: Utilisateur lié à l'activité
By reason: Par sujet
By category of reason: Par catégorie de sujet
Reason's level: Niveau du sujet
Group by reasons: Sujet d'activité
Aggregate by activity user: Aggréger par utilisateur lié à l'activité
Aggregate by activity type: Aggréger par type d'activité
Aggregate by activity reason: Aggréger par sujet de l'activité
Aggregate by activity user: Grouper les activités par utilisateur
Aggregate by activity type: Grouper les activités par type
Aggregate by activity reason: Grouper les activités par sujet
Group activity by locationtype: Grouper les activités par type de localisation
Group activity by date: Grouper les activités par date
Frequency: Fréquence
by month: Par mois
by week: Par semaine
for week: Semaine
by year: Par année
in year: En
Group activity by linked users: Grouper les activités par TMS impliqué
Group activity by linked thirdparties: Grouper les activités par tiers impliqué
Accepted thirdparty: Tiers impliqué
Group activity by linked socialaction: Grouper les activités par action liée
Group activity by linked socialissue: Grouper les activités par problématique liée
Group activity by userscope: Grouper les activités par service du créateur
Last activities: Les dernières activités

View File

@@ -195,7 +195,7 @@ Number of activities: Nombre d'activités
#filters
Filter by reason: Filtrer par sujet d'activité
'Filtered by reasons: only %list%': 'Filtré par sujet: seulement %list%'
'Filtered by activity type: only %list%': "Filtré par type d'activity: seulement %list%"
'Filtered by activity type: only %list%': "Filtré par type d'activity: uniquement %list%"
Filtered by date activity: Filtrer par date d'activité
Activities after this date: Activités après cette date
Activities before this date: Activités avant cette date
@@ -217,9 +217,9 @@ By reason: Par sujet
By category of reason: Par catégorie de sujet
Reason's level: Niveau du sujet
Group by reasons: Sujet d'activité
Aggregate by activity user: Aggréger par utilisateur lié à l'activité
Aggregate by activity type: Aggréger par type d'activité
Aggregate by activity reason: Aggréger par sujet de l'activité
Aggregate by activity user: Grouper par utilisateur lié à l'activité
Aggregate by activity type: Grouper par type d'activité
Aggregate by activity reason: Grouper par sujet de l'activité
Last activities: Les dernières activités

View File

@@ -32,6 +32,7 @@ class ChillCalendarExtension extends Extension implements PrependExtensionInterf
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
$loader->load('services/exports.yaml');
$loader->load('services/controller.yml');
$loader->load('services/fixtures.yml');
$loader->load('services/form.yml');

View File

@@ -0,0 +1,79 @@
<?php
namespace Chill\CalendarBundle\Export\Aggregator;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Templating\Entity\UserRender;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
final class AgentAggregator implements AggregatorInterface
{
private UserRepository $userRepository;
private UserRender $userRender;
public function __construct(
UserRepository $userRepository,
UserRender $userRender
) {
$this->userRepository = $userRepository;
$this->userRender = $userRender;
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->join('cal.user', 'u');
$qb->addSelect('u.id AS agent_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('agent_aggregator');
} else {
$qb->groupBy('agent_aggregator');
}
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getLabels($key, array $values, $data): \Closure
{
return function ($value): string {
if ('_header' === $value) {
return 'Agent';
}
$r = $this->userRepository->find($value);
return $this->userRender->renderString($r, []);
};
}
public function getQueryKeys($data): array
{
return ['agent_aggregator'];
}
public function getTitle(): string
{
return 'Group by agent';
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace Chill\CalendarBundle\Export\Aggregator;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Repository\CancelReasonRepository;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class CancelReasonAggregator implements AggregatorInterface
{
private CancelReasonRepository $cancelReasonRepository;
private TranslatableStringHelper $translatableStringHelper;
public function __construct(
CancelReasonRepository $cancelReasonRepository,
TranslatableStringHelper $translatableStringHelper
) {
$this->cancelReasonRepository = $cancelReasonRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function getLabels($key, array $values, $data): \Closure
{
return function($value): string {
if ($value === '_header') {
return 'Cancel reason';
}
$j = $this->cancelReasonRepository->find($value);
return $this->translatableStringHelper->localize(
$j->getName()
);
};
}
public function getQueryKeys($data): array
{
return ['cancel_reason_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group by cancel reason';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
// TODO: still needs to take into account appointments without a cancel reason somehow
$qb->join('cal.cancelReason', 'cr');
$qb->addSelect('IDENTITY(cal.cancelReason) as cancel_reason_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('cancel_reason_aggregator');
} else {
$qb->groupBy('cancel_reason_aggregator');
}
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Chill\CalendarBundle\Export\Aggregator;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\UserJobRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
final class JobAggregator implements AggregatorInterface
{
private UserJobRepository $jobRepository;
private TranslatableStringHelper $translatableStringHelper;
public function __construct(
UserJobRepository $jobRepository,
TranslatableStringHelper $translatableStringHelper
) {
$this->jobRepository = $jobRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function getLabels($key, array $values, $data): \Closure
{
return function($value): string {
if ($value === '_header') {
return 'Job';
}
$j = $this->jobRepository->find($value);
return $this->translatableStringHelper->localize(
$j->getLabel()
);
};
}
public function getQueryKeys($data): array
{
return ['job_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group by agent job';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->join('cal.user', 'u');
$qb->addSelect('IDENTITY(u.userJob) as job_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('job_aggregator');
} else {
$qb->groupBy('job_aggregator');
}
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace Chill\CalendarBundle\Export\Aggregator;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\LocationRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
final class LocationAggregator implements AggregatorInterface
{
private LocationRepository $locationRepository;
public function __construct(
LocationRepository $locationRepository
) {
$this->locationRepository = $locationRepository;
}
public function getLabels($key, array $values, $data): \Closure
{
return function($value): string {
if ($value === '_header') {
return 'Location';
}
$l = $this->locationRepository->find($value);
return $l->getName();
};
}
public function getQueryKeys($data): array
{
return ['location_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group by location';
}
public function addRole(): ?Role
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->join('cal.location', 'l');
$qb->addSelect('IDENTITY(cal.location) as location_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('location_aggregator');
} else {
$qb->groupBy('location_aggregator');
}
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace Chill\CalendarBundle\Export\Aggregator;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\LocationTypeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
final class LocationTypeAggregator implements AggregatorInterface
{
private LocationTypeRepository $locationTypeRepository;
private TranslatableStringHelper $translatableStringHelper;
public function __construct(
LocationTypeRepository $locationTypeRepository,
TranslatableStringHelper $translatableStringHelper
) {
$this->locationTypeRepository = $locationTypeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function getLabels($key, array $values, $data): \Closure
{
return function($value): string {
if ($value === '_header') {
return 'Location type';
}
$j = $this->locationTypeRepository->find($value);
return $this->translatableStringHelper->localize(
$j->getTitle()
);
};
}
public function getQueryKeys($data): array
{
return ['location_type_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group by location type';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->join('cal.location', 'l');
$qb->addSelect('IDENTITY(l.locationType) as location_type_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('location_type_aggregator');
} else {
$qb->groupBy('location_type_aggregator');
}
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace Chill\CalendarBundle\Export\Aggregator;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class MonthYearAggregator implements AggregatorInterface
{
public function getQueryKeys($data): array
{
return ['month_year_aggregator'];
}
public function getLabels($key, array $values, $data): Closure
{
return function($value): string {
if ($value === '_header') {
return 'by month and year';
}
$month = substr($value,0, 2);
$year = substr($value, 3, 4);
return strftime('%B %G', mktime(0, 0, 0, $month, '1', $year));
};
}
public function buildForm(FormBuilderInterface $builder)
{
// No form needed
}
public function getTitle(): string
{
return 'Group by month and year';
}
public function addRole(): ?Role
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->addSelect("to_char(cal.startDate, 'MM-YYYY') AS month_year_aggregator");
// $qb->addSelect("extract(month from age(cal.startDate, cal.endDate)) AS month_aggregator");
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('month_year_aggregator');
} else {
$qb->groupBy('month_year_aggregator');
}
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Chill\CalendarBundle\Export\Aggregator;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
final class ScopeAggregator implements AggregatorInterface
{
private ScopeRepository $scopeRepository;
private TranslatableStringHelper $translatableStringHelper;
public function __construct(
ScopeRepository $scopeRepository,
TranslatableStringHelper $translatableStringHelper
) {
$this->scopeRepository = $scopeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function getLabels($key, array $values, $data): \Closure
{
return function ($value): string {
if ($value === '_header') {
return 'Scope';
}
$s = $this->scopeRepository->find($value);
return $this->translatableStringHelper->localize(
$s->getName()
);
};
}
public function getQueryKeys($data): array
{
return ['scope_aggregator'];
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getTitle(): string
{
return 'Group by agent scope';
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->join('cal.user', 'u');
$qb->addSelect('IDENTITY(u.mainScope) as scope_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('scope_aggregator');
} else {
$qb->groupBy('scope_aggregator');
}
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\CalendarBundle\Export;
/**
* This class declare constants used for the export framework.
*/
abstract class Declarations
{
public const CALENDAR_TYPE = 'calendar';
}

View File

@@ -0,0 +1,111 @@
<?php
namespace Chill\CalendarBundle\Export\Export;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\CalendarBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Security\Core\Role\Role;
class CountAppointments implements ExportInterface, GroupedExportInterface
{
private CalendarRepository $calendarRepository;
public function __construct(CalendarRepository $calendarRepository)
{
$this->calendarRepository = $calendarRepository;
}
public function buildForm(FormBuilderInterface $builder)
{
// No form necessary
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'Count appointments by various parameters.';
}
public function getLabels($key, array $values, $data): \Closure
{
if ('export_result' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
}
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static function ($value) use ($labels) {
return $labels[$value];
};
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR);
}
public function getTitle(): string
{
return 'Count appointments';
}
public function getType(): string
{
return Declarations::CALENDAR_TYPE;
}
/**
* Initiate the query.
*/
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->calendarRepository->createQueryBuilder('cal');
$qb->select('COUNT(cal.id) AS export_result');
return $qb;
}
public function requiredRole(): Role
{
// which role should we give here?
return new Role(PersonVoter::STATS);
}
public function supportsModifiers(): array
{
return [
Declarations::CALENDAR_TYPE,
];
}
public function getGroup(): string
{
return 'Exports of calendar';
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace Chill\CalendarBundle\Export\Export;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class StatAppointmentAvgDuration implements ExportInterface, GroupedExportInterface
{
private CalendarRepository $calendarRepository;
public function __construct(
CalendarRepository $calendarRepository
) {
$this->calendarRepository = $calendarRepository;
}
public function buildForm(FormBuilderInterface $builder): void
{
// no form needed
}
public function getTitle(): string
{
return 'Average appointment duration';
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'Get the average of appointment duration according to various filters';
}
public function getLabels($key, array $values, $data)
{
if ('export_result' !== $key) {
throw new \LogicException("the key {$key} is not used by this export");
}
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static function ($value) use ($labels) {
return $labels[$value];
};
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getType(): string
{
return Declarations::CALENDAR_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$qb = $this->calendarRepository->createQueryBuilder('cal');
$qb
->select('AVG(cal.endDate - cal.startDate) AS export_result');
return $qb;
}
public function requiredRole(): Role
{
return new Role(AccompanyingPeriodVoter::STATS);
}
public function supportsModifiers(): array
{
return [
Declarations::CALENDAR_TYPE
];
}
public function getGroup(): string
{
return 'Exports of calendar';
}
}

View File

@@ -0,0 +1,102 @@
<?php
namespace Chill\CalendarBundle\Export\Export;
use Chill\CalendarBundle\Export\Declarations;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class StatAppointmentSumDuration implements ExportInterface, GroupedExportInterface
{
private CalendarRepository $calendarRepository;
public function __construct(
CalendarRepository $calendarRepository
) {
$this->calendarRepository = $calendarRepository;
}
public function buildForm(FormBuilderInterface $builder): void
{
// no form needed
}
public function getTitle(): string
{
return 'Sum of appointment durations';
}
public function getAllowedFormattersTypes(): array
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription(): string
{
return 'Get the sum of appointment durations according to various filters';
}
public function getLabels($key, array $values, $data)
{
if ('export_result' !== $key) {
throw new \LogicException("the key {$key} is not used by this export");
}
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static function ($value) use ($labels) {
return $labels[$value];
};
}
public function getQueryKeys($data): array
{
return ['export_result'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getType(): string
{
return Declarations::CALENDAR_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$qb = $this->calendarRepository->createQueryBuilder('cal');
$qb
->select('SUM(cal.endDate - cal.startDate) AS export_result');
return $qb;
}
public function requiredRole(): Role
{
return new Role(AccompanyingPeriodVoter::STATS);
}
public function supportsModifiers(): array
{
return [
Declarations::CALENDAR_TYPE
];
}
public function getGroup(): string
{
return 'Exports of calendar';
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace Chill\CalendarBundle\Export\Filter;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\Entity\UserRender;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class AgentFilter implements FilterInterface
{
private UserRender $userRender;
public function __construct(UserRender $userRender)
{
$this->userRender = $userRender;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_agents', EntityType::class, [
'class' => User::class,
'choice_label' => function (User $u) {
return $this->userRender->renderString($u, []);
},
'multiple' => true,
'expanded' => true
]);
}
public function getTitle(): string
{
return 'Filter by agent';
}
public function describeAction($data, $format = 'string'): array
{
$users = [];
foreach ($data['accepted_agents'] as $r) {
$users[] = $r;
}
return [
'Filtered by agent: only %agents%', [
'%agents' => implode(", ou ", $users)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('cal.user', ':agents');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('agents', $data['accepted_agents']);
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Chill\CalendarBundle\Export\Filter;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class BetweenDatesFilter implements FilterInterface
{
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('date_from', ChillDateType::class, [
'data' => new \DateTime(),
])
->add('date_to', ChillDateType::class, [
'data' => new \DateTime(),
])
;
}
public function getTitle(): string
{
return 'Filter by appointments between certain dates';
}
public function describeAction($data, $format = 'string'): array
{
return ['Filtered by appointments between %dateFrom% and %dateTo%', [
'%dateFrom%' => $data['date_from']->format('d-m-Y'),
'%dateTo%' => $data['date_to']->format('d-m-Y'),
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->andX(
$qb->expr()->gte('cal.startDate', ':dateFrom'),
$qb->expr()->lte('cal.endDate', ':dateTo')
);
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('dateFrom', $data['date_from']);
// modify dateTo so that entire day is also taken into account up until the beginning of the next day.
$qb->setParameter('dateTo', $data['date_to']->modify('+1 day'));
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
}

View File

@@ -0,0 +1,99 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\CalendarBundle\Export\Filter;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class JobFilter implements FilterInterface
{
protected TranslatorInterface $translator;
private TranslatableStringHelper $translatableStringHelper;
public function __construct(
TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper
) {
$this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('job', EntityType::class, [
'class' => UserJob::class,
'choice_label' => function (UserJob $j) {
return $this->translatableStringHelper->localize(
$j->getLabel()
);
},
'multiple' => true,
'expanded' => true
]);
}
public function describeAction($data, $format = 'string'): array
{
$userJobs = [];
foreach ($data['job'] as $j) {
$userJobs[] = $this->translatableStringHelper->localize(
$j->getLabel());
}
return ['Filtered by agent job: only %jobs%', [
'%jobs%' => implode(', ou ', $userJobs)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->join('cal.user', 'u');
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('u.userJob', ':job');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('job', $data['job']);
}
public function applyOn(): string
{
return Declarations::CALENDAR_TYPE;
}
public function getTitle(): string
{
return 'Filter by agent job';
}
}

View File

@@ -0,0 +1,99 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\CalendarBundle\Export\Filter;
use Chill\CalendarBundle\Export\Declarations;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class ScopeFilter implements FilterInterface
{
protected TranslatorInterface $translator;
private TranslatableStringHelper $translatableStringHelper;
public function __construct(
TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper
) {
$this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('scope', EntityType::class, [
'class' => Scope::class,
'choice_label' => function (Scope $s) {
return $this->translatableStringHelper->localize(
$s->getName()
);
},
'multiple' => true,
'expanded' => true
]);
}
public function describeAction($data, $format = 'string')
{
$scopes = [];
foreach ($data['scope'] as $s) {
$scopes[] = $this->translatableStringHelper->localize(
$s->getName());
}
return ['Filtered by agent scope: only %scopes%', [
'%scopes%' => implode(', ou ', $scopes)
]];
}
public function addRole()
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->join('cal.user', 'u');
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('u.mainScope', ':scope');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('scope', $data['scope']);
}
public function applyOn()
{
return Declarations::CALENDAR_TYPE;
}
public function getTitle()
{
return 'Filter by agent scope';
}
}

View File

@@ -0,0 +1,104 @@
services:
## Indicators
chill.calendar.export.count_appointments:
class: Chill\CalendarBundle\Export\Export\CountAppointments
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: count_appointments }
chill.calendar.export.average_duration_appointments:
class: Chill\CalendarBundle\Export\Export\StatAppointmentAvgDuration
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: average_duration_appointments }
chill.calendar.export.sum_duration_appointments:
class: Chill\CalendarBundle\Export\Export\StatAppointmentSumDuration
autowire: true
autoconfigure: true
tags:
- { name: chill.export, alias: sum_duration_appointments }
## Filters
chill.calendar.export.agent_filter:
class: Chill\CalendarBundle\Export\Filter\AgentFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: agent_filter }
chill.calendar.export.job_filter:
class: Chill\CalendarBundle\Export\Filter\JobFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: job_filter }
chill.calendar.export.scope_filter:
class: Chill\CalendarBundle\Export\Filter\ScopeFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: scope_filter }
chill.calendar.export.between_dates_filter:
class: Chill\CalendarBundle\Export\Filter\BetweenDatesFilter
autowire: true
autoconfigure: true
tags:
- { name: chill.export_filter, alias: between_dates_filter }
## Aggregator
chill.calendar.export.agent_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\AgentAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: agent_aggregator }
chill.calendar.export.job_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\JobAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: job_aggregator }
chill.calendar.export.scope_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\ScopeAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: scope_aggregator }
chill.calendar.export.location_type_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\LocationTypeAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: location_type_aggregator }
chill.calendar.export.location_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\LocationAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: location_aggregator }
chill.calendar.export.cancel_reason_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\CancelReasonAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: cancel_reason_aggregator }
chill.calendar.export.month_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\MonthYearAggregator
autowire: true
autoconfigure: true
tags:
- { name: chill.export_aggregator, alias: month_aggregator }

View File

@@ -69,3 +69,36 @@ invite:
declined: Refusé
pending: En attente
tentative: Accepté provisoirement
# exports
Exports of calendar: Exports des rendez-vous
Count appointments: Nombre de rendez-vous
Count appointments by various parameters.: Compte le nombre de rendez-vous en fonction de différents paramètres.
Average appointment duration: Moyenne de la durée des rendez-vous
Get the average of appointment duration according to various filters: Calcule la moyenne des durées des rendez-vous en fonction de différents paramètres.
Sum of appointment durations: Somme de la durée des rendez-vous
Get the sum of appointment durations according to various filters: Calcule la somme des durées des rendez-vous en fonction de différents paramètres.
'Filtered by agent: only %agents%': "Filtré par agents: uniquement %agents%"
Filter by agent: Filtrer par agents
Filter by agent job: Filtrer par métiers des agents
'Filtered by agent job: only %jobs%': 'Filtré par métiers des agents: uniquement les %jobs%'
Filter by agent scope: Filtrer par services des agents
'Filtered by agent scope: only %scopes%': 'Filtré par services des agents: uniquement les services %scopes%'
Filter by appointments between certain dates: Filtrer par date du rendez-vous
'Filtered by appointments between %dateFrom% and %dateTo%': 'Filtré par rendez-vous entre %dateFrom% et %dateTo%'
Group by agent: Grouper par agent
Group by agent job: Grouper par métier de l'agent
Group by agent scope: Grouper par service de l'agent
Group by location type: Grouper par type de localisation
Group by location: Grouper par lieu de rendez-vous
Group by cancel reason: Grouper par motif d'annulation
Group by month and year: Grouper par mois et année
Scope: Service
Job: Métier
Location type: Type de localisation
Location: Lieu de rendez-vous
by month and year: Par mois et année

View File

@@ -188,7 +188,7 @@ class CustomFieldChoice extends AbstractCustomField
$choices = [];
foreach ($cf->getOptions()[self::CHOICES] as $choice) {
if (false === $choices['active']) {
if (false === $choice['active']) {
continue;
}
$choices[$choice['slug']] = $this->translatableStringHelper

View File

@@ -86,6 +86,9 @@ class ExportController extends AbstractController
{
/** @var \Chill\MainBundle\Export\ExportManager $exportManager */
$exportManager = $this->exportManager;
$export = $exportManager->getExport($alias);
$key = $request->query->get('key', null);
[$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key);
@@ -100,7 +103,8 @@ class ExportController extends AbstractController
$viewVariables = [
'alias' => $alias,
'export' => $exportManager->getExport($alias),
'export' => $export,
'export_group' => $this->getExportGroup($export),
];
if ($formater instanceof \Chill\MainBundle\Export\Formatter\CSVListFormatter) {
@@ -316,6 +320,7 @@ class ExportController extends AbstractController
'form' => $form->createView(),
'export_alias' => $alias,
'export' => $export,
'export_group' => $this->getExportGroup($export),
]);
}
@@ -371,6 +376,7 @@ class ExportController extends AbstractController
[
'form' => $form->createView(),
'export' => $export,
'export_group' => $this->getExportGroup($export),
]
);
}
@@ -514,6 +520,7 @@ class ExportController extends AbstractController
[
'form' => $form->createView(),
'export' => $export,
'export_group' => $this->getExportGroup($export),
]
);
}
@@ -565,4 +572,19 @@ class ExportController extends AbstractController
throw new LogicException("the step {$step} is not defined.");
}
}
private function getExportGroup($target): string
{
$exportManager = $this->exportManager;
$groups = $exportManager->getExportsGrouped(true);
foreach ($groups as $group => $array) {
foreach ($array as $alias => $export) {
if ($export === $target) {
return $group;
}
}
}
}
}

View File

@@ -22,6 +22,7 @@ use Chill\MainBundle\Controller\UserController;
use Chill\MainBundle\Controller\UserJobApiController;
use Chill\MainBundle\Controller\UserJobController;
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
use Chill\MainBundle\Doctrine\DQL\Extract;
use Chill\MainBundle\Doctrine\DQL\GetJsonFieldByKey;
use Chill\MainBundle\Doctrine\DQL\JsonAggregate;
use Chill\MainBundle\Doctrine\DQL\JsonbArrayLength;
@@ -31,6 +32,7 @@ use Chill\MainBundle\Doctrine\DQL\Replace;
use Chill\MainBundle\Doctrine\DQL\Similarity;
use Chill\MainBundle\Doctrine\DQL\STContains;
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
use Chill\MainBundle\Doctrine\DQL\ToChar;
use Chill\MainBundle\Doctrine\DQL\Unaccent;
use Chill\MainBundle\Doctrine\ORM\Hydration\FlatHierarchyEntityHydrator;
use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType;
@@ -241,6 +243,10 @@ class ChillMainExtension extends Extension implements
'ST_CONTAINS' => STContains::class,
'JSONB_ARRAY_LENGTH' => JsonbArrayLength::class,
],
'datetime_functions' => [
'EXTRACT' => Extract::class,
'TO_CHAR' => ToChar::class,
],
],
'hydrators' => [
'chill_flat_hierarchy_list' => FlatHierarchyEntityHydrator::class,

View File

@@ -0,0 +1,54 @@
<?php
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\DateDiffFunction;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\AST\PathExpression;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* Extract postgresql function
* https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
*
* Usage : EXTRACT(field FROM timestamp)
* TODO allow interval usage -> EXTRACT(field FROM interval)
*/
class Extract extends FunctionNode
{
private string $field;
private $value;
//private PathExpression $value;
//private FunctionNode $value;
//private DateDiffFunction $value;
public function getSql(SqlWalker $sqlWalker)
{
return sprintf(
'EXTRACT(%s FROM %s)',
$this->field,
$this->value->dispatch($sqlWalker)
);
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(Lexer::T_IDENTIFIER);
$this->field = $parser->getLexer()->token['value'];
$parser->match(Lexer::T_FROM);
//$this->value = $parser->ScalarExpression();
$this->value = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* Usage : TO_CHAR(datetime, fmt)
*/
class ToChar extends FunctionNode
{
private $datetime;
private $fmt;
public function getSql(SqlWalker $sqlWalker)
{
return sprintf(
'TO_CHAR(%s, %s)',
$sqlWalker->walkArithmeticPrimary($this->datetime),
$sqlWalker->walkArithmeticPrimary($this->fmt)
);
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->datetime = $parser->ArithmeticExpression();
$parser->match(Lexer::T_COMMA);
$this->fmt = $parser->StringExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,72 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="chill_main_geographical_unit")
* @ORM\Entity
*/
class GeographicalUnit
{
/**
* @ORM\Column(type="text", nullable=true)
*/
private $geom;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id = null;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $layerName;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $unitName;
public function getId(): ?int
{
return $this->id;
}
public function getLayerName(): ?string
{
return $this->layerName;
}
public function getUnitName(): ?string
{
return $this->unitName;
}
public function setLayerName(?string $layerName): self
{
$this->layerName = $layerName;
return $this;
}
public function setUnitName(?string $unitName): self
{
$this->unitName = $unitName;
return $this;
}
}

View File

@@ -568,6 +568,10 @@ class ExportManager
'role' => $role->getRole(),
]);
///// Bypasse les autorisations qui empêche d'afficher les nouveaux exports
return true;
///// TODO supprimer le return true
return false;
}
}

View File

@@ -449,7 +449,9 @@ class SpreadSheetFormatter implements FormatterInterface
protected function getTitle()
{
return $this->translator->trans($this->export->getTitle());
$title = $this->translator->trans($this->export->getTitle());
return substr($title, 0, 30) . '…';
}
protected function initializeCache($key)

View File

@@ -59,7 +59,7 @@ class CommentType extends AbstractType
$view->vars = array_replace(
$view->vars,
[
'hideLabel' => true,
'fullWidth' => true,
]
);
}

View File

@@ -46,7 +46,7 @@ class PrivateCommentType extends AbstractType
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['hideLabel'] = true;
$view->vars['fullWidth'] = true;
}
public function configureOptions(OptionsResolver $resolver)

View File

@@ -108,7 +108,7 @@ class ScopePickerType extends AbstractType
$view->vars = array_replace(
$view->vars,
[
'hideLabel' => true,
'fullWidth' => true,
]
);
}

View File

@@ -14,6 +14,7 @@ namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\Country;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ObjectRepository;
final class CountryRepository implements ObjectRepository
@@ -25,6 +26,11 @@ final class CountryRepository implements ObjectRepository
$this->repository = $entityManager->getRepository(Country::class);
}
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
{
return $this->repository->createQueryBuilder($alias, $indexBy);
}
public function find($id, $lockMode = null, $lockVersion = null): ?Country
{
return $this->repository->find($id, $lockMode, $lockVersion);

View File

@@ -46,7 +46,6 @@ require('../lib/collection/index.js');
require('../lib/breadcrumb/index.js');
require('../lib/download-report/index.js');
require('../lib/select_interactive_loading/index.js');
require('../lib/export-list/index.js');
//require('../lib/show_hide/index.js');
//require('../lib/tabs/index.js');

View File

@@ -99,11 +99,14 @@ div.flex-table {
div.item-bloc {
flex-direction: column;
&:nth-child(even) {
background-color: $gray-200;
&:not(.no-altern) { // class to avoid even/odd
.chill-user-quote {
background-color: shade-color($gray-200, 5%)
&:nth-child(even) {
background-color: $gray-200;
.chill-user-quote {
background-color: shade-color($gray-200, 5%)
}
}
}

View File

@@ -1,20 +0,0 @@
.container-export {
margin-left: 1rem;
margin-right: 1rem;
.export-list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
.export-list__element {
min-width: 18rem;
max-width: 20rem;
padding: 1rem;
margin: 1rem;
flex-grow: 1;
border: 1px solid var(--chill-gray);
}
}
}

View File

@@ -1 +0,0 @@
require('./export-list.scss');

View File

@@ -1,14 +1,23 @@
// Configuration
/*
* This shared file is used in Chill sass sheets and Vue sass styles to use some bootstrap/chill variables.
* Search on @import 'ChillMainAssets/module/bootstrap/shared';
*/
// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "bootstrap/scss/functions";
/*
* Replaced by CHILL variables
* it is necessary to keep the possibility of making a diff with original !
* original: "bootstrap/scss/variables";
*/
// 2. Include any default variable overrides here
@import "custom/_variables";
// 3. Include remainder of required Bootstrap stylesheets
@import "bootstrap/scss/variables";
// 4. Include any default map overrides here
@import "custom/_maps";
// 5. Include remainder of required parts
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/root";

View File

@@ -1,18 +1,8 @@
/*!
* Bootstrap v5.0.1 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*
* Enable / disable bootstrap assets
*/
// Bootstrap configuration files are shared with chill entrypoint
// Some Bootstrap variables and configuration files are shared with chill entrypoint
@import "shared";
// scss-docs-start import-stack
// Layout & components
@import "bootstrap/scss/root";
// 6. Optionally include any other parts as needed
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/images";
@@ -42,14 +32,11 @@
@import "bootstrap/scss/carousel";
@import "bootstrap/scss/spinners";
@import "bootstrap/scss/offcanvas";
// Helpers
@import "bootstrap/scss/helpers";
// Utilities
// 7. Optionally include utilities API last to generate classes based on the Sass map in
@import "bootstrap/scss/utilities/api";
// scss-docs-end import-stack
// CHILL custom
// 8. Add additional custom code here
@import "custom";
@import "custom/_debug";

View File

@@ -0,0 +1,69 @@
//// CHILL OVERRIDE DEFAULT BOOTSTRAP COLORS MAP
// 'beige' variations
$beige-100: tint-color($beige, 80%);
$beige-200: tint-color($beige, 60%);
$beige-300: tint-color($beige, 40%);
$beige-400: tint-color($beige, 20%);
$beige-500: $beige;
$beige-600: shade-color($beige, 20%);
$beige-700: shade-color($beige, 40%);
$beige-800: shade-color($beige, 60%);
$beige-900: shade-color($beige, 80%);
$chill-blue: $blue;
$chill-green: $green;
$chill-green-dark: $green-600;
$chill-orange: $orange;
$chill-yellow: $yellow;
$chill-red: $red;
$chill-beige: $beige;
$chill-pink: $pink;
$chill-dark-gray: $gray-800;
$chill-gray: $gray-600;
$chill-l-gray: $gray-400;
$chill-ll-gray: $gray-300;
$chill-light-gray: $gray-200;
$chill-llight-gray: $gray-100;
$colors: (
"blue": $blue,
"green": $green,
"green-dark": $green-600,
"yellow": $yellow,
"orange": $orange,
"red": $red,
"pink": $pink,
"beige": $beige,
"white": $white,
"gray": $gray-600,
"dark": $gray-800,
"black": $black
);
$chill-colors: (
"chill-blue": $chill-blue,
"chill-green": $chill-green,
"chill-green-dark": $chill-green-dark,
"chill-orange": $chill-orange,
"chill-yellow": $chill-yellow,
"chill-red": $chill-red,
"chill-beige": $chill-beige,
"chill-pink": $chill-pink,
"chill-dark-gray": $chill-dark-gray,
"chill-gray": $chill-gray,
"chill-l-gray": $chill-l-gray,
"chill-ll-gray": $chill-ll-gray,
"chill-light-gray": $chill-light-gray,
"chill-llight-gray": $chill-llight-gray,
);
// Merge the maps
$theme-colors: map-merge($theme-colors, $chill-colors);
// Chill color classes
@each $color, $value in $chill-colors {
.#{$color} {
color: $value;
}
}

View File

@@ -1,190 +0,0 @@
/*
* NOTE 2021.04
* scss/chill.scss is the main sass file for the new chill.2
* scratch will be replaced by bootstrap, please avoid to edit in modules/scratch/_custom.scss
*/
// YOUR CUSTOM SCSS
@import 'custom/config/colors';
@import 'custom/config/variables';
@import 'custom/fonts';
@import 'custom/timeline';
@import 'custom/mixins/entity';
@import 'custom/report';
@import 'custom/person';
@import 'custom/pagination';
@import 'custom/custom-fields';
@import 'custom/address';
@import 'custom/record_actions';
@import 'custom/flash_messages';
@import 'custom/box';
html,body {
min-height:100%;
font-family: 'Open Sans';
}
header {
position: relative;
}
#content_conainter {
position: relative;
min-height: calc(100% - 145px);
}
#content_conainter:before {
bottom: 0;
content: "";
left: 0;
opacity: 0.1;
position: absolute;
right: 0;
top: 0;
z-index: -1;
//background-image: url('./../../img/background/desert.jpg');
background-attachment: fixed;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
/* CUSTOM FIELDS -> */
.cf-title {
font-size: 2em;
}
.cf-subtitle {
font-size: 1.5em;
}
/* <- CUSTOM FIELDS */
@each $len in 11, 15 {
ul.submenu.width-#{$len}-em {
min-width: #{$len}em;
}
}
.content {
padding-top: 1em;
padding-bottom: 1em;
}
.select2 {
width: 100%;
}
ul.custom_fields.choice li {
list-style:none;
}
.errors {
color: $red;
}
.footer {
p {
font-family: 'Open Sans';
font-weight: 300;
}
a {
color: white;
text-decoration: underline;
}
}
// inline time input
.time_compound {
input[type=text], select {
width: 4em;
display: inline-block;
text-align: center;
}
.separator {
margin-left: 0.2em;
margin-right: 0.2em;
}
}
.open_sansbold {
font-family: 'Open Sans';
font-weight: bold;
}
dd {
margin-left: 0;
}
dt {
font-family: 'Open Sans';
font-weight: 600;
}
/* INPUT CLASS -> */
div.input_with_post_text {
display: flex;
align-items: center;
}
div.input_with_post_text span.post_text {
flex: 1;
margin-left: 0.5em;
}
div.input_with_post_text input {
width: 70%;
display: inline-block;
flex: 2;
}
/* <- INPUT CLASS */
dl.chill_report_view_data,
dl.chill_view_data {
dt {
margin-top: 1.5em;
color: $chill-blue;
}
dd {
padding-left: 1.5em;
margin-top: 0.2em;
ul {
padding-left: 0;
}
}
}
blockquote.chill-user-quote,
div.chill-user-quote {
border-left: 10px solid $chill-yellow;
margin: 1.5em 10px;
padding: 0.5em 10px;
quotes: "\201C""\201D""\2018""\2019";
background-color: $chill-llight-gray;
blockquote {
margin: 1.5em 10px;
padding: 0.5em 10px;
}
blockquote:before {
color: #ccc;
content: open-quote;
font-size: 4em;
line-height: 0.1em;
margin-right: 0.25em;
vertical-align: -0.4em;
}
}
.chill-no-data-statement {
font-style: italic;
}

View File

@@ -1,7 +0,0 @@
// Buttons
$button-font-size : 15px !default;
$button-text-color : #000 !default;
$button-text-weight : 300 !default;
$button-padding : 8px 12px !default;
$button-background : #eee !default;
$button-margin : 5px !default;

View File

@@ -1,64 +0,0 @@
// BODY
$body-background : #fff !default;
// PLAIN TEXT
$text-color : #555 !default;
// HEADINGS
$headings-color : #404040 !default;
// LINKS
$link-color : #6998C9 !default;
$link-visited-color : #808080 !default;
$link-active-color : shade(red,5%) !default;
$link-hover-color : #007ED5 !default;
$link-focus-color : $link-color !default;
$white : #fff !default;
$black : #000 !default;
$orange : #FF622C !default;
$red : #C83D3D !default;
$green : #27806f !default;
$blue : #2980b9 !default;
$yellow : #FFC82C !default;
$light-blue : #4995C7;
$llight-blue : #72B0D9;
$dark-blue : #096EB0 !default;
$ddark-blue : #07507F !default;
$light-green : #419484 !default;
$llight-green : #6CB3A5 !default;
$warning-bg : $orange !default;
$caution-bg : $red !default;
$error-bg : $red !default;
$success-bg : $green !default;
$info-bg : $blue !default;
$grey-95 : lighten($black, 5%) !default;
$grey-90 : lighten($black, 10%) !default;
$grey-85 : lighten($black, 15%) !default;
$grey-80 : lighten($black, 20%) !default;
$grey-75 : lighten($black, 25%) !default;
$grey-70 : lighten($black, 30%) !default;
$grey-65 : lighten($black, 35%) !default;
$grey-60 : lighten($black, 40%) !default;
$grey-55 : lighten($black, 45%) !default;
$grey-50 : lighten($black, 50%) !default;
$grey-45 : lighten($black, 55%) !default;
$grey-40 : lighten($black, 60%) !default;
$grey-35 : lighten($black, 65%) !default;
$grey-30 : lighten($black, 70%) !default;
$grey-25 : lighten($black, 75%) !default;
$grey-20 : lighten($black, 80%) !default;
$grey-15 : lighten($black, 85%) !default;
$grey-10 : lighten($black, 90%) !default;
$grey-5 : lighten($black, 95%) !default;
$dark-grey: $grey-80; //#333;
$medium-grey: $grey-50; //#999;
$light-grey: $grey-20; //#DDD;
@import "../custom/config/colors";

View File

@@ -1,115 +0,0 @@
// Typography
//$sans-serif: $helvetica;
//$serif: $georgia;
//$base-font-family: $sans-serif;
//$header-font-family: $base-font-family;
// Font Sizes
$base-font-size: 1em;
$h1-font-size: $base-font-size * 2.25;
$h2-font-size: $base-font-size * 2;
$h3-font-size: $base-font-size * 1.75;
$h4-font-size: $base-font-size * 1.5;
$h5-font-size: $base-font-size * 1.25;
$h6-font-size: $base-font-size;
// Line height
$base-line-height: 1.5;
$header-line-height: 1.25;
// Other Sizes
$base-border-radius: 3px;
$base-spacing: $base-line-height * 1em;
$base-z-index: 0;
// Background Color
$base-background-color: white;
// Font Colors
$base-font-color: $dark-grey;
$base-accent-color: $blue;
// Link Colors
$base-link-color: $base-accent-color;
$hover-link-color: darken($base-accent-color, 15);
$base-button-color: $base-link-color;
$hover-button-color: $hover-link-color;
/*
// Flash Colors
$alert-color: $light-yellow;
$error-color: $light-red;
$notice-color: lighten($base-accent-color, 40);
$success-color: $light-green;
*/
// Border color
$base-border-color: $light-grey;
$base-border: 1px solid $base-border-color;
// Footer
$footer-background: $grey-50;//-blue;// desaturate(darken($base-accent-color, 20), 30);
$footer-color: white;
$footer-link-color: transparentize($footer-color, .6);
$footer-disclaimer-color: transparentize($footer-color, .6);
$footer-vertical-padding: 0;
// Forms
$form-border-size: 1px;
$form-border-color: $base-border-color;
$form-border-color-hover: darken($base-border-color, 10);
$form-border-color-focus: $base-accent-color;
$form-border-radius: $base-border-radius;
$form-box-shadow: inset 0 1px 3px rgba(black,0.06);
$form-box-shadow-focus: $form-box-shadow, 0 0 5px rgba(darken($form-border-color-focus, 5), 0.7);
$form-font-size: $base-font-size;
//$form-font-family: $base-font-family;
// Navigation
$navigation-background: $dark-grey;
$navigation-color: transparentize(white, 0.3);
$navigation-color-hover: white;
$navigation-height: 60px;
$navigation-active-link-color: transparentize(white, 0.5);
$navigation-submenu-padding: 1em;
$navigation-submenu-width: 12em;
$navigation-border-radius: $base-border-radius;
$navigation-first-padding-top: 1em;
$navigation-last-padding-bottom: 0.7em;
$navigation-more-pin: '\25BE';
$navigation-more-pin-color: $navigation-color;
$navigation-ul-submenu-top: 1.5em;
$navigation-ul-submenu-padding-left: 0;
$navigation-search-padding: .85em .6em;
$navigation-border-bottom: 1px solid darken($navigation-background, 10);
//Table
$table-width: 100%;
$table-head-bg-color: $orange;
$table-head-td-border: unset;
$table-head-td-text-align: center;
$table-head-td-padding: 0.3em;
$table-head-text-color: $white;
$table-body-tr-bg-color-even: $grey-5;
$table-body-tr-bg-color-odd: unset;
$table-body-td-border: unset;
$table-body-td-text-align: left;
$table-body-td-padding: 0.3em;
$table-body-text-color: unset;
//Tabs
$tabs-nav-margin-bottom: none;
$tabs-nav-title-bg-color: $blue;
$tabs-nav-title-text-color: $white;
$tabs-nav-title-padding: 0.5em 0.5em 0.5em 1em;
$tabs-nav-bg-color: none;
$tabs-nav-text-color: inherit;
$tabs-new-border: 3px solid transparent;
$tabs-nav-hover-border: 3px solid $orange;
$tabs-nav-hover-text-color: inherit;
$tabs-nav-font-family: unset;
$tabs-nav-padding: 0.5em 0.5em 0.5em 1.5em;
@import "../custom/config/variables";

View File

@@ -1,411 +0,0 @@
// The following features have been deprecated and will be removed in the next MAJOR version release
@mixin inline-block {
display: inline-block;
@warn "The inline-block mixin is deprecated and will be removed in the next major version release";
}
@mixin button ($style: simple, $base-color: #4294f0, $text-size: inherit, $padding: 7px 18px) {
@if type-of($style) == string and type-of($base-color) == color {
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == string and type-of($base-color) == number {
$padding: $text-size;
$text-size: $base-color;
$base-color: #4294f0;
@if $padding == inherit {
$padding: 7px 18px;
}
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == color and type-of($base-color) == color {
$base-color: $style;
$style: simple;
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == color and type-of($base-color) == number {
$padding: $text-size;
$text-size: $base-color;
$base-color: $style;
$style: simple;
@if $padding == inherit {
$padding: 7px 18px;
}
@include buttonstyle($style, $base-color, $text-size, $padding);
}
@if type-of($style) == number {
$padding: $base-color;
$text-size: $style;
$base-color: #4294f0;
$style: simple;
@if $padding == #4294f0 {
$padding: 7px 18px;
}
@include buttonstyle($style, $base-color, $text-size, $padding);
}
&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
@warn "The button mixin is deprecated and will be removed in the next major version release";
}
// Selector Style Button
@mixin buttonstyle($type, $b-color, $t-size, $pad) {
// Grayscale button
@if $type == simple and $b-color == grayscale($b-color) {
@include simple($b-color, true, $t-size, $pad);
}
@if $type == shiny and $b-color == grayscale($b-color) {
@include shiny($b-color, true, $t-size, $pad);
}
@if $type == pill and $b-color == grayscale($b-color) {
@include pill($b-color, true, $t-size, $pad);
}
@if $type == flat and $b-color == grayscale($b-color) {
@include flat($b-color, true, $t-size, $pad);
}
// Colored button
@if $type == simple {
@include simple($b-color, false, $t-size, $pad);
}
@else if $type == shiny {
@include shiny($b-color, false, $t-size, $pad);
}
@else if $type == pill {
@include pill($b-color, false, $t-size, $pad);
}
@else if $type == flat {
@include flat($b-color, false, $t-size, $pad);
}
}
// Simple Button
@mixin simple($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow: adjust-color($base-color, $saturation: -8%, $lightness: 15%);
$stop-gradient: adjust-color($base-color, $saturation: 9%, $lightness: -11%);
$text-shadow: adjust-color($base-color, $saturation: 15%, $lightness: -18%);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border: grayscale($border);
$inset-shadow: grayscale($inset-shadow);
$stop-gradient: grayscale($stop-gradient);
$text-shadow: grayscale($text-shadow);
}
border: 1px solid $border;
border-radius: 3px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: bold;
@include linear-gradient ($base-color, $stop-gradient);
padding: $padding;
text-decoration: none;
text-shadow: 0 1px 0 $text-shadow;
background-clip: padding-box;
&:hover:not(:disabled) {
$base-color-hover: adjust-color($base-color, $saturation: -4%, $lightness: -5%);
$inset-shadow-hover: adjust-color($base-color, $saturation: -7%, $lightness: 5%);
$stop-gradient-hover: adjust-color($base-color, $saturation: 8%, $lightness: -14%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
$inset-shadow-hover: grayscale($inset-shadow-hover);
$stop-gradient-hover: grayscale($stop-gradient-hover);
}
@include linear-gradient ($base-color-hover, $stop-gradient-hover);
box-shadow: inset 0 1px 0 0 $inset-shadow-hover;
cursor: pointer;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$border-active: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow-active: adjust-color($base-color, $saturation: 7%, $lightness: -17%);
@if $grayscale == true {
$border-active: grayscale($border-active);
$inset-shadow-active: grayscale($inset-shadow-active);
}
border: 1px solid $border-active;
box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active;
}
}
// Shiny Button
@mixin shiny($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $red: -117, $green: -111, $blue: -81);
$border-bottom: adjust-color($base-color, $red: -126, $green: -127, $blue: -122);
$fourth-stop: adjust-color($base-color, $red: -79, $green: -70, $blue: -46);
$inset-shadow: adjust-color($base-color, $red: 37, $green: 29, $blue: 12);
$second-stop: adjust-color($base-color, $red: -56, $green: -50, $blue: -33);
$text-shadow: adjust-color($base-color, $red: -140, $green: -141, $blue: -114);
$third-stop: adjust-color($base-color, $red: -86, $green: -75, $blue: -48);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border: grayscale($border);
$border-bottom: grayscale($border-bottom);
$fourth-stop: grayscale($fourth-stop);
$inset-shadow: grayscale($inset-shadow);
$second-stop: grayscale($second-stop);
$text-shadow: grayscale($text-shadow);
$third-stop: grayscale($third-stop);
}
@include linear-gradient(top, $base-color 0%, $second-stop 50%, $third-stop 50%, $fourth-stop 100%);
border: 1px solid $border;
border-bottom: 1px solid $border-bottom;
border-radius: 5px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: bold;
padding: $padding;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
&:hover:not(:disabled) {
$first-stop-hover: adjust-color($base-color, $red: -13, $green: -15, $blue: -18);
$second-stop-hover: adjust-color($base-color, $red: -66, $green: -62, $blue: -51);
$third-stop-hover: adjust-color($base-color, $red: -93, $green: -85, $blue: -66);
$fourth-stop-hover: adjust-color($base-color, $red: -86, $green: -80, $blue: -63);
@if $grayscale == true {
$first-stop-hover: grayscale($first-stop-hover);
$second-stop-hover: grayscale($second-stop-hover);
$third-stop-hover: grayscale($third-stop-hover);
$fourth-stop-hover: grayscale($fourth-stop-hover);
}
@include linear-gradient(top, $first-stop-hover 0%,
$second-stop-hover 50%,
$third-stop-hover 50%,
$fourth-stop-hover 100%);
cursor: pointer;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$inset-shadow-active: adjust-color($base-color, $red: -111, $green: -116, $blue: -122);
@if $grayscale == true {
$inset-shadow-active: grayscale($inset-shadow-active);
}
box-shadow: inset 0 0 20px 0 $inset-shadow-active;
}
}
// Pill Button
@mixin pill($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
$border-bottom: adjust-color($base-color, $hue: 8, $saturation: -11%, $lightness: -26%);
$border-sides: adjust-color($base-color, $hue: 4, $saturation: -21%, $lightness: -21%);
$border-top: adjust-color($base-color, $hue: -1, $saturation: -30%, $lightness: -15%);
$inset-shadow: adjust-color($base-color, $hue: -1, $saturation: -1%, $lightness: 7%);
$stop-gradient: adjust-color($base-color, $hue: 8, $saturation: 14%, $lightness: -10%);
$text-shadow: adjust-color($base-color, $hue: 5, $saturation: -19%, $lightness: -15%);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border-bottom: grayscale($border-bottom);
$border-sides: grayscale($border-sides);
$border-top: grayscale($border-top);
$inset-shadow: grayscale($inset-shadow);
$stop-gradient: grayscale($stop-gradient);
$text-shadow: grayscale($text-shadow);
}
border: 1px solid $border-top;
border-color: $border-top $border-sides $border-bottom;
border-radius: 16px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: normal;
line-height: 1;
@include linear-gradient ($base-color, $stop-gradient);
padding: $padding;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
background-clip: padding-box;
&:hover:not(:disabled) {
$base-color-hover: adjust-color($base-color, $lightness: -4.5%);
$border-bottom: adjust-color($base-color, $hue: 8, $saturation: 13.5%, $lightness: -32%);
$border-sides: adjust-color($base-color, $hue: 4, $saturation: -2%, $lightness: -27%);
$border-top: adjust-color($base-color, $hue: -1, $saturation: -17%, $lightness: -21%);
$inset-shadow-hover: adjust-color($base-color, $saturation: -1%, $lightness: 3%);
$stop-gradient-hover: adjust-color($base-color, $hue: 8, $saturation: -4%, $lightness: -15.5%);
$text-shadow-hover: adjust-color($base-color, $hue: 5, $saturation: -5%, $lightness: -22%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
$border-bottom: grayscale($border-bottom);
$border-sides: grayscale($border-sides);
$border-top: grayscale($border-top);
$inset-shadow-hover: grayscale($inset-shadow-hover);
$stop-gradient-hover: grayscale($stop-gradient-hover);
$text-shadow-hover: grayscale($text-shadow-hover);
}
@include linear-gradient ($base-color-hover, $stop-gradient-hover);
background-clip: padding-box;
border: 1px solid $border-top;
border-color: $border-top $border-sides $border-bottom;
box-shadow: inset 0 1px 0 0 $inset-shadow-hover;
cursor: pointer;
text-shadow: 0 -1px 1px $text-shadow-hover;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$active-color: adjust-color($base-color, $hue: 4, $saturation: -12%, $lightness: -10%);
$border-active: adjust-color($base-color, $hue: 6, $saturation: -2.5%, $lightness: -30%);
$border-bottom-active: adjust-color($base-color, $hue: 11, $saturation: 6%, $lightness: -31%);
$inset-shadow-active: adjust-color($base-color, $hue: 9, $saturation: 2%, $lightness: -21.5%);
$text-shadow-active: adjust-color($base-color, $hue: 5, $saturation: -12%, $lightness: -21.5%);
@if $grayscale == true {
$active-color: grayscale($active-color);
$border-active: grayscale($border-active);
$border-bottom-active: grayscale($border-bottom-active);
$inset-shadow-active: grayscale($inset-shadow-active);
$text-shadow-active: grayscale($text-shadow-active);
}
background: $active-color;
border: 1px solid $border-active;
border-bottom: 1px solid $border-bottom-active;
box-shadow: inset 0 0 6px 3px $inset-shadow-active;
text-shadow: 0 -1px 1px $text-shadow-active;
}
}
// Flat Button
@mixin flat($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) {
$color: hsl(0, 0, 100%);
@if is-light($base-color) {
$color: hsl(0, 0, 20%);
}
background-color: $base-color;
border-radius: 3px;
border: 0;
color: $color;
display: inline-block;
font-size: $textsize;
font-weight: bold;
padding: $padding;
text-decoration: none;
background-clip: padding-box;
&:hover:not(:disabled){
$base-color-hover: adjust-color($base-color, $saturation: 4%, $lightness: 5%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
}
background-color: $base-color-hover;
cursor: pointer;
}
&:active:not(:disabled),
&:focus:not(:disabled) {
$base-color-active: adjust-color($base-color, $saturation: -4%, $lightness: -5%);
@if $grayscale == true {
$base-color-active: grayscale($base-color-active);
}
background-color: $base-color-active;
cursor: pointer;
}
}
// Flexible grid
@function flex-grid($columns, $container-columns: $fg-max-columns) {
$width: $columns * $fg-column + ($columns - 1) * $fg-gutter;
$container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
@return percentage($width / $container-width);
@warn "The flex-grid function is deprecated and will be removed in the next major version release";
}
// Flexible gutter
@function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) {
$container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
@return percentage($gutter / $container-width);
@warn "The flex-gutter function is deprecated and will be removed in the next major version release";
}
@function grid-width($n) {
@return $n * $gw-column + ($n - 1) * $gw-gutter;
@warn "The grid-width function is deprecated and will be removed in the next major version release";
}
@function golden-ratio($value, $increment) {
@return modular-scale($increment, $value, $ratio: $golden);
@warn "The golden-ratio function is deprecated and will be removed in the next major version release. Please use the modular-scale function, instead.";
}
@mixin box-sizing($box) {
@include prefixer(box-sizing, $box, webkit moz spec);
@warn "The box-sizing mixin is deprecated and will be removed in the next major version release. This property can now be used un-prefixed.";
}

View File

@@ -1,87 +0,0 @@
// Bourbon 4.2.6
// http://bourbon.io
// Copyright 2011-2015 thoughtbot, inc.
// MIT License
@import "settings/prefixer";
@import "settings/px-to-em";
@import "settings/asset-pipeline";
@import "functions/assign-inputs";
@import "functions/contains";
@import "functions/contains-falsy";
@import "functions/is-length";
@import "functions/is-light";
@import "functions/is-number";
@import "functions/is-size";
@import "functions/px-to-em";
@import "functions/px-to-rem";
@import "functions/shade";
@import "functions/strip-units";
@import "functions/tint";
@import "functions/transition-property-name";
@import "functions/unpack";
@import "functions/modular-scale";
@import "helpers/convert-units";
@import "helpers/directional-values";
@import "helpers/font-source-declaration";
@import "helpers/gradient-positions-parser";
@import "helpers/linear-angle-parser";
@import "helpers/linear-gradient-parser";
@import "helpers/linear-positions-parser";
@import "helpers/linear-side-corner-parser";
@import "helpers/radial-arg-parser";
@import "helpers/radial-positions-parser";
@import "helpers/radial-gradient-parser";
@import "helpers/render-gradients";
@import "helpers/shape-size-stripper";
@import "helpers/str-to-num";
@import "css3/animation";
@import "css3/appearance";
@import "css3/backface-visibility";
@import "css3/background";
@import "css3/background-image";
@import "css3/border-image";
@import "css3/calc";
@import "css3/columns";
@import "css3/filter";
@import "css3/flex-box";
@import "css3/font-face";
@import "css3/font-feature-settings";
@import "css3/hidpi-media-query";
@import "css3/hyphens";
@import "css3/image-rendering";
@import "css3/keyframes";
@import "css3/linear-gradient";
@import "css3/perspective";
@import "css3/placeholder";
@import "css3/radial-gradient";
@import "css3/selection";
@import "css3/text-decoration";
@import "css3/transform";
@import "css3/transition";
@import "css3/user-select";
@import "addons/border-color";
@import "addons/border-radius";
@import "addons/border-style";
@import "addons/border-width";
@import "addons/buttons";
@import "addons/clearfix";
@import "addons/ellipsis";
@import "addons/font-stacks";
@import "addons/hide-text";
@import "addons/margin";
@import "addons/padding";
@import "addons/position";
@import "addons/prefixer";
@import "addons/retina-image";
@import "addons/size";
@import "addons/text-inputs";
@import "addons/timing-functions";
@import "addons/triangle";
@import "addons/word-wrap";
@import "bourbon-deprecated-upcoming";

View File

@@ -1,26 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-color` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include border-color(#a60b55 #76cd9c null #e8ae1a);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-left-color: #e8ae1a;
/// border-right-color: #76cd9c;
/// border-top-color: #a60b55;
/// }
///
/// @require {mixin} directional-property
///
/// @output `border-color`
@mixin border-color($vals...) {
@include directional-property(border, color, $vals...);
}

View File

@@ -1,48 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-radius` on both corners on the side of a box.
///
/// @param {Number} $radii
/// List of arguments
///
/// @example scss - Usage
/// .element-one {
/// @include border-top-radius(5px);
/// }
///
/// .element-two {
/// @include border-left-radius(3px);
/// }
///
/// @example css - CSS Output
/// .element-one {
/// border-top-left-radius: 5px;
/// border-top-right-radius: 5px;
/// }
///
/// .element-two {
/// border-bottom-left-radius: 3px;
/// border-top-left-radius: 3px;
/// }
///
/// @output `border-radius`
@mixin border-top-radius($radii) {
border-top-left-radius: $radii;
border-top-right-radius: $radii;
}
@mixin border-right-radius($radii) {
border-bottom-right-radius: $radii;
border-top-right-radius: $radii;
}
@mixin border-bottom-radius($radii) {
border-bottom-left-radius: $radii;
border-bottom-right-radius: $radii;
}
@mixin border-left-radius($radii) {
border-bottom-left-radius: $radii;
border-top-left-radius: $radii;
}

View File

@@ -1,25 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-style` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include border-style(dashed null solid);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-bottom-style: solid;
/// border-top-style: dashed;
/// }
///
/// @require {mixin} directional-property
///
/// @output `border-style`
@mixin border-style($vals...) {
@include directional-property(border, style, $vals...);
}

View File

@@ -1,25 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `border-width` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include border-width(1em null 20px);
/// }
///
/// @example css - CSS Output
/// .element {
/// border-bottom-width: 20px;
/// border-top-width: 1em;
/// }
///
/// @require {mixin} directional-property
///
/// @output `border-width`
@mixin border-width($vals...) {
@include directional-property(border, width, $vals...);
}

View File

@@ -1,64 +0,0 @@
@charset "UTF-8";
/// Generates variables for all buttons. Please note that you must use interpolation on the variable: `#{$all-buttons}`.
///
/// @example scss - Usage
/// #{$all-buttons} {
/// background-color: #f00;
/// }
///
/// #{$all-buttons-focus},
/// #{$all-buttons-hover} {
/// background-color: #0f0;
/// }
///
/// #{$all-buttons-active} {
/// background-color: #00f;
/// }
///
/// @example css - CSS Output
/// button,
/// input[type="button"],
/// input[type="reset"],
/// input[type="submit"] {
/// background-color: #f00;
/// }
///
/// button:focus,
/// input[type="button"]:focus,
/// input[type="reset"]:focus,
/// input[type="submit"]:focus,
/// button:hover,
/// input[type="button"]:hover,
/// input[type="reset"]:hover,
/// input[type="submit"]:hover {
/// background-color: #0f0;
/// }
///
/// button:active,
/// input[type="button"]:active,
/// input[type="reset"]:active,
/// input[type="submit"]:active {
/// background-color: #00f;
/// }
///
/// @require assign-inputs
///
/// @type List
///
/// @todo Remove double assigned variables (Lines 5962) in v5.0.0
$buttons-list: 'button',
'input[type="button"]',
'input[type="reset"]',
'input[type="submit"]';
$all-buttons: assign-inputs($buttons-list);
$all-buttons-active: assign-inputs($buttons-list, active);
$all-buttons-focus: assign-inputs($buttons-list, focus);
$all-buttons-hover: assign-inputs($buttons-list, hover);
$all-button-inputs: $all-buttons;
$all-button-inputs-active: $all-buttons-active;
$all-button-inputs-focus: $all-buttons-focus;
$all-button-inputs-hover: $all-buttons-hover;

View File

@@ -1,25 +0,0 @@
@charset "UTF-8";
/// Provides an easy way to include a clearfix for containing floats.
///
/// @link http://cssmojo.com/latest_new_clearfix_so_far/
///
/// @example scss - Usage
/// .element {
/// @include clearfix;
/// }
///
/// @example css - CSS Output
/// .element::after {
/// clear: both;
/// content: "";
/// display: table;
/// }
@mixin clearfix {
&::after {
clear: both;
content: "";
display: table;
}
}

View File

@@ -1,30 +0,0 @@
@charset "UTF-8";
/// Truncates text and adds an ellipsis to represent overflow.
///
/// @param {Number} $width [100%]
/// Max-width for the string to respect before being truncated
///
/// @example scss - Usage
/// .element {
/// @include ellipsis;
/// }
///
/// @example css - CSS Output
/// .element {
/// display: inline-block;
/// max-width: 100%;
/// overflow: hidden;
/// text-overflow: ellipsis;
/// white-space: nowrap;
/// word-wrap: normal;
/// }
@mixin ellipsis($width: 100%) {
display: inline-block;
max-width: $width;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
}

View File

@@ -1,31 +0,0 @@
@charset "UTF-8";
/// Georgia font stack.
///
/// @type List
$georgia: "Georgia", "Cambria", "Times New Roman", "Times", serif;
/// Helvetica font stack.
///
/// @type List
$helvetica: "Helvetica Neue", "Helvetica", "Roboto", "Arial", sans-serif;
/// Lucida Grande font stack.
///
/// @type List
$lucida-grande: "Lucida Grande", "Tahoma", "Verdana", "Arial", sans-serif;
/// Monospace font stack.
///
/// @type List
$monospace: "Bitstream Vera Sans Mono", "Consolas", "Courier", monospace;
/// Verdana font stack.
///
/// @type List
$verdana: "Verdana", "Geneva", sans-serif;

View File

@@ -1,27 +0,0 @@
/// Hides the text in an element, commonly used to show an image. Some elements will need block-level styles applied.
///
/// @link http://zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement
///
/// @example scss - Usage
/// .element {
/// @include hide-text;
/// }
///
/// @example css - CSS Output
/// .element {
/// overflow: hidden;
/// text-indent: 101%;
/// white-space: nowrap;
/// }
///
/// @todo Remove height argument in v5.0.0
@mixin hide-text($height: null) {
overflow: hidden;
text-indent: 101%;
white-space: nowrap;
@if $height {
@warn "The `hide-text` mixin has changed and no longer requires a height. The height argument will no longer be accepted in v5.0.0";
}
}

View File

@@ -1,26 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `margin` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include margin(null 10px 3em 20vh);
/// }
///
/// @example css - CSS Output
/// .element {
/// margin-bottom: 3em;
/// margin-left: 20vh;
/// margin-right: 10px;
/// }
///
/// @require {mixin} directional-property
///
/// @output `margin`
@mixin margin($vals...) {
@include directional-property(margin, false, $vals...);
}

View File

@@ -1,26 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for targeting `padding` on specific sides of a box. Use a `null` value to “skip” a side.
///
/// @param {Arglist} $vals
/// List of arguments
///
/// @example scss - Usage
/// .element {
/// @include padding(12vh null 10px 5%);
/// }
///
/// @example css - CSS Output
/// .element {
/// padding-bottom: 10px;
/// padding-left: 5%;
/// padding-top: 12vh;
/// }
///
/// @require {mixin} directional-property
///
/// @output `padding`
@mixin padding($vals...) {
@include directional-property(padding, false, $vals...);
}

View File

@@ -1,48 +0,0 @@
@charset "UTF-8";
/// Provides a quick method for setting an elements position. Use a `null` value to “skip” a side.
///
/// @param {Position} $position [relative]
/// A CSS position value
///
/// @param {Arglist} $coordinates [null null null null]
/// List of values that correspond to the 4-value syntax for the edges of a box
///
/// @example scss - Usage
/// .element {
/// @include position(absolute, 0 null null 10em);
/// }
///
/// @example css - CSS Output
/// .element {
/// left: 10em;
/// position: absolute;
/// top: 0;
/// }
///
/// @require {function} is-length
/// @require {function} unpack
@mixin position($position: relative, $coordinates: null null null null) {
@if type-of($position) == list {
$coordinates: $position;
$position: relative;
}
$coordinates: unpack($coordinates);
$offsets: (
top: nth($coordinates, 1),
right: nth($coordinates, 2),
bottom: nth($coordinates, 3),
left: nth($coordinates, 4)
);
position: $position;
@each $offset, $value in $offsets {
@if is-length($value) {
#{$offset}: $value;
}
}
}

View File

@@ -1,66 +0,0 @@
@charset "UTF-8";
/// A mixin for generating vendor prefixes on non-standardized properties.
///
/// @param {String} $property
/// Property to prefix
///
/// @param {*} $value
/// Value to use
///
/// @param {List} $prefixes
/// Prefixes to define
///
/// @example scss - Usage
/// .element {
/// @include prefixer(border-radius, 10px, webkit ms spec);
/// }
///
/// @example css - CSS Output
/// .element {
/// -webkit-border-radius: 10px;
/// -moz-border-radius: 10px;
/// border-radius: 10px;
/// }
///
/// @require {variable} $prefix-for-webkit
/// @require {variable} $prefix-for-mozilla
/// @require {variable} $prefix-for-microsoft
/// @require {variable} $prefix-for-opera
/// @require {variable} $prefix-for-spec
@mixin prefixer($property, $value, $prefixes) {
@each $prefix in $prefixes {
@if $prefix == webkit {
@if $prefix-for-webkit {
-webkit-#{$property}: $value;
}
} @else if $prefix == moz {
@if $prefix-for-mozilla {
-moz-#{$property}: $value;
}
} @else if $prefix == ms {
@if $prefix-for-microsoft {
-ms-#{$property}: $value;
}
} @else if $prefix == o {
@if $prefix-for-opera {
-o-#{$property}: $value;
}
} @else if $prefix == spec {
@if $prefix-for-spec {
#{$property}: $value;
}
} @else {
@warn "Unrecognized prefix: #{$prefix}";
}
}
}
@mixin disable-prefix-for-all() {
$prefix-for-webkit: false !global;
$prefix-for-mozilla: false !global;
$prefix-for-microsoft: false !global;
$prefix-for-opera: false !global;
$prefix-for-spec: false !global;
}

View File

@@ -1,25 +0,0 @@
@mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $retina-suffix: _2x, $asset-pipeline: $asset-pipeline) {
@if $asset-pipeline {
background-image: image-url("#{$filename}.#{$extension}");
} @else {
background-image: url("#{$filename}.#{$extension}");
}
@include hidpi {
@if $asset-pipeline {
@if $retina-filename {
background-image: image-url("#{$retina-filename}.#{$extension}");
} @else {
background-image: image-url("#{$filename}#{$retina-suffix}.#{$extension}");
}
} @else {
@if $retina-filename {
background-image: url("#{$retina-filename}.#{$extension}");
} @else {
background-image: url("#{$filename}#{$retina-suffix}.#{$extension}");
}
}
background-size: $background-size;
}
}

View File

@@ -1,51 +0,0 @@
@charset "UTF-8";
/// Sets the `width` and `height` of the element.
///
/// @param {List} $size
/// A list of at most 2 size values.
///
/// If there is only a single value in `$size` it is used for both width and height. All units are supported.
///
/// @example scss - Usage
/// .first-element {
/// @include size(2em);
/// }
///
/// .second-element {
/// @include size(auto 10em);
/// }
///
/// @example css - CSS Output
/// .first-element {
/// width: 2em;
/// height: 2em;
/// }
///
/// .second-element {
/// width: auto;
/// height: 10em;
/// }
///
/// @todo Refactor in 5.0.0 to use a comma-separated argument
@mixin size($value) {
$width: nth($value, 1);
$height: $width;
@if length($value) > 1 {
$height: nth($value, 2);
}
@if is-size($height) {
height: $height;
} @else {
@warn "`#{$height}` is not a valid length for the `$height` parameter in the `size` mixin.";
}
@if is-size($width) {
width: $width;
} @else {
@warn "`#{$width}` is not a valid length for the `$width` parameter in the `size` mixin.";
}
}

View File

@@ -1,113 +0,0 @@
@charset "UTF-8";
/// Generates variables for all text-based inputs. Please note that you must use interpolation on the variable: `#{$all-text-inputs}`.
///
/// @example scss - Usage
/// #{$all-text-inputs} {
/// border: 1px solid #f00;
/// }
///
/// #{$all-text-inputs-focus},
/// #{$all-text-inputs-hover} {
/// border: 1px solid #0f0;
/// }
///
/// #{$all-text-inputs-active} {
/// border: 1px solid #00f;
/// }
///
/// @example css - CSS Output
/// input[type="color"],
/// input[type="date"],
/// input[type="datetime"],
/// input[type="datetime-local"],
/// input[type="email"],
/// input[type="month"],
/// input[type="number"],
/// input[type="password"],
/// input[type="search"],
/// input[type="tel"],
/// input[type="text"],
/// input[type="time"],
/// input[type="url"],
/// input[type="week"],
/// textarea {
/// border: 1px solid #f00;
/// }
///
/// input[type="color"]:focus,
/// input[type="date"]:focus,
/// input[type="datetime"]:focus,
/// input[type="datetime-local"]:focus,
/// input[type="email"]:focus,
/// input[type="month"]:focus,
/// input[type="number"]:focus,
/// input[type="password"]:focus,
/// input[type="search"]:focus,
/// input[type="tel"]:focus,
/// input[type="text"]:focus,
/// input[type="time"]:focus,
/// input[type="url"]:focus,
/// input[type="week"]:focus,
/// textarea:focus,
/// input[type="color"]:hover,
/// input[type="date"]:hover,
/// input[type="datetime"]:hover,
/// input[type="datetime-local"]:hover,
/// input[type="email"]:hover,
/// input[type="month"]:hover,
/// input[type="number"]:hover,
/// input[type="password"]:hover,
/// input[type="search"]:hover,
/// input[type="tel"]:hover,
/// input[type="text"]:hover,
/// input[type="time"]:hover,
/// input[type="url"]:hover,
/// input[type="week"]:hover,
/// textarea:hover {
/// border: 1px solid #0f0;
/// }
///
/// input[type="color"]:active,
/// input[type="date"]:active,
/// input[type="datetime"]:active,
/// input[type="datetime-local"]:active,
/// input[type="email"]:active,
/// input[type="month"]:active,
/// input[type="number"]:active,
/// input[type="password"]:active,
/// input[type="search"]:active,
/// input[type="tel"]:active,
/// input[type="text"]:active,
/// input[type="time"]:active,
/// input[type="url"]:active,
/// input[type="week"]:active,
/// textarea:active {
/// border: 1px solid #00f;
/// }
///
/// @require assign-inputs
///
/// @type List
$text-inputs-list: 'input[type="color"]',
'input[type="date"]',
'input[type="datetime"]',
'input[type="datetime-local"]',
'input[type="email"]',
'input[type="month"]',
'input[type="number"]',
'input[type="password"]',
'input[type="search"]',
'input[type="tel"]',
'input[type="text"]',
'input[type="time"]',
'input[type="url"]',
'input[type="week"]',
'input:not([type])',
'textarea';
$all-text-inputs: assign-inputs($text-inputs-list);
$all-text-inputs-active: assign-inputs($text-inputs-list, active);
$all-text-inputs-focus: assign-inputs($text-inputs-list, focus);
$all-text-inputs-hover: assign-inputs($text-inputs-list, hover);

View File

@@ -1,34 +0,0 @@
@charset "UTF-8";
/// CSS cubic-bezier timing functions. Timing functions courtesy of jquery.easie (github.com/jaukia/easie)
///
/// Timing functions are the same as demoed here: http://jqueryui.com/resources/demos/effect/easing.html
///
/// @type cubic-bezier
$ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530);
$ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190);
$ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220);
$ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060);
$ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715);
$ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035);
$ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335);
$ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045);
$ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940);
$ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000);
$ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000);
$ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000);
$ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000);
$ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000);
$ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000);
$ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275);
$ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955);
$ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000);
$ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000);
$ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000);
$ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950);
$ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000);
$ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860);
$ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550);

View File

@@ -1,63 +0,0 @@
@mixin triangle($size, $color, $direction) {
$width: nth($size, 1);
$height: nth($size, length($size));
$foreground-color: nth($color, 1);
$background-color: if(length($color) == 2, nth($color, 2), transparent);
height: 0;
width: 0;
@if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) {
$width: $width / 2;
$height: if(length($size) > 1, $height, $height/2);
@if $direction == up {
border-bottom: $height solid $foreground-color;
border-left: $width solid $background-color;
border-right: $width solid $background-color;
} @else if $direction == right {
border-bottom: $width solid $background-color;
border-left: $height solid $foreground-color;
border-top: $width solid $background-color;
} @else if $direction == down {
border-left: $width solid $background-color;
border-right: $width solid $background-color;
border-top: $height solid $foreground-color;
} @else if $direction == left {
border-bottom: $width solid $background-color;
border-right: $height solid $foreground-color;
border-top: $width solid $background-color;
}
} @else if ($direction == up-right) or ($direction == up-left) {
border-top: $height solid $foreground-color;
@if $direction == up-right {
border-left: $width solid $background-color;
} @else if $direction == up-left {
border-right: $width solid $background-color;
}
} @else if ($direction == down-right) or ($direction == down-left) {
border-bottom: $height solid $foreground-color;
@if $direction == down-right {
border-left: $width solid $background-color;
} @else if $direction == down-left {
border-right: $width solid $background-color;
}
} @else if ($direction == inset-up) {
border-color: $background-color $background-color $foreground-color;
border-style: solid;
border-width: $height $width;
} @else if ($direction == inset-down) {
border-color: $foreground-color $background-color $background-color;
border-style: solid;
border-width: $height $width;
} @else if ($direction == inset-right) {
border-color: $background-color $background-color $background-color $foreground-color;
border-style: solid;
border-width: $width $height;
} @else if ($direction == inset-left) {
border-color: $background-color $foreground-color $background-color $background-color;
border-style: solid;
border-width: $width $height;
}
}

View File

@@ -1,29 +0,0 @@
@charset "UTF-8";
/// Provides an easy way to change the `word-wrap` property.
///
/// @param {String} $wrap [break-word]
/// Value for the `word-break` property.
///
/// @example scss - Usage
/// .wrapper {
/// @include word-wrap(break-word);
/// }
///
/// @example css - CSS Output
/// .wrapper {
/// overflow-wrap: break-word;
/// word-break: break-all;
/// word-wrap: break-word;
/// }
@mixin word-wrap($wrap: break-word) {
overflow-wrap: $wrap;
word-wrap: $wrap;
@if $wrap == break-word {
word-break: break-all;
} @else {
word-break: $wrap;
}
}

View File

@@ -1,43 +0,0 @@
// http://www.w3.org/TR/css3-animations/#the-animation-name-property-
// Each of these mixins support comma separated lists of values, which allows different transitions for individual properties to be described in a single style rule. Each value in the list corresponds to the value at that same position in the other properties.
@mixin animation($animations...) {
@include prefixer(animation, $animations, webkit moz spec);
}
@mixin animation-name($names...) {
@include prefixer(animation-name, $names, webkit moz spec);
}
@mixin animation-duration($times...) {
@include prefixer(animation-duration, $times, webkit moz spec);
}
@mixin animation-timing-function($motions...) {
// ease | linear | ease-in | ease-out | ease-in-out
@include prefixer(animation-timing-function, $motions, webkit moz spec);
}
@mixin animation-iteration-count($values...) {
// infinite | <number>
@include prefixer(animation-iteration-count, $values, webkit moz spec);
}
@mixin animation-direction($directions...) {
// normal | alternate
@include prefixer(animation-direction, $directions, webkit moz spec);
}
@mixin animation-play-state($states...) {
// running | paused
@include prefixer(animation-play-state, $states, webkit moz spec);
}
@mixin animation-delay($times...) {
@include prefixer(animation-delay, $times, webkit moz spec);
}
@mixin animation-fill-mode($modes...) {
// none | forwards | backwards | both
@include prefixer(animation-fill-mode, $modes, webkit moz spec);
}

Some files were not shown because too many files have changed in this diff Show More