prepare release 1.7 (#1388)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Change Log
|
||||
|
||||
## [1.7](https://github.com/kevinpapst/kimai2/tree/1.7) (2020-01-0?)
|
||||
## [1.7](https://github.com/kevinpapst/kimai2/tree/1.7) (2020-01-19)
|
||||
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.6.2...1.7)
|
||||
|
||||
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.7)
|
||||
|
||||
@@ -7,8 +7,8 @@ As announced in the [README](README.md) I only support the latest available rele
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| master | :white_check_mark: |
|
||||
| 1.6 | :white_check_mark: |
|
||||
| < 1.6 | :x: |
|
||||
| 1.7 | :white_check_mark: |
|
||||
| < 1.7 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export default class KimaiPaginatedBoxWidget {
|
||||
|
||||
constructor(boxId) {
|
||||
this.selector = boxId;
|
||||
this.overlay = jQuery('<div class="overlay"><div class="fa fa-refresh fa-spin"></div></div>');
|
||||
this.overlay = jQuery('<div class="overlay"><div class="fas fa-sync fa-spin"></div></div>');
|
||||
this.widget = jQuery(this.selector);
|
||||
this.href = this.widget.data('href');
|
||||
this.events = this.widget.data('reload').split(' ');
|
||||
@@ -63,6 +63,11 @@ export default class KimaiPaginatedBoxWidget {
|
||||
const html = jQuery(response);
|
||||
jQuery(selector + ' .box-tools').replaceWith(html.find('.box-tools'));
|
||||
jQuery(selector + ' .box-body').replaceWith(html.find('.box-body'));
|
||||
jQuery(selector + ' .box-title').replaceWith(html.find('.box-title'));
|
||||
if (jQuery(selector + ' .box-footer').length > 0) {
|
||||
jQuery(selector + ' .box-footer').replaceWith(html.find('.box-footer'));
|
||||
}
|
||||
jQuery(selector + ' .box-body [data-toggle="tooltip"]').tooltip();
|
||||
self.widget.removeData('error-retry');
|
||||
self._hideOverlay();
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@ import jQuery from "jquery";
|
||||
export default class KimaiReloadPageWidget {
|
||||
|
||||
constructor(events, fullReload) {
|
||||
this.overlay = jQuery('<div class="overlay-wrapper"><div class="overlay"><div class="fa fa-refresh fa-spin"></div></div></div>');
|
||||
this.overlay = jQuery('<div class="overlay-wrapper"><div class="overlay"><div class="fas fa-sync fa-spin"></div></div></div>');
|
||||
this.widget = jQuery('div.content-wrapper');
|
||||
|
||||
const self = this;
|
||||
|
||||
File diff suppressed because one or more lines are too long
1
public/build/app.8b409f35.js
Normal file
1
public/build/app.8b409f35.js
Normal file
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
"build/runtime.6ca1eea5.js",
|
||||
"build/0.1a6ffb43.js",
|
||||
"build/1.16767f92.js",
|
||||
"build/app.6ece8872.js"
|
||||
"build/app.8b409f35.js"
|
||||
],
|
||||
"css": [
|
||||
"build/app.8240996d.css"
|
||||
@@ -35,7 +35,7 @@
|
||||
"build/runtime.6ca1eea5.js": "sha384-xNNrNinl64G3nCUrIskgSjU0mUXXCB9lj6XCSInBTwxSKXk8uTMafnLHtdWdIGtd",
|
||||
"build/0.1a6ffb43.js": "sha384-vuVCyLVj2b4h3jpKl+JSANRCacmXeLk+ihK5T5NZBO7+SJ5Y+o6d4qju116hTPSD",
|
||||
"build/1.16767f92.js": "sha384-JPoKdrVtBemSiVBoAnmSxLML7xXM9zYeuwOPYQv/kLzt/P4cmLY5r9gH8oaGRPFG",
|
||||
"build/app.6ece8872.js": "sha384-4GinRERdzHwjjjUjAu6BfF705cW61DDoScnO+mWdMx7FjuXqGrQRlVzjlW7f5k3g",
|
||||
"build/app.8b409f35.js": "sha384-KLjCz4QplvRgAqezJx4OSJp38bRW0WHel8mmbmGgDtYTKIHBahoGY72PQwD+UU4m",
|
||||
"build/app.8240996d.css": "sha384-ZaS4ro6HGbDfLyaJc8cVXJzTd8plX3mRzhHhiiUEErSzPlRKdZfViDk23BNvAaz+",
|
||||
"build/2.dad56560.js": "sha384-oKsefSmRq0GL+Qa6f6jExXvFay3cM6YZFHQRKoAHi2p54UOCtjJfjF2eAB1qykoL",
|
||||
"build/chart.7f4d7f29.js": "sha384-I57c9DtU3AOG2kzKqIZkIu0hi1aGYHRZ5QG4LKC9+9slzJnAMttPGXoL2cQG3m6y",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"build/1.16767f92.js": "build/1.16767f92.js",
|
||||
"build/2.dad56560.js": "build/2.dad56560.js",
|
||||
"build/app.css": "build/app.8240996d.css",
|
||||
"build/app.js": "build/app.6ece8872.js",
|
||||
"build/app.js": "build/app.8b409f35.js",
|
||||
"build/calendar.css": "build/calendar.ade7bcdf.css",
|
||||
"build/calendar.js": "build/calendar.13664a8f.js",
|
||||
"build/chart.js": "build/chart.7f4d7f29.js",
|
||||
|
||||
@@ -21,7 +21,7 @@ class Constants
|
||||
/**
|
||||
* The current release status, either "stable" or "dev"
|
||||
*/
|
||||
public const STATUS = 'dev';
|
||||
public const STATUS = 'stable';
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -55,6 +55,29 @@ class DoctorController extends AbstractController
|
||||
$this->projectDirectory = $projectDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(path="/flush-log", name="doctor_flush_log", methods={"GET"})
|
||||
* @Security("is_granted('system_configuration')")
|
||||
*/
|
||||
public function deleteLogfileAction(): Response
|
||||
{
|
||||
$logfile = $this->getLogFilename();
|
||||
|
||||
if (file_exists($logfile)) {
|
||||
if (!is_writable($logfile)) {
|
||||
$this->flashError('action.delete.error', ['%reason%' => 'Logfile cannot be written']);
|
||||
} else {
|
||||
if (false === file_put_contents($logfile, '')) {
|
||||
$this->flashError('action.delete.error', ['%reason%' => 'Failed writing to logfile']);
|
||||
} else {
|
||||
$this->flashSuccess('action.delete.success');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('doctor');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(path="", name="doctor", methods={"GET"})
|
||||
*/
|
||||
@@ -62,6 +85,8 @@ class DoctorController extends AbstractController
|
||||
{
|
||||
$logLines = 100;
|
||||
|
||||
$canDeleteLogfile = $this->isGranted('system_configuration') && is_writable($this->getLogFilename());
|
||||
|
||||
return $this->render('doctor/index.html.twig', array_merge(
|
||||
[
|
||||
'modules' => get_loaded_extensions(),
|
||||
@@ -70,6 +95,7 @@ class DoctorController extends AbstractController
|
||||
'settings' => $this->getIniSettings(),
|
||||
'extensions' => $this->getLoadedExtensions(),
|
||||
'directories' => $this->getFilePermissions(),
|
||||
'log_delete' => $canDeleteLogfile,
|
||||
'logs' => $this->getLog(),
|
||||
'logLines' => $logLines,
|
||||
'logSize' => $this->getLogSize(),
|
||||
@@ -106,20 +132,31 @@ class DoctorController extends AbstractController
|
||||
return filesize($logfile);
|
||||
}
|
||||
|
||||
private function getLog(int $lines = 100)
|
||||
private function getLogFilename(): string
|
||||
{
|
||||
// why is this check here ???
|
||||
if (!in_array(getenv('APP_ENV'), ['test', 'dev', 'prod'])) {
|
||||
return [
|
||||
'Unsupported log environment'
|
||||
];
|
||||
throw new \RuntimeException('Unsupported log environment');
|
||||
}
|
||||
|
||||
$logfileName = 'var/log/' . getenv('APP_ENV') . '.log';
|
||||
$logfile = $this->projectDirectory . '/' . $logfileName;
|
||||
|
||||
return $this->projectDirectory . '/' . $logfileName;
|
||||
}
|
||||
|
||||
private function getLog(int $lines = 100)
|
||||
{
|
||||
try {
|
||||
$logfile = $this->getLogFilename();
|
||||
} catch (\Exception $ex) {
|
||||
return [
|
||||
$ex->getMessage()
|
||||
];
|
||||
}
|
||||
|
||||
if (!file_exists($logfile)) {
|
||||
return [
|
||||
'Could not find logfile: ' . $logfileName
|
||||
'Empty or missing logfile'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ class ThemeOptionsSubscriber implements EventSubscriberInterface
|
||||
/** @var User $user */
|
||||
$user = $this->storage->getToken()->getUser();
|
||||
|
||||
/** @var UserPreference $ref */
|
||||
foreach ($user->getPreferences() as $ref) {
|
||||
$name = $ref->getName();
|
||||
switch ($name) {
|
||||
@@ -73,6 +74,16 @@ class ThemeOptionsSubscriber implements EventSubscriberInterface
|
||||
}
|
||||
break;
|
||||
|
||||
case 'theme.layout':
|
||||
if ($ref->getValue() === 'boxed') {
|
||||
$this->helper->setOption('boxed_layout', true);
|
||||
$this->helper->setOption('fixed_layout', false);
|
||||
} elseif ($ref->getValue() === 'fixed') {
|
||||
$this->helper->setOption('boxed_layout', false);
|
||||
$this->helper->setOption('fixed_layout', true);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'theme.collapsed_sidebar':
|
||||
$this->helper->setOption('collapsed_sidebar', $ref->getValue());
|
||||
break;
|
||||
|
||||
@@ -18,6 +18,7 @@ use App\Form\Type\CalendarViewType;
|
||||
use App\Form\Type\InitialViewType;
|
||||
use App\Form\Type\LanguageType;
|
||||
use App\Form\Type\SkinType;
|
||||
use App\Form\Type\ThemeLayoutType;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
@@ -128,6 +129,12 @@ class UserPreferenceSubscriber implements EventSubscriberInterface
|
||||
->setOrder(400)
|
||||
->setType(SkinType::class),
|
||||
|
||||
(new UserPreference())
|
||||
->setName('theme.layout')
|
||||
->setValue('fixed')
|
||||
->setOrder(450)
|
||||
->setType(ThemeLayoutType::class),
|
||||
|
||||
(new UserPreference())
|
||||
->setName('theme.collapsed_sidebar')
|
||||
->setValue(false)
|
||||
|
||||
42
src/Form/Type/ThemeLayoutType.php
Normal file
42
src/Form/Type/ThemeLayoutType.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?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\ChoiceType;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* Custom form field type to select the theme layout.
|
||||
*/
|
||||
class ThemeLayoutType extends AbstractType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'required' => true,
|
||||
'choices' => [
|
||||
'fixed' => 'fixed',
|
||||
'boxed' => 'boxed',
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return ChoiceType::class;
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,8 @@ class UserCreateType extends UserEditType
|
||||
->add('plainPassword', RepeatedType::class, [
|
||||
'required' => true,
|
||||
'type' => PasswordType::class,
|
||||
'first_options' => ['label' => 'label.password'],
|
||||
'second_options' => ['label' => 'label.password_repeat'],
|
||||
'first_options' => ['label' => 'label.password', 'attr' => ['autocomplete' => 'new-password']],
|
||||
'second_options' => ['label' => 'label.password_repeat', 'attr' => ['autocomplete' => 'new-password']],
|
||||
]);
|
||||
|
||||
parent::buildForm($builder, $options);
|
||||
|
||||
@@ -29,8 +29,8 @@ class UserPasswordType extends AbstractType
|
||||
$builder
|
||||
->add('plainPassword', RepeatedType::class, [
|
||||
'type' => PasswordType::class,
|
||||
'first_options' => ['label' => 'label.password'],
|
||||
'second_options' => ['label' => 'label.password_repeat'],
|
||||
'first_options' => ['label' => 'label.password', 'attr' => ['autocomplete' => 'new-password']],
|
||||
'second_options' => ['label' => 'label.password_repeat', 'attr' => ['autocomplete' => 'new-password']],
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
@@ -304,6 +304,8 @@ final class InvoiceModel
|
||||
'project.name' => $project->getName(),
|
||||
'project.comment' => $project->getComment(),
|
||||
'project.order_number' => $project->getOrderNumber(),
|
||||
'project.start_date' => null !== $project->getStart() ? $formatter->getFormattedDateTime($project->getStart()) : '',
|
||||
'project.end_date' => null !== $project->getEnd() ? $formatter->getFormattedDateTime($project->getEnd()) : '',
|
||||
'project.order_date' => null !== $project->getOrderDate() ? $formatter->getFormattedDateTime($project->getOrderDate()) : '',
|
||||
'project.fixed_rate' => $formatter->getFormattedMoney($project->getFixedRate(), $currency),
|
||||
'project.fixed_rate_nc' => $formatter->getFormattedMoney($project->getFixedRate(), null),
|
||||
@@ -408,14 +410,47 @@ final class InvoiceModel
|
||||
'entry.user_name' => $user->getUsername(),
|
||||
'entry.user_title' => $user->getTitle(),
|
||||
'entry.user_alias' => $user->getAlias(),
|
||||
'entry.activity' => $activity->getName(),
|
||||
'entry.activity_id' => $activity->getId(),
|
||||
'entry.project' => $project->getName(),
|
||||
'entry.project_id' => $project->getId(),
|
||||
'entry.customer' => $customer->getName(),
|
||||
'entry.customer_id' => $customer->getId(),
|
||||
];
|
||||
|
||||
if (null !== $activity) {
|
||||
$values = array_merge($values, [
|
||||
'entry.activity' => $activity->getName(),
|
||||
'entry.activity_id' => $activity->getId(),
|
||||
]);
|
||||
|
||||
foreach ($activity->getVisibleMetaFields() as $metaField) {
|
||||
$values = array_merge($values, [
|
||||
'entry.activity.meta.' . $metaField->getName() => $metaField->getValue(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $project) {
|
||||
$values = array_merge($values, [
|
||||
'entry.project' => $project->getName(),
|
||||
'entry.project_id' => $project->getId(),
|
||||
]);
|
||||
|
||||
foreach ($project->getVisibleMetaFields() as $metaField) {
|
||||
$values = array_merge($values, [
|
||||
'entry.project.meta.' . $metaField->getName() => $metaField->getValue(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $customer) {
|
||||
$values = array_merge($values, [
|
||||
'entry.customer' => $customer->getName(),
|
||||
'entry.customer_id' => $customer->getId(),
|
||||
]);
|
||||
|
||||
foreach ($customer->getVisibleMetaFields() as $metaField) {
|
||||
$values = array_merge($values, [
|
||||
'entry.customer.meta.' . $metaField->getName() => $metaField->getValue(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($invoiceItem->getAdditionalFields() as $name => $value) {
|
||||
$values = array_merge($values, [
|
||||
'entry.meta.' . $name => $value,
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
{% endif %}
|
||||
{% for metaField in customer.visibleMetaFields %}
|
||||
<tr>
|
||||
<th>{{ metaField.name }}</th>
|
||||
<th>{{ metaField.label }}</th>
|
||||
<td>{{ widgets.form_type_value(metaField.type, metaField.value, customer) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
@@ -168,7 +168,7 @@
|
||||
{{ parent() }}
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('kimai.initialized', function() {
|
||||
KimaiReloadPageWidget.create('kimai.customerTeamUpdate kimai.customerUpdate kimai.teamUpdate');
|
||||
KimaiReloadPageWidget.create('kimai.customerTeamUpdate kimai.customerUpdate kimai.teamUpdate kimai.projectTeamUpdate kimai.projectUpdate');
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{% if projects|length > 0 %}
|
||||
{% embed '@AdminLTE/Widgets/box-widget.html.twig' with {'customer': customer, 'projects': projects, 'page': page} %}
|
||||
{% import "project/actions.html.twig" as actions %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% block box_title %}{{ 'menu.admin_project'|trans }}{% endblock %}
|
||||
{% block box_attributes %}
|
||||
id="project_list_box" data-href="{{ path('customer_projects', {'id': customer.id}) }}" data-reload="kimai.projectUpdate"
|
||||
@@ -17,6 +18,13 @@
|
||||
<tr>
|
||||
<td>{{ project.name }}</td>
|
||||
<td>{{ project.comment|comment2html }}</td>
|
||||
<td>
|
||||
{% if project.teams|length > 0 %}
|
||||
{{ widgets.badge_counter(project.teams|length) }}
|
||||
{% else %}
|
||||
{{ widgets.icon('unlocked') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="actions">{{ actions.project(project, 'custom') }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -74,6 +74,11 @@
|
||||
{% endif %}
|
||||
{% embed '@AdminLTE/Widgets/box-widget.html.twig' with logOpts %}
|
||||
{% block box_title %}Logfile (max. {{ logLines }} last lines){% endblock %}
|
||||
{% block box_tools %}
|
||||
{% if log_delete %}
|
||||
<a class="btn-box-tool confirmation-link" href="{{ path('doctor_flush_log') }}" data-question="confirm.delete"><i class="{{ 'delete'|icon }}"></i></a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block box_body %}
|
||||
{% if logSize > 52428800 %}
|
||||
<p>Your logfile is larger than 50 MB, consider deleting it (it will be re-created automatically).</p>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<a href="{{ path(route_pin, {'id': comment.id}) }}" class="btn btn-default btn-xs {% if comment.pinned %}active{% endif %}"><i class="{{ 'pin'|icon }}"></i></a>
|
||||
{% endif %}
|
||||
{% if route_delete is not null %}
|
||||
<a href="{{ path(route_delete, {'id': comment.id}) }}" class="confirmation-link btn btn-default btn-xs" data-method="POST" data-question="confirm.delete" data-msg-error="action.delete.error" data-msg-success="action.delete.success"><i class="{{ 'delete'|icon }}"></i></a>
|
||||
<a href="{{ path(route_delete, {'id': comment.id}) }}" class="confirmation-link btn btn-default btn-xs" data-question="confirm.delete"><i class="{{ 'delete'|icon }}"></i></a>
|
||||
{% endif %}
|
||||
{{ comment.createdAt|date_full }}
|
||||
</span>
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
{% endif %}
|
||||
{% for metaField in project.visibleMetaFields %}
|
||||
<tr>
|
||||
<th>{{ metaField.name }}</th>
|
||||
<th>{{ metaField.label }}</th>
|
||||
<td>{{ widgets.form_type_value(metaField.type, metaField.value, project) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
|
||||
{% if tags|length == 0 %}
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('kimai.initialized', function() {
|
||||
KimaiReloadPageWidget.create('kimai.tagUpdate');
|
||||
});
|
||||
</script>
|
||||
{% else %}
|
||||
|
||||
{% set columns = {
|
||||
|
||||
@@ -58,6 +58,11 @@
|
||||
|
||||
{% if entries.count == 0 %}
|
||||
{{ widgets.callout('warning', 'error.no_entries_found') }}
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('kimai.initialized', function() {
|
||||
KimaiReloadPageWidget.create('kimai.timesheetUpdate');
|
||||
});
|
||||
</script>
|
||||
{% else %}
|
||||
{{ tables.datatable_header(tableName, columns, query, {'striped': not showSummary, 'reload': 'kimai.timesheetUpdate'}) }}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
{% set options = {'class': 'alwaysVisible text-center'} %}
|
||||
{% if canEditPermissions and role.name not in system_roles|keys %}
|
||||
{% set widget %}
|
||||
<a href="{{ path('admin_user_role_delete', {'id': role.id}) }}" class="confirmation-link" data-question="confirm.delete" data-msg-error="action.delete.error" data-msg-success="action.delete.success">{{ widgets.icon('trash') }}</a>
|
||||
<a href="{{ path('admin_user_role_delete', {'id': role.id}) }}" class="confirmation-link" data-question="confirm.delete">{{ widgets.icon('trash') }}</a>
|
||||
{% endset %}
|
||||
{% set options = options|merge({'html_after': widget}) %}
|
||||
{% endif %}
|
||||
|
||||
@@ -9,18 +9,12 @@
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% import "macros/progressbar.html.twig" as progress %}
|
||||
{% block box_attributes %}id="{{ widgetId }}"{% endblock %}
|
||||
{% block box_body_class %}no-padding{% endblock %}
|
||||
{% block box_title %}
|
||||
{% if not title is empty %}{{ title|trans }}{% endif %}
|
||||
{% endblock %}
|
||||
{% block box_body %}
|
||||
<table class="table table-hover dataTable" role="grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'label.project'|trans }}</th>
|
||||
<th class="hidden-xs hidden-sm hidden-md">{{ 'label.team'|trans }}</th>
|
||||
<th style="width:50%">{{ 'label.progress'|trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for stats in projectStats %}
|
||||
{% set project = stats.project %}
|
||||
@@ -33,7 +27,7 @@
|
||||
<td class="hidden-xs hidden-sm hidden-md">
|
||||
{% for team in project.teams %}
|
||||
{% if app.user.isInTeam(team) %}
|
||||
{{ widgets.label_team(team) }}
|
||||
{{ team.name }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
|
||||
@@ -402,6 +402,7 @@ class ProfileControllerTest extends ControllerBaseTest
|
||||
['name' => 'timezone', 'value' => 'America/Creston'],
|
||||
['name' => 'language', 'value' => 'ar'],
|
||||
['name' => UserPreference::SKIN, 'value' => 'blue'],
|
||||
['name' => 'theme.layout', 'value' => 'fixed'],
|
||||
['name' => 'theme.collapsed_sidebar', 'value' => true],
|
||||
['name' => 'calendar.initial_view', 'value' => 'agendaDay'],
|
||||
]
|
||||
|
||||
@@ -135,6 +135,8 @@ class DebugRendererTest extends TestCase
|
||||
'project.hourly_rate_nc',
|
||||
'project.hourly_rate_plain',
|
||||
'project.meta.foo-project',
|
||||
'project.start_date',
|
||||
'project.end_date',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -174,10 +176,13 @@ class DebugRendererTest extends TestCase
|
||||
'entry.user_title',
|
||||
'entry.activity',
|
||||
'entry.activity_id',
|
||||
'entry.activity.meta.foo-activity',
|
||||
'entry.project',
|
||||
'entry.customer',
|
||||
'entry.project_id',
|
||||
'entry.project.meta.foo-project',
|
||||
'entry.customer',
|
||||
'entry.customer_id',
|
||||
'entry.customer.meta.foo-customer',
|
||||
'entry.category',
|
||||
'entry.type',
|
||||
];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="about.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="about.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="about.title">
|
||||
<source>about.title</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="daterangepicker.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="daterangepicker.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="daterangepicker.today">
|
||||
<source>daterangepicker.today</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="exceptions.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="exceptions.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="access.denied">
|
||||
<source>access.denied</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="flashmessages.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="flashmessages.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="warning">
|
||||
<source>warning</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="invoice-calculator.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="invoice-calculator.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="label.invoice_calculator">
|
||||
<source>label.invoice_calculator</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="invoice-numbergenerator.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="invoice-numbergenerator.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="label.invoice_number_generator">
|
||||
<source>label.invoice_number_generator</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="invoice-renderer.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="invoice-renderer.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="label.invoice_renderer">
|
||||
<source>label.invoice_renderer</source>
|
||||
|
||||
@@ -266,7 +266,11 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="label.skin">
|
||||
<source>label.skin</source>
|
||||
<target>Kimai-Theme</target>
|
||||
<target>Darstellung: Farben</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="label.theme.layout">
|
||||
<source>label.theme.layout</source>
|
||||
<target>Darstellung: Layout</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="label.hours">
|
||||
<source>label.hours</source>
|
||||
|
||||
@@ -266,7 +266,11 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="label.skin">
|
||||
<source>label.skin</source>
|
||||
<target>Kimai-Theme</target>
|
||||
<target>Display: colors</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="label.theme.layout">
|
||||
<source>label.theme.layout</source>
|
||||
<target>Display: layout</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="label.hours">
|
||||
<source>label.hours</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="messages.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="messages.en.xlf">
|
||||
<body>
|
||||
<!--
|
||||
Global template keys
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="pagerfanta.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="pagerfanta.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="previous">
|
||||
<source>previous</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="fr" datatype="plaintext" original="plugins.en.xliff ">
|
||||
<file source-language="en" target-language="fr" datatype="plaintext" original="plugins.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="plugins.title">
|
||||
<source>plugins.title</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="plugins.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="plugins.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="plugins.title">
|
||||
<source>plugins.title</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="system-configuration.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="system-configuration.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="title">
|
||||
<source>title</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="tags.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="tags.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="tags.title">
|
||||
<source>tags.title</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="teams.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="teams.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="teams.title">
|
||||
<source>teams.title</source>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="validators.en.xliff">
|
||||
<file source-language="en" target-language="zh-CN" datatype="plaintext" original="validators.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="This value is not a valid role.">
|
||||
<source>This value is not a valid role.</source>
|
||||
|
||||
Reference in New Issue
Block a user