fetch toolbar results without page reload (#518)
This commit is contained in:
@@ -15,12 +15,15 @@ use App\Form\Type\ProjectType;
|
||||
use App\Form\Type\YesNoType;
|
||||
use App\Repository\CustomerRepository;
|
||||
use App\Repository\ProjectRepository;
|
||||
use App\Repository\Query\ProjectQuery;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
@@ -64,11 +67,7 @@ class ActivityEditForm extends AbstractType
|
||||
'data' => $customer ? $customer : null,
|
||||
'required' => false,
|
||||
'mapped' => false,
|
||||
'api_data' => [
|
||||
'select' => 'project',
|
||||
'route' => 'get_projects',
|
||||
'route_params' => ['customer' => '-s-']
|
||||
],
|
||||
'project_enabled' => true,
|
||||
])
|
||||
->add('project', ProjectType::class, [
|
||||
'label' => 'label.project',
|
||||
@@ -76,7 +75,27 @@ class ActivityEditForm extends AbstractType
|
||||
'query_builder' => function (ProjectRepository $repo) use ($project, $customer) {
|
||||
return $repo->builderForEntityType($project, $customer);
|
||||
},
|
||||
])
|
||||
]);
|
||||
|
||||
// replaces the project select after submission, to make sure only projects for the selected customer are displayed
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($project) {
|
||||
$data = $event->getData();
|
||||
if (!isset($data['customer']) || empty($data['customer'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->getForm()->add('project', ProjectType::class, [
|
||||
'group_by' => null,
|
||||
'query_builder' => function (ProjectRepository $repo) use ($data, $project) {
|
||||
return $repo->builderForEntityType($project, $data['customer']);
|
||||
},
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
$builder
|
||||
->add('fixedRate', MoneyType::class, [
|
||||
'label' => 'label.fixed_rate',
|
||||
'required' => false,
|
||||
@@ -93,7 +112,7 @@ class ActivityEditForm extends AbstractType
|
||||
])
|
||||
;
|
||||
|
||||
if ($entry->getId() === null) {
|
||||
if (null === $entry->getId()) {
|
||||
$builder->add('create_more', CheckboxType::class, [
|
||||
'label' => 'label.create_more',
|
||||
'required' => false,
|
||||
|
||||
@@ -55,8 +55,12 @@ class SelectWithApiDataExtension extends AbstractTypeExtension
|
||||
|
||||
$apiData = $options['api_data'];
|
||||
|
||||
if (!is_array($apiData)) {
|
||||
throw new \InvalidArgumentException('Option "api_data" must be an array for form "' . $form->getName() . '"');
|
||||
}
|
||||
|
||||
if (!isset($apiData['select'])) {
|
||||
throw new \InvalidArgumentException('Missing "select" option for "api_data" option for form "' . $form->getName() . '"');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($apiData['route'])) {
|
||||
@@ -67,8 +71,13 @@ class SelectWithApiDataExtension extends AbstractTypeExtension
|
||||
$apiData['route_params'] = [];
|
||||
}
|
||||
|
||||
$formPrefix = $form->getParent()->getName();
|
||||
if (!empty($formPrefix)) {
|
||||
$formPrefix .= '_';
|
||||
}
|
||||
|
||||
$view->vars['attr'] = array_merge($view->vars['attr'], [
|
||||
'data-related-select' => $form->getParent()->getName() . '_' . $apiData['select'],
|
||||
'data-related-select' => $formPrefix . $apiData['select'],
|
||||
'data-api-url' => $this->router->generate($apiData['route'], $apiData['route_params']),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -96,12 +96,14 @@ class TimesheetEditForm extends AbstractType
|
||||
'html5' => false,
|
||||
'format' => 'yyyy-MM-dd HH:mm',
|
||||
'with_seconds' => false,
|
||||
'attr' => ['autocomplete' => 'off', 'data-datetimepicker' => 'on'],
|
||||
'attr' => ['autocomplete' => 'off', 'data-datetimepicker' => 'on', 'placeholder' => 'yyyy-MM-dd HH:mm'],
|
||||
]);
|
||||
}
|
||||
|
||||
if ($options['duration_only']) {
|
||||
$builder->add('duration', DurationType::class);
|
||||
$builder->add('duration', DurationType::class, [
|
||||
'required' => false,
|
||||
]);
|
||||
} else {
|
||||
$builder->add('end', DateTimeType::class, [
|
||||
'label' => 'label.end',
|
||||
@@ -110,7 +112,7 @@ class TimesheetEditForm extends AbstractType
|
||||
'html5' => false,
|
||||
'format' => 'yyyy-MM-dd HH:mm',
|
||||
'with_seconds' => false,
|
||||
'attr' => ['autocomplete' => 'off', 'data-datetimepicker' => 'on'],
|
||||
'attr' => ['autocomplete' => 'off', 'data-datetimepicker' => 'on', 'placeholder' => 'yyyy-MM-dd HH:mm'],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -131,11 +133,7 @@ class TimesheetEditForm extends AbstractType
|
||||
'required' => false,
|
||||
'placeholder' => null === $customer ? '' : null,
|
||||
'mapped' => false,
|
||||
'api_data' => [
|
||||
'select' => 'project',
|
||||
'route' => 'get_projects',
|
||||
'route_params' => ['customer' => '-s-']
|
||||
],
|
||||
'project_enabled' => true,
|
||||
]);
|
||||
} else {
|
||||
$projectOptions['group_by'] = null;
|
||||
@@ -149,25 +147,41 @@ class TimesheetEditForm extends AbstractType
|
||||
|
||||
$builder
|
||||
->add('project', ProjectType::class, array_merge($projectOptions, [
|
||||
'activity_enabled' => true,
|
||||
// documentation is for NelmioApiDocBundle
|
||||
'documentation' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Project ID',
|
||||
],
|
||||
'required' => true,
|
||||
'query_builder' => function (ProjectRepository $repo) use ($project, $customer) {
|
||||
return $repo->builderForEntityType($project, $customer);
|
||||
},
|
||||
'api_data' => [
|
||||
'select' => 'activity',
|
||||
'route' => 'get_activities',
|
||||
'route_params' => ['project' => '-s-']
|
||||
],
|
||||
]));
|
||||
])
|
||||
);
|
||||
|
||||
// replaces the project select after submission, to make sure only projects for the selected customer are displayed
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($project) {
|
||||
$data = $event->getData();
|
||||
if (!isset($data['customer']) || empty($data['customer'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->getForm()->add('project', ProjectType::class, [
|
||||
'activity_enabled' => true,
|
||||
'group_by' => null,
|
||||
'query_builder' => function (ProjectRepository $repo) use ($data, $project) {
|
||||
return $repo->builderForEntityType($project, $data['customer']);
|
||||
},
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
$builder
|
||||
->add('activity', ActivityType::class, [
|
||||
// documentation is for NelmioApiDocBundle
|
||||
'placeholder' => null,
|
||||
'documentation' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Activity ID',
|
||||
@@ -176,6 +190,27 @@ class TimesheetEditForm extends AbstractType
|
||||
return $repo->builderForEntityType($activity, $project);
|
||||
},
|
||||
])
|
||||
;
|
||||
|
||||
// replaces the activity select after submission, to make sure only activities for the selected project are displayed
|
||||
$builder->addEventListener(
|
||||
FormEvents::PRE_SUBMIT,
|
||||
function (FormEvent $event) use ($activity) {
|
||||
$data = $event->getData();
|
||||
if (!isset($data['project']) || empty($data['project'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->getForm()->add('activity', ActivityType::class, [
|
||||
'placeholder' => null,
|
||||
'query_builder' => function (ActivityRepository $repo) use ($data, $activity) {
|
||||
return $repo->builderForEntityType($activity, $data['project']);
|
||||
},
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
$builder
|
||||
->add('description', TextareaType::class, [
|
||||
'label' => 'label.description',
|
||||
'required' => false,
|
||||
@@ -196,41 +231,6 @@ class TimesheetEditForm extends AbstractType
|
||||
]);
|
||||
}
|
||||
|
||||
/*
|
||||
$builder->get('customer')->addEventListener(
|
||||
FormEvents::POST_SUBMIT,
|
||||
function (FormEvent $event) {
|
||||
$customer = $event->getForm()->getData();
|
||||
$event->getForm()->getParent()->add('project', ProjectType::class, [
|
||||
'required' => true,
|
||||
'placeholder' => '',
|
||||
'label' => 'label.project',
|
||||
'query_builder' => function (ProjectRepository $repo) use ($customer) {
|
||||
return $repo->builderForEntityType(null, $customer);
|
||||
},
|
||||
'api_data' => [
|
||||
'select' => 'activity',
|
||||
'route' => 'get_activities',
|
||||
'route_params' => ['project' => '-s-']
|
||||
],
|
||||
]);
|
||||
}
|
||||
);
|
||||
*/
|
||||
|
||||
$builder->get('project')->addEventListener(
|
||||
FormEvents::POST_SUBMIT,
|
||||
function (FormEvent $event) {
|
||||
$project = $event->getForm()->getData();
|
||||
$event->getForm()->getParent()->add('activity', ActivityType::class, [
|
||||
'label' => 'label.activity',
|
||||
'query_builder' => function (ActivityRepository $repo) use ($project) {
|
||||
return $repo->builderForEntityType(null, $project);
|
||||
},
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
if ($options['include_user']) {
|
||||
$builder->add('user', UserType::class);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
namespace App\Form\Toolbar;
|
||||
|
||||
use App\Form\Type\ActivityType;
|
||||
use App\Form\Type\BeginDateType;
|
||||
use App\Form\Type\CustomerType;
|
||||
use App\Form\Type\EndDateType;
|
||||
use App\Form\Type\PageSizeType;
|
||||
use App\Form\Type\ProjectType;
|
||||
use App\Form\Type\UserRoleType;
|
||||
@@ -23,8 +25,6 @@ use App\Repository\Query\ActivityQuery;
|
||||
use App\Repository\Query\CustomerQuery;
|
||||
use App\Repository\Query\ProjectQuery;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
@@ -65,6 +65,8 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
{
|
||||
$builder->add('customer', CustomerType::class, [
|
||||
'required' => false,
|
||||
'project_enabled' => true,
|
||||
'project_visibility' => ProjectQuery::SHOW_BOTH,
|
||||
'query_builder' => function (CustomerRepository $repo) {
|
||||
$query = new CustomerQuery();
|
||||
$query->setVisibility(CustomerQuery::SHOW_BOTH); // this field is the reason for the query here
|
||||
@@ -114,14 +116,8 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
*/
|
||||
protected function addStartDateChoice(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('begin', DateType::class, [
|
||||
'label' => 'label.begin',
|
||||
'widget' => 'single_text',
|
||||
'html5' => false,
|
||||
$builder->add('begin', BeginDateType::class, [
|
||||
'required' => false,
|
||||
'format' => DateType::HTML5_FORMAT,
|
||||
'attr' => ['autocomplete' => 'off', 'data-datepicker' => 'on'],
|
||||
'empty_data' => (new \DateTime('first day of this month'))->format('Y-M-d')
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -130,14 +126,8 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
*/
|
||||
protected function addEndDateChoice(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('end', DateType::class, [
|
||||
'label' => 'label.end',
|
||||
'widget' => 'single_text',
|
||||
'html5' => false,
|
||||
$builder->add('end', EndDateType::class, [
|
||||
'required' => false,
|
||||
'format' => DateType::HTML5_FORMAT,
|
||||
'attr' => ['autocomplete' => 'off', 'data-datepicker' => 'on'],
|
||||
'empty_data' => (new \DateTime('last day of this month'))->format('Y-M-d')
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -146,10 +136,11 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
*/
|
||||
protected function addProjectChoice(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('project', ChoiceType::class, [
|
||||
'group_by' => null,
|
||||
$builder->add('project', ProjectType::class, [
|
||||
'required' => false,
|
||||
'label' => 'label.project',
|
||||
'activity_enabled' => true,
|
||||
'activity_visibility' => ActivityQuery::SHOW_BOTH,
|
||||
'choices' => [],
|
||||
]);
|
||||
|
||||
$builder->addEventListener(
|
||||
@@ -163,6 +154,8 @@ abstract class AbstractToolbarForm extends AbstractType
|
||||
$event->getForm()->add('project', ProjectType::class, [
|
||||
'group_by' => null,
|
||||
'required' => false,
|
||||
'activity_enabled' => true,
|
||||
'activity_visibility' => ActivityQuery::SHOW_BOTH,
|
||||
'query_builder' => function (ProjectRepository $repo) use ($data) {
|
||||
$query = new ProjectQuery();
|
||||
$query->setCustomer($data['customer']);
|
||||
|
||||
51
src/Form/Type/BeginDateType.php
Normal file
51
src/Form/Type/BeginDateType.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Form\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* Custom form field type to display the begin-date input field.
|
||||
*/
|
||||
class BeginDateType extends AbstractType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'label' => 'label.begin',
|
||||
'widget' => 'single_text',
|
||||
'html5' => false,
|
||||
'format' => DateType::HTML5_FORMAT,
|
||||
'empty_data' => (new \DateTime('first day of this month'))->format('Y-M-d')
|
||||
]);
|
||||
|
||||
$resolver->setDefault('attr', function (Options $options) {
|
||||
return [
|
||||
'autocomplete' => 'off',
|
||||
'data-datepicker' => 'on',
|
||||
'placeholder' => $options['format'],
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return DateType::class;
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,10 @@ namespace App\Form\Type;
|
||||
|
||||
use App\Entity\Customer;
|
||||
use App\Repository\CustomerRepository;
|
||||
use App\Repository\Query\ProjectQuery;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
@@ -32,8 +34,22 @@ class CustomerType extends AbstractType
|
||||
'query_builder' => function (CustomerRepository $repo) {
|
||||
return $repo->builderForEntityType(null);
|
||||
},
|
||||
'project_enabled' => false,
|
||||
'project_visibility' => ProjectQuery::SHOW_VISIBLE,
|
||||
//'attr' => ['class' => 'selectpicker', 'data-size' => 10, 'data-live-search' => true, 'data-width' => '100%']
|
||||
]);
|
||||
|
||||
$resolver->setDefault('api_data', function (Options $options) {
|
||||
if (true === $options['project_enabled']) {
|
||||
return [
|
||||
'select' => 'project',
|
||||
'route' => 'get_projects',
|
||||
'route_params' => ['customer' => '-s-', 'orderBy' => 'name', 'visible' => $options['project_visibility']],
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
51
src/Form/Type/EndDateType.php
Normal file
51
src/Form/Type/EndDateType.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Form\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* Custom form field type to display the end-date input field.
|
||||
*/
|
||||
class EndDateType extends AbstractType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'label' => 'label.end',
|
||||
'widget' => 'single_text',
|
||||
'html5' => false,
|
||||
'format' => DateType::HTML5_FORMAT,
|
||||
'empty_data' => (new \DateTime('last day of this month'))->format('Y-M-d')
|
||||
]);
|
||||
|
||||
$resolver->setDefault('attr', function (Options $options) {
|
||||
return [
|
||||
'autocomplete' => 'off',
|
||||
'data-datepicker' => 'on',
|
||||
'placeholder' => $options['format'],
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return DateType::class;
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,10 @@ namespace App\Form\Type;
|
||||
|
||||
use App\Entity\Project;
|
||||
use App\Repository\ProjectRepository;
|
||||
use App\Repository\Query\ActivityQuery;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
@@ -57,8 +59,22 @@ class ProjectType extends AbstractType
|
||||
'query_builder' => function (ProjectRepository $repo) {
|
||||
return $repo->builderForEntityType(null);
|
||||
},
|
||||
'activity_enabled' => false,
|
||||
'activity_visibility' => ActivityQuery::SHOW_VISIBLE,
|
||||
//'attr' => ['class' => 'selectpicker', 'data-size' => 10, 'data-live-search' => true, 'data-width' => '100%']
|
||||
]);
|
||||
|
||||
$resolver->setDefault('api_data', function (Options $options) {
|
||||
if (true === $options['activity_enabled']) {
|
||||
return [
|
||||
'select' => 'activity',
|
||||
'route' => 'get_activities',
|
||||
'route_params' => ['project' => '-s-', 'orderBy' => 'name', 'visible' => $options['activity_visibility']],
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user