form improvement
using theme clone
This commit is contained in:
@@ -209,6 +209,10 @@
|
|||||||
<source>label.language</source>
|
<source>label.language</source>
|
||||||
<target>Sprache</target>
|
<target>Sprache</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="label.customer">
|
||||||
|
<source>label.customer</source>
|
||||||
|
<target>Kunde</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Buttons & Actions
|
Buttons & Actions
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
{% if entries.count > 0 %}
|
{% if entries.count > 0 %}
|
||||||
{{ tables.data_table_header({
|
{{ tables.data_table_header({
|
||||||
'label.id': '',
|
'label.id': '',
|
||||||
|
'label.alias': 'bookmark-o',
|
||||||
'label.username': 'user',
|
'label.username': 'user',
|
||||||
'label.alias': 'comment-o',
|
|
||||||
'label.email': 'envelope-o',
|
'label.email': 'envelope-o',
|
||||||
'label.title': 'graduation-cap',
|
'label.title': 'graduation-cap',
|
||||||
'label.active': 'lock',
|
'label.active': 'lock',
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
{% for entry in entries %}
|
{% for entry in entries %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ entry.id }}</td>
|
<td>{{ entry.id }}</td>
|
||||||
<td><a href="{{ path('user_profile', {'username' : entry.username}) }}">{{ entry.username }}</a></td>
|
|
||||||
<td>{{ entry.alias }}</td>
|
<td>{{ entry.alias }}</td>
|
||||||
|
<td>{{ entry.username }}</td>
|
||||||
<td>{{ entry.email }}</td>
|
<td>{{ entry.email }}</td>
|
||||||
<td>{{ entry.title }}</td>
|
<td>{{ entry.title }}</td>
|
||||||
<td>{{ widgets.label_visible(entry.active) }}</td>
|
<td>{{ widgets.label_visible(entry.active) }}</td>
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
{#
|
|
||||||
This is a template fragment designed to be included in other templates
|
|
||||||
See http://symfony.com/doc/current/book/templating.html#including-other-templates
|
|
||||||
|
|
||||||
A common practice to better distinguish between templates and fragments is to
|
|
||||||
prefix fragments with an underscore. That's why this template is called
|
|
||||||
'_flash_messages.html.twig' instead of 'flash_messages.html.twig'
|
|
||||||
#}
|
|
||||||
|
|
||||||
{% if app.session.started and app.session.flashBag.peekAll is not empty %}
|
{% if app.session.started and app.session.flashBag.peekAll is not empty %}
|
||||||
<div class="messages">
|
<div class="messages">
|
||||||
{% for type, messages in app.session.flashBag.all %}
|
{% for type, messages in app.session.flashBag.all %}
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
|
|
||||||
{% macro data_table_header(entries) %}
|
{% macro data_table_header(entries) %}
|
||||||
<div class="box">
|
<div class="box">
|
||||||
{# <div class="box-header">
|
{#
|
||||||
<h3 class="box-title">Hover Data Table</h3>
|
<div class="box-header">
|
||||||
</div> #}
|
<h3 class="box-title"><a href="#" class="btn btn-primary">jkbkj</a></h3>
|
||||||
|
<div class="box-tools">
|
||||||
|
<ul class="pagination pagination-sm no-margin pull-right">
|
||||||
|
<li><a href="#">«</a></li>
|
||||||
|
<li><a href="#">1</a></li>
|
||||||
|
<li><a href="#">2</a></li>
|
||||||
|
<li><a href="#">3</a></li>
|
||||||
|
<li><a href="#">»</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
#}
|
||||||
<div class="box-body no-padding">
|
<div class="box-body no-padding">
|
||||||
<div class="dataTables_wrapper form-inline dt-bootstrap">
|
<div class="dataTables_wrapper form-inline dt-bootstrap">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ framework:
|
|||||||
twig:
|
twig:
|
||||||
debug: "%kernel.debug%"
|
debug: "%kernel.debug%"
|
||||||
strict_variables: "%kernel.debug%"
|
strict_variables: "%kernel.debug%"
|
||||||
form_themes:
|
# form_themes:
|
||||||
- "bootstrap_3_layout.html.twig"
|
# - "bootstrap_3_layout.html.twig"
|
||||||
- "form/fields.html.twig"
|
# - "form/fields.html.twig"
|
||||||
globals:
|
globals:
|
||||||
kimai_context:
|
kimai_context:
|
||||||
date_1: "d.m.Y" # used for display in timesheets
|
date_1: "d.m.Y" # used for display in timesheets
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# This file defines the canonical configuration parameters of the application.
|
# This file defines the canonical configuration parameters of the application.
|
||||||
# Symfony uses this file as a template to generate the real app/config/parameters.yml
|
# Symfony uses this file as a template to generate the real app/config/parameters.yml used by the application.
|
||||||
# used by the application.
|
|
||||||
# See http://symfony.com/doc/current/best_practices/configuration.html#canonical-parameters
|
# See http://symfony.com/doc/current/best_practices/configuration.html#canonical-parameters
|
||||||
parameters:
|
parameters:
|
||||||
|
|
||||||
@@ -28,8 +27,8 @@ parameters:
|
|||||||
mailer_password: ~
|
mailer_password: ~
|
||||||
mailer_from: anonymous@example.com
|
mailer_from: anonymous@example.com
|
||||||
|
|
||||||
# The code of the default language used by the application ('en' = English)
|
# The code of the default language used by the application ('en' = English, 'de' = German)
|
||||||
locale: en
|
locale: de
|
||||||
|
|
||||||
# The 'secret' value is a random string of characters, numbers and symbols
|
# The 'secret' value is a random string of characters, numbers and symbols
|
||||||
# used internally by Symfony in several places (CSRF tokens, URI signing,
|
# used internally by Symfony in several places (CSRF tokens, URI signing,
|
||||||
|
|||||||
@@ -12,6 +12,12 @@
|
|||||||
"app/AppCache.php"
|
"app/AppCache.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/kevinpapst/AdminThemeBundle"
|
||||||
|
}
|
||||||
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.5.9",
|
"php": ">=5.5.9",
|
||||||
"ext-pdo_sqlite": "*",
|
"ext-pdo_sqlite": "*",
|
||||||
@@ -31,7 +37,7 @@
|
|||||||
"symfony/symfony": "^3.1",
|
"symfony/symfony": "^3.1",
|
||||||
"twig/extensions": "^1.3",
|
"twig/extensions": "^1.3",
|
||||||
"white-october/pagerfanta-bundle": "^1.0",
|
"white-october/pagerfanta-bundle": "^1.0",
|
||||||
"avanzu/admin-theme-bundle": "dev-feature/2.0",
|
"avanzu/admin-theme-bundle": "dev-feature/2.0-advanced",
|
||||||
"beberlei/DoctrineExtensions": "^1.0"
|
"beberlei/DoctrineExtensions": "^1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|||||||
30
composer.lock
generated
30
composer.lock
generated
@@ -4,21 +4,21 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"hash": "d5aa01779571420f9166199f60fa2a17",
|
"hash": "6823aa58cef4fcd853f97ddd207c7cbd",
|
||||||
"content-hash": "20dda7356ab7c685ada168dd7e9b7593",
|
"content-hash": "a88a2b7ecf31f6e57be9ee123efac828",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "almasaeed2010/adminlte",
|
"name": "almasaeed2010/adminlte",
|
||||||
"version": "v2.3.7",
|
"version": "v2.3.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/almasaeed2010/AdminLTE.git",
|
"url": "https://github.com/almasaeed2010/AdminLTE.git",
|
||||||
"reference": "797b65b3ca90525a4e048de5b8d02ba6878ea239"
|
"reference": "ced14b133daed8c163863a497c43dcf69eea4340"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/almasaeed2010/AdminLTE/zipball/797b65b3ca90525a4e048de5b8d02ba6878ea239",
|
"url": "https://api.github.com/repos/almasaeed2010/AdminLTE/zipball/ced14b133daed8c163863a497c43dcf69eea4340",
|
||||||
"reference": "797b65b3ca90525a4e048de5b8d02ba6878ea239",
|
"reference": "ced14b133daed8c163863a497c43dcf69eea4340",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@@ -45,20 +45,20 @@
|
|||||||
"theme",
|
"theme",
|
||||||
"web"
|
"web"
|
||||||
],
|
],
|
||||||
"time": "2016-10-19 15:34:25"
|
"time": "2016-11-04 14:42:55"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "avanzu/admin-theme-bundle",
|
"name": "avanzu/admin-theme-bundle",
|
||||||
"version": "dev-feature/2.0",
|
"version": "dev-feature/2.0-advanced",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/avanzu/AdminThemeBundle.git",
|
"url": "https://github.com/kevinpapst/AdminThemeBundle.git",
|
||||||
"reference": "b2728cd76434cafd5f37dd0b75fe133429d2b1e0"
|
"reference": "9332a142b271d5eccd0d69e71de6b290cc133ae8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/avanzu/AdminThemeBundle/zipball/b2728cd76434cafd5f37dd0b75fe133429d2b1e0",
|
"url": "https://api.github.com/repos/kevinpapst/AdminThemeBundle/zipball/9332a142b271d5eccd0d69e71de6b290cc133ae8",
|
||||||
"reference": "b2728cd76434cafd5f37dd0b75fe133429d2b1e0",
|
"reference": "9332a142b271d5eccd0d69e71de6b290cc133ae8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -80,7 +80,6 @@
|
|||||||
"Avanzu\\AdminThemeBundle\\": ""
|
"Avanzu\\AdminThemeBundle\\": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
"license": [
|
||||||
"MIT"
|
"MIT"
|
||||||
],
|
],
|
||||||
@@ -91,7 +90,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Admin Theme based on the AdminLTE Template for easy integration into symfony",
|
"description": "Admin Theme based on the AdminLTE Template for easy integration into symfony",
|
||||||
"time": "2016-08-26 08:28:19"
|
"support": {
|
||||||
|
"source": "https://github.com/kevinpapst/AdminThemeBundle/tree/feature/2.0-advanced"
|
||||||
|
},
|
||||||
|
"time": "2016-11-13 10:50:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "beberlei/DoctrineExtensions",
|
"name": "beberlei/DoctrineExtensions",
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ class YesNoType extends AbstractType
|
|||||||
{
|
{
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'choices' => ['yes' => true, 'no' => false],
|
'choices' => ['yes' => true, 'no' => false],
|
||||||
|
'multiple' => false,
|
||||||
|
'expanded' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class Extensions extends \Twig_Extension
|
|||||||
$minute = $minute > 9 ? $minute : '0' . $minute;
|
$minute = $minute > 9 ? $minute : '0' . $minute;
|
||||||
|
|
||||||
if (!$includeSeconds) {
|
if (!$includeSeconds) {
|
||||||
return $hour . ':' . $minute;
|
return $hour . ':' . $minute . ' h';
|
||||||
}
|
}
|
||||||
|
|
||||||
$second = $seconds % 60;
|
$second = $seconds % 60;
|
||||||
@@ -93,11 +93,12 @@ class Extensions extends \Twig_Extension
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param float $amount
|
* @param float $amount
|
||||||
|
* @param string $currency
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function money($amount)
|
public function money($amount, $currency = 'EUR')
|
||||||
{
|
{
|
||||||
return round($amount) . ' €';
|
return round($amount) . ' ' . Intl::getCurrencyBundle()->getCurrencySymbol($currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,13 +12,15 @@
|
|||||||
namespace TimesheetBundle\Controller\Admin;
|
namespace TimesheetBundle\Controller\Admin;
|
||||||
|
|
||||||
use Pagerfanta\Pagerfanta;
|
use Pagerfanta\Pagerfanta;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use TimesheetBundle\Entity\Project;
|
use TimesheetBundle\Entity\Project;
|
||||||
use TimesheetBundle\Entity\Timesheet;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||||
|
use TimesheetBundle\Form\ProjectEditForm;
|
||||||
|
use TimesheetBundle\Repository\ProjectRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller used to manage projects in the admin part of the site.
|
* Controller used to manage projects in the admin part of the site.
|
||||||
@@ -35,6 +37,9 @@ class ProjectController extends Controller
|
|||||||
* @Route("/page/{page}", requirements={"page": "[1-9]\d*"}, name="admin_project_paginated")
|
* @Route("/page/{page}", requirements={"page": "[1-9]\d*"}, name="admin_project_paginated")
|
||||||
* @Method("GET")
|
* @Method("GET")
|
||||||
* @Cache(smaxage="10")
|
* @Cache(smaxage="10")
|
||||||
|
*
|
||||||
|
* @param $page
|
||||||
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
*/
|
*/
|
||||||
public function indexAction($page)
|
public function indexAction($page)
|
||||||
{
|
{
|
||||||
@@ -43,4 +48,72 @@ class ProjectController extends Controller
|
|||||||
|
|
||||||
return $this->render('TimesheetBundle:admin:project.html.twig', ['entries' => $entries]);
|
return $this->render('TimesheetBundle:admin:project.html.twig', ['entries' => $entries]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{id}/edit", name="admin_project_edit")
|
||||||
|
* @Method({"GET", "POST"})
|
||||||
|
*
|
||||||
|
* @param $id
|
||||||
|
* @param Request $request
|
||||||
|
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
|
||||||
|
*/
|
||||||
|
public function editAction($id, Request $request)
|
||||||
|
{
|
||||||
|
$project = $this->getById($id);
|
||||||
|
$editForm = $this->createEditForm($project);
|
||||||
|
|
||||||
|
$editForm->handleRequest($request);
|
||||||
|
|
||||||
|
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
||||||
|
$entityManager = $this->getDoctrine()->getManager();
|
||||||
|
$entityManager->persist($project);
|
||||||
|
$entityManager->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', 'action.updated_successfully');
|
||||||
|
|
||||||
|
return $this->redirectToRoute(
|
||||||
|
'admin_project', ['id' => $project->getId()]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render(
|
||||||
|
'TimesheetBundle:admin:project_edit.html.twig',
|
||||||
|
[
|
||||||
|
'project' => $project,
|
||||||
|
'form' => $editForm->createView()
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $id
|
||||||
|
* @return null|Project
|
||||||
|
*/
|
||||||
|
protected function getById($id)
|
||||||
|
{
|
||||||
|
/* @var $repo ProjectRepository */
|
||||||
|
$repo = $this->getDoctrine()->getRepository(Project::class);
|
||||||
|
$activity = $repo->getById($id);
|
||||||
|
if (null === $activity) {
|
||||||
|
throw new NotFoundHttpException('Project "'.$id.'" does not exist');
|
||||||
|
}
|
||||||
|
return $activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Project $project
|
||||||
|
* @return \Symfony\Component\Form\Form
|
||||||
|
*/
|
||||||
|
private function createEditForm(Project $project)
|
||||||
|
{
|
||||||
|
return $this->createForm(
|
||||||
|
ProjectEditForm::class,
|
||||||
|
$project,
|
||||||
|
[
|
||||||
|
'action' => $this->generateUrl('admin_project_edit', ['id' => $project->getId()]),
|
||||||
|
'method' => 'POST',
|
||||||
|
'currency' => $project->getCurrency()
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
namespace TimesheetBundle\DataFixtures\ORM;
|
namespace TimesheetBundle\DataFixtures\ORM;
|
||||||
|
|
||||||
use AppBundle\Entity\User;
|
use AppBundle\Entity\User;
|
||||||
|
use Symfony\Component\Intl\Intl;
|
||||||
use TimesheetBundle\Entity\Activity;
|
use TimesheetBundle\Entity\Activity;
|
||||||
use TimesheetBundle\Entity\Customer;
|
use TimesheetBundle\Entity\Customer;
|
||||||
use TimesheetBundle\Entity\Project;
|
use TimesheetBundle\Entity\Project;
|
||||||
@@ -173,6 +174,7 @@ class LoadFixtures extends AppBundleLoadFixtures
|
|||||||
|
|
||||||
$entry = new Project();
|
$entry = new Project();
|
||||||
$entry->setName($this->getRandomProject());
|
$entry->setName($this->getRandomProject());
|
||||||
|
$entry->setCurrency($this->getRandomCurrency());
|
||||||
$entry->setBudget(rand(1000, 100000));
|
$entry->setBudget(rand(1000, 100000));
|
||||||
$entry->setComment($this->getRandomPhrase());
|
$entry->setComment($this->getRandomPhrase());
|
||||||
$entry->setCustomer($allCustomer[rand(1, $amountCustomer)]);
|
$entry->setCustomer($allCustomer[rand(1, $amountCustomer)]);
|
||||||
@@ -202,6 +204,9 @@ class LoadFixtures extends AppBundleLoadFixtures
|
|||||||
$manager->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
private function getActivities()
|
private function getActivities()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -213,33 +218,51 @@ class LoadFixtures extends AppBundleLoadFixtures
|
|||||||
'Internal',
|
'Internal',
|
||||||
'Research',
|
'Research',
|
||||||
'Meeting',
|
'Meeting',
|
||||||
|
'Hosting',
|
||||||
|
'Relaunch',
|
||||||
|
'Support',
|
||||||
|
'Refactoring',
|
||||||
|
'Interview',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
private function getRandomActivity()
|
private function getRandomActivity()
|
||||||
{
|
{
|
||||||
$all = $this->getActivities();
|
$all = $this->getActivities();
|
||||||
return $all[array_rand($all)];
|
return $all[array_rand($all)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
private function getProjects()
|
private function getProjects()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'FooBar',
|
'User Experience',
|
||||||
'Relaunch',
|
'Database Migration',
|
||||||
'Refactoring',
|
|
||||||
'Test Automatisation',
|
'Test Automatisation',
|
||||||
'Website redesign',
|
'Website Redesign',
|
||||||
'Services',
|
'API Development',
|
||||||
|
'Hosting & Server',
|
||||||
|
'Customer Relations',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
private function getRandomProject()
|
private function getRandomProject()
|
||||||
{
|
{
|
||||||
$all = $this->getProjects();
|
$all = $this->getProjects();
|
||||||
return $all[array_rand($all)];
|
return $all[array_rand($all)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
private function getLocations()
|
private function getLocations()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -258,12 +281,18 @@ class LoadFixtures extends AppBundleLoadFixtures
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
private function getRandomLocation()
|
private function getRandomLocation()
|
||||||
{
|
{
|
||||||
$all = $this->getLocations();
|
$all = $this->getLocations();
|
||||||
return $all[array_rand($all)];
|
return $all[array_rand($all)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
private function getCustomers()
|
private function getCustomers()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -280,9 +309,37 @@ class LoadFixtures extends AppBundleLoadFixtures
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
private function getRandomCustomer()
|
private function getRandomCustomer()
|
||||||
{
|
{
|
||||||
$all = $this->getCustomers();
|
$all = $this->getCustomers();
|
||||||
return $all[array_rand($all)];
|
return $all[array_rand($all)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
private function getCurrencies()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'EUR',
|
||||||
|
'GBP',
|
||||||
|
'USD',
|
||||||
|
'RUB',
|
||||||
|
'JPY',
|
||||||
|
'CNY',
|
||||||
|
'INR'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getRandomCurrency()
|
||||||
|
{
|
||||||
|
$all = $this->getCurrencies();
|
||||||
|
return $all[array_rand($all)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,10 +68,17 @@ class Project
|
|||||||
*/
|
*/
|
||||||
private $budget = 0.00;
|
private $budget = 0.00;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @ORM\Column(name="currency", type="string", length=3, nullable=false)
|
||||||
|
*/
|
||||||
|
private $currency = 'EUR';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Activity[]
|
* @var Activity[]
|
||||||
*
|
*
|
||||||
* @ORM\OneToMany(targetEntity="TimesheetBundle\Entity\Activity", mappedBy="project")
|
* @ORM\OneToMany(targetEntity="TimesheetBundle\Entity\Activity", mappedBy="project", cascade={"persist", "merge", "remove"})
|
||||||
*/
|
*/
|
||||||
private $activities;
|
private $activities;
|
||||||
|
|
||||||
@@ -85,6 +92,25 @@ class Project
|
|||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getCurrency()
|
||||||
|
{
|
||||||
|
return $this->currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $currency
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setCurrency($currency)
|
||||||
|
{
|
||||||
|
$this->currency = $currency;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Customer
|
* @return Customer
|
||||||
*/
|
*/
|
||||||
@@ -199,6 +225,17 @@ class Project
|
|||||||
return $this->budget;
|
return $this->budget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Activity[] $activities
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setActivities($activities)
|
||||||
|
{
|
||||||
|
$this->activities = $activities;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Activity[]
|
* @return Activity[]
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace TimesheetBundle\Form;
|
|||||||
use AppBundle\Form\Type\YesNoType;
|
use AppBundle\Form\Type\YesNoType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
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\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use TimesheetBundle\Entity\Activity;
|
use TimesheetBundle\Entity\Activity;
|
||||||
@@ -34,20 +35,22 @@ class ActivityEditForm extends AbstractType
|
|||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
// string - length 255
|
// string - length 255
|
||||||
->add('name', null, [
|
->add('name', TextType::class, [
|
||||||
'label' => 'label.name',
|
'label' => 'label.name',
|
||||||
])
|
])
|
||||||
// text
|
// text
|
||||||
->add('comment', TextareaType::class, [
|
->add('comment', TextareaType::class, [
|
||||||
'label' => 'label.comment',
|
'label' => 'label.comment',
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
|
// entity type: project
|
||||||
|
->add('project', ProjectType::class, [
|
||||||
|
'label' => 'label.project',
|
||||||
])
|
])
|
||||||
// boolean
|
// boolean
|
||||||
->add('visible', YesNoType::class, [
|
->add('visible', YesNoType::class, [
|
||||||
'label' => 'label.visible',
|
'label' => 'label.visible',
|
||||||
])
|
])
|
||||||
->add('project', ProjectType::class, [
|
|
||||||
'label' => 'label.project',
|
|
||||||
])
|
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
88
src/TimesheetBundle/Form/ProjectEditForm.php
Normal file
88
src/TimesheetBundle/Form/ProjectEditForm.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Kimai package.
|
||||||
|
*
|
||||||
|
* (c) Kevin Papst <kevin@kevinpapst.de>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TimesheetBundle\Form;
|
||||||
|
|
||||||
|
use AppBundle\Form\Type\YesNoType;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Intl\Intl;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use TimesheetBundle\Entity\Project;
|
||||||
|
use TimesheetBundle\Form\Type\CustomerType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the form used to manipulate Projects.
|
||||||
|
*
|
||||||
|
* @author Kevin Papst <kevin@kevinpapst.de>
|
||||||
|
*/
|
||||||
|
class ProjectEditForm extends AbstractType
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
// string - length 255
|
||||||
|
->add('name', null, [
|
||||||
|
'label' => 'label.name',
|
||||||
|
])
|
||||||
|
// text
|
||||||
|
->add('comment', TextareaType::class, [
|
||||||
|
'label' => 'label.comment',
|
||||||
|
])
|
||||||
|
// customer
|
||||||
|
->add('customer', CustomerType::class, [
|
||||||
|
'label' => 'label.customer',
|
||||||
|
])
|
||||||
|
// boolean
|
||||||
|
->add('visible', YesNoType::class, [
|
||||||
|
'label' => 'label.visible',
|
||||||
|
])
|
||||||
|
// string
|
||||||
|
->add('budget', MoneyType::class, [
|
||||||
|
'label' => 'label.budget',
|
||||||
|
'currency' => $builder->getOption('currency'),
|
||||||
|
])
|
||||||
|
// FIXME add budget
|
||||||
|
// do not allow activity selection as this causes headaches:
|
||||||
|
// 1. it is a bad UX
|
||||||
|
// 2. what should happen if they are detached?
|
||||||
|
/*
|
||||||
|
->add('activities', EntityType::class, [
|
||||||
|
'label' => 'label.activity',
|
||||||
|
'class' => 'TimesheetBundle:Activity',
|
||||||
|
'multiple' => true,
|
||||||
|
'expanded' => true
|
||||||
|
])
|
||||||
|
*/
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => Project::class,
|
||||||
|
'csrf_protection' => true,
|
||||||
|
'csrf_field_name' => '_token',
|
||||||
|
'csrf_token_id' => 'admin_activity_edit',
|
||||||
|
'currency' => 'EUR,'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/TimesheetBundle/Form/Type/CustomerType.php
Normal file
44
src/TimesheetBundle/Form/Type/CustomerType.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Kimai package.
|
||||||
|
*
|
||||||
|
* (c) Kevin Papst <kevin@kevinpapst.de>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace TimesheetBundle\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom form field type to select a customer.
|
||||||
|
*
|
||||||
|
* @author Kevin Papst <kevin@kevinpapst.de>
|
||||||
|
*/
|
||||||
|
class CustomerType extends AbstractType
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'class' => 'TimesheetBundle:Customer',
|
||||||
|
'choice_label' => 'name',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return EntityType::class;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,7 +100,7 @@ class ActivityRepository extends EntityRepository
|
|||||||
*/
|
*/
|
||||||
public function findAll($page = 1)
|
public function findAll($page = 1)
|
||||||
{
|
{
|
||||||
return $this->getPager($this->queryLatest(), $page);
|
return $this->getPager($this->queryAll(), $page);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
namespace TimesheetBundle\Repository;
|
namespace TimesheetBundle\Repository;
|
||||||
|
|
||||||
use AppBundle\Entity\User;
|
use AppBundle\Entity\User;
|
||||||
use TimesheetBundle\Entity\Timesheet;
|
use TimesheetBundle\Entity\Project;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Doctrine\ORM\Query;
|
use Doctrine\ORM\Query;
|
||||||
use Pagerfanta\Adapter\DoctrineORMAdapter;
|
use Pagerfanta\Adapter\DoctrineORMAdapter;
|
||||||
@@ -27,6 +27,15 @@ use TimesheetBundle\Model\ProjectStatistic;
|
|||||||
class ProjectRepository extends EntityRepository
|
class ProjectRepository extends EntityRepository
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $id
|
||||||
|
* @return null|Project
|
||||||
|
*/
|
||||||
|
public function getById($id)
|
||||||
|
{
|
||||||
|
return $this->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return statistic data for all user.
|
* Return statistic data for all user.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -39,8 +39,10 @@ class TimesheetRepository extends EntityRepository
|
|||||||
*/
|
*/
|
||||||
protected function queryThisMonth($select, User $user = null)
|
protected function queryThisMonth($select, User $user = null)
|
||||||
{
|
{
|
||||||
$end = new DateTime();
|
$end = new DateTime('last day of this month');
|
||||||
$begin = $end->sub(new \DateInterval("P30D")); // FIXME last month is not last 30 days
|
$end->setTime(23, 59, 59);
|
||||||
|
$begin = new DateTime('first day of this month');
|
||||||
|
$begin->setTime(0,0,0);
|
||||||
|
|
||||||
return $this->queryTimeRange($select, $begin, $end, $user);
|
return $this->queryTimeRange($select, $begin, $end, $user);
|
||||||
}
|
}
|
||||||
@@ -59,7 +61,7 @@ class TimesheetRepository extends EntityRepository
|
|||||||
$qb->select($select)
|
$qb->select($select)
|
||||||
->from('TimesheetBundle:Timesheet', 't')
|
->from('TimesheetBundle:Timesheet', 't')
|
||||||
->where($qb->expr()->gt('t.begin', ':from'))
|
->where($qb->expr()->gt('t.begin', ':from'))
|
||||||
->andWhere($qb->expr()->gt('t.end', ':to'))
|
->andWhere($qb->expr()->lt('t.end', ':to'))
|
||||||
->setParameter('from', $begin, Type::DATETIME)
|
->setParameter('from', $begin, Type::DATETIME)
|
||||||
->setParameter('to', $end, Type::DATETIME);
|
->setParameter('to', $end, Type::DATETIME);
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
<td>
|
<td>
|
||||||
{{ widgets.button_group({
|
{{ widgets.button_group({
|
||||||
'edit': path('admin_activity_edit', {'id': entry.id}),
|
'edit': path('admin_activity_edit', {'id': entry.id}),
|
||||||
'trash': '#'}
|
'trash': '#'
|
||||||
) }}
|
}) }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -6,10 +6,13 @@
|
|||||||
{% block page_subtitle %}{{ 'admin_project.subtitle'|trans }}{% endblock %}
|
{% block page_subtitle %}{{ 'admin_project.subtitle'|trans }}{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
{{ include('default/_flash_messages.html.twig') }}
|
||||||
|
|
||||||
{% if entries.count > 0 %}
|
{% if entries.count > 0 %}
|
||||||
{{ tables.data_table_header({
|
{{ tables.data_table_header({
|
||||||
'label.id': '',
|
'label.id': '',
|
||||||
'label.name': 'bookmark-o',
|
'label.name': 'bookmark-o',
|
||||||
|
'label.customer': 'address-card-o',
|
||||||
'label.comment': 'comment-o',
|
'label.comment': 'comment-o',
|
||||||
'label.activity': 'tasks',
|
'label.activity': 'tasks',
|
||||||
'label.budget': 'credit-card',
|
'label.budget': 'credit-card',
|
||||||
@@ -21,12 +24,16 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ entry.id }}</td>
|
<td>{{ entry.id }}</td>
|
||||||
<td>{{ entry.name }}</td>
|
<td>{{ entry.name }}</td>
|
||||||
|
<td>{{ entry.customer.name }}</td>
|
||||||
<td>{{ entry.comment }}</td>
|
<td>{{ entry.comment }}</td>
|
||||||
<td>{{ widgets.badge_counter(entry.activities.count) }}</td>
|
<td>{{ widgets.badge_counter(entry.activities.count) }}</td>
|
||||||
<td>{{ entry.budget|money}}</td>
|
<td>{{ entry.budget|money(entry.currency) }}</td>
|
||||||
<td>{{ widgets.label_visible(entry.visible) }}</td>
|
<td>{{ widgets.label_visible(entry.visible) }}</td>
|
||||||
<td>
|
<td>
|
||||||
{{ widgets.button_group({'edit': '#', 'trash': '#'}) }}
|
{{ widgets.button_group({
|
||||||
|
'edit': path('admin_project_edit', {'id': entry.id}),
|
||||||
|
'trash': '#'
|
||||||
|
}) }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
{% import "macros/widgets.html.twig" as widgets %}
|
||||||
|
{% import "macros/datatables.html.twig" as tables %}
|
||||||
|
|
||||||
|
{% block page_title %}{{ 'admin_project.title'|trans }}{% endblock %}
|
||||||
|
{% block page_subtitle %}{{ 'admin_project.subtitle'|trans }}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{{ include('default/_flash_messages.html.twig') }}
|
||||||
|
{{ include('default/_form.html.twig', {
|
||||||
|
'title': project.name,
|
||||||
|
'form': form,
|
||||||
|
'back': path('admin_project')
|
||||||
|
}) }}
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user