Compare commits

..

483 Commits

Author SHA1 Message Date
Weblate (bot)
84cc65b008 Translated using Weblate (#3655)
Co-authored-by: Jonas Tisell <jonas.tisell@live.no>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2022-12-17 01:43:45 +01:00
Kevin Papst
b8b3a3c8ab fix find activity for project (#3681) 2022-12-07 22:42:02 +01:00
Kevin Papst
db0e555eae weekly timesheet uses automatic billable mode, auto responsiveness (#3679) 2022-12-07 18:44:17 +01:00
Kevin Papst
58a9facc6d Release 1.30 (#3651)
* exclude all 403 and 404 from logs
* bump version
* cleanup tag handling
* prevent mandatory user preferences turning null
2022-12-04 15:02:36 +01:00
Kevin Papst
11dac19c8c added mastodon link 2022-11-25 20:45:29 +01:00
Weblate (bot)
2d82f0400d Translated using Weblate (#3649)
Co-authored-by: Teng You Jyun <youjyun0728@gmail.com>
2022-11-24 14:37:52 +01:00
Kevin Papst
94a6b99c57 fix php 8.1 deprecations (#3648)
* show session maxlifetime in doctor
* rephrase compatibility in release notes
* bump version
2022-11-24 13:12:18 +01:00
Pieter Frenssen
2aa5eccc7c Add accessibility attributes to sortable table headers. (#3647) 2022-11-23 11:36:57 +01:00
Weblate (bot)
52f5e5640e Translated using Weblate (#3628)
Co-authored-by: BeckeBauer <berko@gmx.de>
Co-authored-by: Sergii Horichenko <m@sgg.im>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
2022-11-21 21:17:02 +01:00
Kevin Papst
d6c15bb1cb respect project start and end dates in quick-entry form (#3642) 2022-11-21 19:07:33 +01:00
Kevin Papst
4f698f73dc added username parameter to export command (#3638) 2022-11-19 18:38:13 +01:00
Kevin Papst
e413325337 added project + customer setting for calendar entry titles (#3636) 2022-11-16 23:02:26 +01:00
Kevin Papst
608a45408a Release 1.29 (#3622) 2022-11-06 20:44:30 +01:00
Weblate (bot)
323baa2d65 Translations update from Hosted Weblate (#3607)
Co-authored-by: Laurens Wuyts <laurens@mapix.be>
Co-authored-by: Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
Co-authored-by: MohammadReza Baeedi (M.R.B) <mohammadreza.baeedi@gmail.com>
Co-authored-by: Sergii Horichenko <m@sgg.im>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Swyter <swyterzone@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
2022-11-06 19:54:22 +01:00
Kevin Papst
6235d18dab improve user unique check (#3621) 2022-11-06 14:15:21 +01:00
Kevin Papst
3d0f480d9e added missing permission check on project rates in monthly report (#3627) 2022-11-05 11:39:18 +01:00
Kevin Papst
642d31432a bump dependencies and improved export command (#3606) 2022-10-30 11:34:17 +01:00
Weblate (bot)
421be6835e Translated using Weblate (#3586)
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Bogi Napoleon Wennerstrøm <bogi.wennerstrom@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: MohammadReza Baeedi (M.R.B) <mohammadreza.baeedi@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Sergii Horichenko <m@sgg.im>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: gnu-ewm <gnu.ewm@protonmail.com>
Co-authored-by: yangyangdaji <1504305527@qq.com>
Co-authored-by: Мистер Перевод <sergei@racingrebel.com>
2022-10-29 18:23:28 +02:00
Kevin Papst
d58720252e create exports via command (#3605) 2022-10-29 18:20:19 +02:00
Kevin Papst
0461539f4b new stateless firewall to prevent new sessions for API calls (#3602) 2022-10-28 15:13:40 +02:00
Kevin Papst
78749ad3b4 copy teams from logged-in user for new projects (#3599) 2022-10-25 16:31:34 +02:00
Kevin Papst
8b4828f236 allow 4 decimals for rounded rates (#3596) 2022-10-24 16:21:57 +02:00
Kevin Papst
e5614b92a0 fix test 2022-10-24 11:59:05 +02:00
Kevin Papst
f5b725e32b added first and last fields for invoices (#3594) 2022-10-24 11:46:13 +02:00
Kevin Papst
006de60f66 Release 1.28 (#3587)
* bump version
* extract toolbar cleanup logic to helper class
* allow 3 digits in invoice template tax rate
2022-10-24 11:42:56 +02:00
Kevin Papst
14f4530de0 added team filter in timesheet search forms (#3590)
* added team filter in export and invoice search form
* added teams select to timesheet filter
* added team select to report filter
* hide user and team filter if count < 2
2022-10-21 16:14:39 +02:00
Kevin Papst
2022fa54d3 added customer name as pattern option in project dropdown (#3589) 2022-10-21 15:26:53 +02:00
Kevin Papst
73ef090b9e fix several rendering issues in markdown (#3588)
- fix double escaping of html entities: &quot; instead of "
- fix table is missing css class "table"
- fix quotes are not rendered
2022-10-19 21:17:49 +02:00
Kevin Papst
6d7054c18c Release 1.27.0 (#3571)
* bump version
* ignore .disabled for plugins
* simplify gitignore
* prevent duration field from showing up in the API
* change release template wording
* prepare method for later usage
* add 8.2 to issue template
2022-10-19 08:55:42 +02:00
Weblate (bot)
4549d826dd Translations update from Hosted Weblate (#3570)
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Sergii Horichenko <m@sgg.im>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: gnu-ewm <gnu.ewm@protonmail.com>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2022-10-19 08:44:42 +02:00
Kevin Papst
7eacb1dc3c improved issue templates 2022-10-19 01:00:22 +02:00
Kevin Papst
5264dd111d fix markdown 2022-10-19 00:13:32 +02:00
Kevin Papst
a4f0b6a97e fix markdown 2022-10-19 00:12:48 +02:00
Kevin Papst
46af5e8ebf fix markdown 2022-10-19 00:12:19 +02:00
Kevin Papst
35fb15fe9f fix filename 2022-10-19 00:08:56 +02:00
Kevin Papst
662259468d improve issue templates 2022-10-18 23:42:16 +02:00
Kevin Papst
1e1b9a6919 allow to order by hourlyRate (#3582) 2022-10-16 12:01:57 +02:00
Kevin Papst
5fa10dfdf1 fix one-minute rounding bug in quick-entries (#3580)
* fix one-minute rounding bug for quick entries form
* allow to delete and create/update timesheets in one go
* prevent issues with negative durations
2022-10-16 01:05:38 +02:00
Kevin Papst
a5556a0c63 do not show potential invoices with a negative total (#3579) 2022-10-13 12:29:11 +02:00
Kevin Papst
0cefcf0e16 allow negative duration via internal API (#3573) 2022-10-10 17:47:11 +02:00
Kevin Papst
1959d4d8df added filter for globalActivities in project collection (#3565) 2022-10-01 23:25:33 +02:00
Kevin Papst
1d445d9eb6 Project API and globalActivities flag (#3564)
* expose globalActivities setting in project entity
* fix globalActivities being true by default if created via API
2022-10-01 18:14:22 +02:00
Weblate (bot)
6cfcbccabc Translated using Weblate (#3549)
Co-authored-by: Daniel <danchao@freedom.net.tw>
Co-authored-by: Eric <hamburger1024@mailbox.org>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Nguyễn Hoàng Minh <mingu03@yandex.com>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: SHINJI.K <shinkuroshi@gmail.com>
Co-authored-by: adam Petro <grimnoobster@gmail.com>
Co-authored-by: office256 <ohofman@seznam.cz>
Co-authored-by: power meshal <powermeshal@gmail.com>
Co-authored-by: Мистер Перевод <sergei@racingrebel.com>
Co-authored-by: 이정희 <daemul72@gmail.com>
2022-10-01 17:40:42 +02:00
Kevin Papst
de39623378 prepare release 1.26.0 (#3554)
* bump version
* suppress deprecation
* composer update to fix twig security issue
* make sure to use the same timezone in all test runs
2022-10-01 17:23:15 +02:00
Kevin Papst
96d0d4943b update composer packages (#3502)
drop full database schema in test
2022-09-25 17:06:49 +02:00
Kevin Papst
bfab6f42d0 use saml config interface instead of generic system configuration (#3551) 2022-09-23 13:29:46 +02:00
Weblate (bot)
b38fc96623 Translated using Weblate (#3542)
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Maamon AlHaqli <mamon321@hotmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nguyễn Hoàng Minh <mingu03@yandex.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: skotperez <skotperez@voragine.net>
2022-09-20 15:53:32 +02:00
Kevin Papst
b7bade20ea make project and customer available in summaries (#3543) 2022-09-16 13:57:03 +02:00
Kevin Papst
283ab80fc7 configurable calendar drag and drop behavior (#3537) 2022-09-14 23:29:26 +02:00
Kevin Papst
d705287510 prepare release 1.25.0 (#3531)
* remove unused variable
* allow to set field name in form helper
* fix edge case permission check in menu
2022-09-14 15:16:06 +02:00
Weblate (bot)
47d17af593 Translated using Weblate (#3532)
Co-authored-by: Nguyễn Hoàng Minh <mingu03@yandex.com>
Co-authored-by: phande <phanwiki@gmail.com>
Co-authored-by: skotperez <skotperez@voragine.net>
2022-09-14 14:43:35 +02:00
Kevin Papst
496a74f7a3 added keyboard shortcuts (#3536) 2022-09-14 14:30:15 +02:00
Kevin Papst
7eded6e126 fix resname 2022-09-08 18:08:42 +02:00
Weblate (bot)
4c9d3222d7 Translated using Weblate (#3523)
Co-authored-by: Daniel <danchao@freedom.net.tw>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Jordy Heutinck <jordyheutinck@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
2022-09-08 18:02:10 +02:00
Kevin Papst
5a2b539003 version 1.24.0 (#3515) 2022-09-04 23:55:52 +02:00
Weblate (bot)
a9252701c5 Translated using Weblate (Faroese) (#3496) 2022-09-04 23:18:18 +02:00
Alexander Pankow
2fbbbe7260 added inline disposition for PDF previews (#3486) 2022-09-04 12:15:47 +02:00
Alexander Pankow
1d1f5835da allow to hide tax rows in invoice templates if vat rate is zero (#3484) 2022-09-04 11:43:38 +02:00
Alexander Pankow
a04b72e866 use custom fonts in mpdf via twig template (#3509) 2022-09-04 00:58:54 +02:00
Kevin Papst
3f4f63dc33 fix datetime modify to now (#3511) 2022-09-03 01:11:48 +02:00
Jelle Sebreghts
1763a2efff fix grace period in quick-entry form (#3504) 2022-09-03 00:49:16 +02:00
Kevin Papst
00906851b5 bump version to 1.23.1 (#3499) 2022-09-01 13:15:17 +02:00
Kevin Papst
844a805de6 fix unit test failing on month borders (#3494) 2022-08-31 15:12:18 +02:00
Kevin Papst
718e0b5c1e prevent accidental invoice template updates (#3493) 2022-08-31 13:18:21 +02:00
Weblate (bot)
ad20fd1c64 Translated using Weblate (#3482)
Co-authored-by: Cường Bá <cuongba956@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: SDGArmenia <webadmin@armstat.am>
Co-authored-by: Tom Sawyer <weblate@grymkoll.se>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2022-08-30 18:02:44 +02:00
Kevin Papst
0eb5c0a08a fixed multiple budget validation checks (#3489)
* fix budget check for monthly budgets for records with a changed month
* fix API update of begin and end
* fix update of project and activity
2022-08-29 01:03:44 +02:00
Kevin Papst
7c3a08057d Order quick entries by project name (#3488) 2022-08-27 17:11:48 +02:00
Weblate (bot)
c3a43fe677 Translated using Weblate (#3462)
Co-authored-by: Ahmed Saleh <sniperasa8@gmail.com>
Co-authored-by: Alireza Mousavi <alrzmsv@gmail.com>
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Co-authored-by: Jiri Nakola <github@nakola.fi>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2022-08-18 14:28:35 +02:00
Kevin Papst
1c613d0a52 do not require user_preference permission when creating new user (#3474) 2022-08-16 21:13:26 +02:00
Kevin Papst
303ec5be11 bump composer packages for version 1.22.1 (#3455) 2022-08-01 18:56:48 +02:00
Kevin Papst
0e33da7760 fix invoice preview opening in current tab (#3454) 2022-08-01 18:09:41 +02:00
Kevin Papst
64c752bea3 disable create-invoice links after click to prevent double invoices (#3452) 2022-08-01 14:45:22 +02:00
Weblate (bot)
cb2938b5c2 Translations update from Hosted Weblate (#3436)
Co-authored-by: ID-86 <id86dev@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Jan Čejka <posta@jancejka.cz>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nubovik <babushkin.nikita.2008@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: andt <andywondering@protonmail.com>
2022-08-01 14:44:52 +02:00
Kevin Papst
1b8a26d36b rebuild assets for croatian (#3451) 2022-08-01 14:14:17 +02:00
Milo Ivir
afdcc88342 added javascript translations for croatian (#3447) 2022-08-01 13:57:54 +02:00
Kevin Papst
7238f404f7 technical debts (#3438)
* reformat release notes
* deactivate transactions in migrations by default
* fix migration base class
* fix default value
* composer update
2022-07-27 00:54:43 +02:00
Kevin Papst
1b8948a086 show total hourly rate in detail pages (#3441) 2022-07-27 00:52:10 +02:00
Kevin Papst
95ab9bda2d saml: allow to keep existing roles on login (#3440) 2022-07-26 23:18:04 +02:00
Kevin Papst
ed7f89cfe1 allow to restrict usage of global activities for projects (#3437) 2022-07-23 01:17:24 +02:00
Kevin Papst
8d695d03df link customer, project and activity in invoice listing (#3428) 2022-07-22 13:26:17 +02:00
Kevin Papst
ad880b5b97 bump version 1.22 (#3429)
* adjusted release note template
* stabilize test
* deactivate audit listener, more pre-validation for kimai 1 importer
2022-07-22 12:41:49 +02:00
Kevin Papst
c0f3f31095 total sums for duration and rate in invoice and export preview (#3431) 2022-07-22 12:39:50 +02:00
Kevin Papst
e2ac6a0b17 Project date-range report: allow budget-type independent project-listing (#3430) 2022-07-22 12:27:53 +02:00
Kevin Papst
0dba83d8e9 Budget graph in project details (#3406)
* do not copy description if restarting via calendar
* added support to display negative durations
* fix charts for larger numbers
2022-07-13 17:21:36 +02:00
Weblate (bot)
245dd47082 Translated using Weblate (Polish) (#3399)
Co-authored-by: Alejandro Malo <malo@pinion.education>
Co-authored-by: Anupam Malhotra <anpm.malhotra@gmail.com>
Co-authored-by: DNSE <kty5663@gmail.com>
Co-authored-by: Jiri Nakola <github@nakola.fi>
Co-authored-by: Jozef Cibík <jozef.cibik@fatchillimedia.com>
Co-authored-by: KonradMazur <konrad@mazur.legal>
2022-07-13 17:15:00 +02:00
Kevin Papst
dc40a05ebd allow to filter for canceled invoices (#3415) 2022-07-13 12:21:57 +02:00
Kevin Papst
0616506b31 re-style overlapping border (#3400) 2022-07-05 20:23:10 +02:00
Kevin Papst
196ca4f1cb new command to delete empty translations (#3392)
* composer update and phpstan issues
* bump version
2022-06-30 14:19:56 +02:00
Weblate (bot)
2d9677eefa Translations update (#3356)
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nathan <bonnemainsnathan@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: haoyubox <3306221756@qq.com>
Co-authored-by: phlostically <phlostically@mailinator.com>
Co-authored-by: whisley.wang <whisley.wang@amsrbt.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2022-06-30 14:05:18 +02:00
Kevin Papst
cd297150ea suppress deprecation notice, convert route param (#3391) 2022-06-30 12:14:01 +02:00
Kevin Papst
665f0d0ca7 require a language for invoice templates (#3387) 2022-06-27 22:57:15 +02:00
Kevin Papst
bd1097f7b5 fix en_GB format definition (#3383) 2022-06-27 22:37:31 +02:00
Kevin Papst
f30bb89597 remove currency symbol if unknown (#3381) 2022-06-25 01:23:16 +02:00
Kevin Papst
9f1f7b989c allow to set api token when creating user via API (#3380) 2022-06-25 00:26:39 +02:00
Kevin Papst
aa8549b633 reoad permissions page after role was created (#3377) 2022-06-24 16:57:59 +02:00
Kevin Papst
222056f973 removed invalid destroy calls to daterangepicker (#3371) 2022-06-23 01:59:09 +02:00
Kevin Papst
e431a1ad9e Export invoice metafields (#3366) 2022-06-21 14:06:23 +02:00
Kevin Papst
452cc46d67 fix original filenames for translations (#3363) 2022-06-19 18:01:08 +02:00
Kevin Papst
c956d075d9 added release drafter workflow (#3362) 2022-06-19 17:42:09 +02:00
Kevin Papst
cdf5a545eb fix calendar drag and drop for regular user (#3358) 2022-06-14 13:07:57 +02:00
Weblate (bot)
a60df65062 Translations update from Weblate (#3339)
* Translated using Weblate (Croatian)
Co-authored-by: ABDULLAH MOHAMMED ALMONTSHRI <acc302@gmail.com>
Co-authored-by: Bogi Napoleon Wennerstrøm <bogi.wennerstrom@gmail.com>
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Jiri Nakola <github@nakola.fi>
Co-authored-by: Luiz Carlos Lucasv <csversut@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: majorwave <majorwavebeats@gmail.com>
2022-06-11 13:53:10 +02:00
Kevin Papst
f8cb8900d6 Release 1.20.3 (#3340)
* fix edit timesheet link
* fix drag & drop creates record for wrong user
* fix search with multiple bindings
* hide user switcher in calendar if there is only one user to choose
* make quick entry responsive for mobile-only users
* mark invoices as exported by default
* fix serialization deprecation warning
* fix duration calculation for fixed rate entries
* updated composer packages
* fix checkbox for horizontal forms
* support pdfContext for PDF invoice templates
2022-06-11 13:25:50 +02:00
Kevin Papst
b46fdcefad added new permission to separate time and money budget (#3352) 2022-06-11 12:23:02 +02:00
Kevin Papst
3f827b3104 code cleanup (#3338) 2022-05-31 18:08:41 +02:00
Kevin Papst
88bf534573 added invoice text field to project and activity (#3335) 2022-05-31 17:49:23 +02:00
Weblate (bot)
a93e78bd34 Translated using Weblate (Norwegian Bokmål) (#3329)
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
2022-05-31 17:41:30 +02:00
Kevin Papst
4eb1fffeb2 added meta-field names to listing pages as css classes (#3336) 2022-05-31 17:38:53 +02:00
Kevin Papst
889e3c0d4a pre-select an option if it is the only available one (#3337) 2022-05-31 17:38:21 +02:00
Andreas Pollak
184026f5f1 added css class for custom fields (#3328) 2022-05-26 17:11:02 +02:00
Weblate (bot)
3c14fee36c Translated using Weblate (#3321)
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
2022-05-26 14:08:09 +02:00
Kevin Papst
5fb326db4d Release 1.20.2 (#3320) 2022-05-24 16:28:14 +02:00
Kevin Papst
d5f8655827 Release 1.20.1 (#3317)
- improved timesheet calculator with changesets and priority
- calculate and include exported stats (e.g. available in export templates)
- added hourly rate column to timesheet listing
2022-05-21 13:13:56 +02:00
Kevin Papst
3e6100f368 bump version to 1.20 (#3315) 2022-05-19 01:36:12 +02:00
Kevin Papst
3c71640547 allow switching user displayed in calendar (#3314) 2022-05-18 21:30:58 +02:00
Kevin Papst
913839727c permission check for mark-as-exported buttons (#3313) 2022-05-18 12:54:59 +02:00
Kevin Papst
9e2a295182 Release 1.19.8 (#3296)
* unify extension check
* fix updating one config section redirects to all sections
* weekly times: configure number of weeks for recent activities
* weekly times: configure minimum number of rows
* added explicit formats for en_GB and pt
2022-05-17 11:52:45 +02:00
Lukas Steinmann
27c60d9fc4 Prevent bookings with same start / stop time (#3304) 2022-05-17 11:12:08 +02:00
Weblate (bot)
f409ce5364 Translated using Weblate (#3310)
Co-authored-by: SHINJI.K <shinkuroshi@gmail.com>
Co-authored-by: poog <poogchamp@gmail.com>
2022-05-17 10:36:20 +02:00
Weblate (bot)
68cd879d1e Translated using Weblate (Portuguese) (#3276)
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
2022-05-08 22:27:48 +02:00
Kevin Papst
c8098b2e00 Release 1.19.7 (#3286)
* fix isWeekend() test for sunday fdow
* re-use the pattern for optgroup title
* prevent method on null
* composer update
* pre-select an option if it is the only available one
* added command to stop all active timesheets
2022-05-07 23:47:32 +02:00
Kevin Papst
100f8a5165 Release 1.19.6 (#3277) 2022-04-29 18:14:12 +02:00
Kevin Papst
76899d2fdb Release 1.19.5 (#3265) 2022-04-26 18:48:43 +02:00
j0hannesr0th
41e8e196ec fix: billable not respected in api post request (#3275) 2022-04-26 17:46:44 +02:00
Kevin Papst
ef5977bcfe allow changing calendar entry title (#3272) 2022-04-25 18:18:48 +02:00
Weblate (bot)
e94d47bf0f Translations update from Hosted Weblate (#3267)
Co-authored-by: SHINJI.K <shinkuroshi@gmail.com>
Co-authored-by: Tamás Papp <tamas.papp.it@gmail.com>
Co-authored-by: xiexieqing <xqmayone@outlook.com>
2022-04-25 16:59:55 +02:00
Weblate (bot)
f8bbb3065c Translated using Weblate (#3263)
Co-authored-by: Nathan <bonnemainsnathan@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: adam Petro <grimnoobster@gmail.com>
Co-authored-by: dkstiler <dkstiler@gmail.com>
2022-04-19 13:12:44 +02:00
Kevin Papst
bc908b4534 Release 1.19.4 (#3255)
* login redirects to homepage if already being logged-in
* fix budget check for entries that were moved to another moth
* invoice: fix amount should be decimal if decimal template is used
* added new month grouped by project/activity/user report
2022-04-18 12:41:45 +02:00
Kevin Papst
a179719c3e version 1.19.3 (#3250) 2022-04-05 18:10:09 +02:00
Kevin Papst
2ca3a3f7db interface for saml config (#3249) 2022-04-05 17:49:41 +02:00
Kevin Papst
f2a8cf0930 Release 1.19.2 (#3244) 2022-04-05 00:59:13 +02:00
Weblate (bot)
966701f94e Translated using Weblate (#3235)
Co-authored-by: ANIGO R. (AR) <franigoyt@gmail.com>
Co-authored-by: leuedaniel <leuenberger.daniel@bluewin.ch>
2022-04-04 18:20:55 +02:00
Kevin Papst
1a183a4825 allow arbitrary string length for system configurations (#3243) 2022-04-04 17:38:50 +02:00
Kevin Papst
3a7e3b2168 bump version 1.19.1 (#3229) 2022-03-30 22:23:12 +02:00
Kevin Papst
eb2664ac79 support more complex metafield queries (#3228) 2022-03-30 19:01:22 +02:00
Kevin Papst
31743cf962 fix billable calculation on timesheet restart (#3225) 2022-03-29 23:24:22 +02:00
Kevin Papst
2c2ba2e32c show user account number in report export (#3224) 2022-03-29 12:48:42 +02:00
Weblate (bot)
4ff2153e15 Translated using Weblate (#3221)
Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Mzw <466271552@qq.com>
2022-03-29 12:31:35 +02:00
Kevin Papst
3c6b5c6c1e fix relative times in budget calculation in export (#3216) 2022-03-22 21:02:29 +01:00
Kevin Papst
6c1d79fe5b release 1.19 (#3215) 2022-03-21 23:42:56 +01:00
Weblate (bot)
e5f1df8c70 Translated using Weblate (#3208)
Co-authored-by: Gil <almontegil@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Taplou <ploutarchosgram@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: 이정희 <daemul72@gmail.com>
2022-03-21 21:32:46 +01:00
Kevin Papst
d6b59f6799 defensive javascript (#3210) 2022-03-20 21:08:59 +01:00
Kevin Papst
4b069edd33 added event to extend detail pages (#3209) 2022-03-19 23:54:40 +01:00
Kevin Papst
a8ac6b2eda Release 1.18.3 (#3204)
* fix truncated comments for customer, project and activity
* fix export button label for non-translated renderer
* fixed avatar size if image or SVG is used
* filter timesheets by billable state in API
2022-03-18 23:45:41 +01:00
Weblate (bot)
5c925f0ca5 Translated using Weblate (#3194)
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Taplou <ploutarchosgram@gmail.com>
2022-03-18 23:25:22 +01:00
Kevin Papst
30c7782d6e automatic billable calculation (#3200) 2022-03-18 22:31:50 +01:00
Weblate (bot)
f7480902b4 Translated using Weblate (#3181)
Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Tiger <tigercrl@icloud.com>
2022-03-11 23:50:37 +01:00
Kevin Papst
00b5a65859 1.18.2 (#3190)
* improve console version output
* fix empty string issue in csv export (DDE protection) - fixes #3189
* fix twig sort deprecation in php 8
* sort user by displayName in users report
* fix missing custom translations in edit modal
* fix font-family in invoice.css
* invoice template "freelancer pdf" - added customer number, moved some fields around
* invoice template "default" - relocate customer number and order number in
2022-03-11 23:25:23 +01:00
Kevin Papst
317ac59f47 fix select2 and dropdown width for quick-entry form (#3188) 2022-03-07 14:22:16 +01:00
Kevin Papst
b08c156552 1.18.1 - fix description pattern in title (#3179)
* bump version
* add comment to customer/project/activity entity and collections api 
* improve title pattern usage
2022-02-28 16:32:41 +01:00
Weblate (bot)
2ad7629c2a Translations update from Hosted Weblate (#3177)
* fix broken files containing keys from messages namespace
* pre-fill missing translations with english
* new command to pre-fill empty translations
* fix locale in filename
* activate locales fa and nb_NO

Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2022-02-28 16:02:40 +01:00
Kevin Papst
42963ead5c switch to excel cell formats for report exports (#3178) 2022-02-27 13:36:52 +01:00
Kevin Papst
c0168ecc5b 1.18 (#3158)
* bump version
* fix translation ids
* added css classes to modify form with custom css
* improve export pdf file names
* respect financial year in new report
* added new InvoiceCalculator: price
* upgrade packages and node-sass to v7
* title pattern for customer, project and activity via API
* support negative money without currency
* fix sub-locale in print export template
* fix overbooking validation for monthly budget
* fix copying entities with different set of custom-fields compared to the current configuration
2022-02-25 20:41:56 +01:00
Weblate (bot)
34649d809e Translated using Weblate (Croatian) (#3174)
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
2022-02-25 20:40:16 +01:00
Weblate (bot)
ee0f6b0ccf Translations update from Hosted Weblate (#3171)
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
2022-02-25 15:30:37 +01:00
Kevin Papst
c8b47d1033 added explicit classes for widgets (#3170) 2022-02-22 21:15:19 +01:00
Weblate (bot)
3d3ae97af4 Translations update from Hosted Weblate (#3160)
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
2022-02-22 13:29:48 +01:00
fredyb
d7066a2bbc support subtotal in filtered spreadsheet (#3166) 2022-02-22 13:29:03 +01:00
Weblate (bot)
7f8545f1dc Translations update from Hosted Weblate (#3105)
Co-authored-by: Miovio <mgrundemar@gmail.com>
Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2022-02-16 12:57:47 +01:00
Kevin Papst
85a63c4b78 new user-year reporting and data-type chooser (#3155) 2022-02-16 12:18:04 +01:00
Kevin Papst
1852d71974 export user-list reports in excel (#3154) 2022-02-14 17:55:10 +01:00
Kevin Papst
7da7468965 configure display of customer, project and activity in dropdown lists (#3151) 2022-02-14 17:43:05 +01:00
Kevin Papst
83a894823f release 1.17.2 (#3135)
* allow to input password interactively in console
* added block to simplify overwriting export template parts
* prevent installation in PHP 8.1
* composer update
* phpunit version to 9
* support negative amounts in excel export
* added system configuration actions for calendar, weekly timesheet, users
* added method to render text with full markdown support
2022-02-14 17:33:52 +01:00
Kevin Papst
4cb0ac37a6 unify access to custom fields (#3106) 2022-01-28 00:04:58 +01:00
Weblate (bot)
7a6fab8624 Translations update from Hosted Weblate (#3093)
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Eric <alchemillatruth@purelymail.com>
Co-authored-by: Bogi Napoleon Wennerstrøm <bogi.wennerstrom@gmail.com>
Co-authored-by: Oliver Darvishi <nimawm81@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
2022-01-25 14:07:30 +01:00
Kevin Papst
6416b67c63 fix admin access for customer in invoice module (#3095) 2022-01-25 14:06:09 +01:00
Kevin Papst
1e269a6f82 improve team member handling (#3097) 2022-01-25 13:44:49 +01:00
Kevin Papst
8694a3bfe4 added invoice delete event (#3096) 2022-01-24 21:33:13 +01:00
Kevin Papst
9e320674c1 phpstan improvements (#3092) 2022-01-23 15:49:38 +01:00
Kevin Papst
9047e9e785 optimize prod error messages (#3091) 2022-01-23 15:29:41 +01:00
Kevin Papst
b8d8f0c16d release 1.17 (#3090) 2022-01-23 01:33:00 +01:00
Kevin Papst
8b8e9b001e bump dependencies (#3089) 2022-01-22 17:11:30 +01:00
Weblate (bot)
9c40bd98aa Translations update from Hosted Weblate (#3048)
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: 黄煜祺 <QQBB18646265284@163.com>
Co-authored-by: Hibiki Kimura <h.kimura787@gmail.com>
Co-authored-by: 좀비때려잡아 <mickey9301@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2022-01-22 13:38:45 +01:00
Kevin Papst
1a0608f49e new export template (#3082) 2022-01-22 13:20:22 +01:00
Kevin Papst
3543e0a1b5 code improvements (#3088) 2022-01-22 02:46:02 +01:00
Kevin Papst
97c23f75dd improve permission handling for quick entry controller (#3081) 2022-01-20 22:24:19 +01:00
Kevin Papst
49bb9980b8 added invoice model to invoice created event (#3079)
* added model to InvoiceCreatedEvent
* allow to switch formatter locale
2022-01-20 18:41:55 +01:00
Kevin Papst
fd4cbb43c1 bugfixes (#3078)
* fix phpdoc
* fix invoice export field order
* prevent empty migration warning
* do not trigger export validation on new timesheets
* update license year
* remove trailing comma in function call for php compatibility
* add new composer plugin config
* bump phpunit schema version
2022-01-20 17:10:56 +01:00
Kevin Papst
40242b7dcc support custom fields for invoices (#3077) 2022-01-20 16:59:26 +01:00
Kevin Papst
9731023014 1.16.10 (#3047) 2022-01-01 18:12:57 +01:00
Weblate (bot)
0abbba7a56 Translations update from Hosted Weblate (#3032)
Co-authored-by: easyjoh <johannes@easyplusplus.net>
Co-authored-by: Dmitry <dmitrydmitry761@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: 拉姆徐 <xulong_715138082@qq.com>
Co-authored-by: Michal Gajewski <gajewmic@gmail.com>
Co-authored-by: DJScias <djscias@gmail.com>
2021-12-30 22:53:01 +01:00
Kevin Papst
cc809183ae added comment field to invoice (#3045) 2021-12-30 21:49:30 +01:00
Kevin Papst
f7b3f4ed76 improve export permission checks (#3027) 2021-12-17 01:10:49 +01:00
Kevin Papst
04fc954769 allow to configure the amount of recent activity rows in an empty week (#3026) 2021-12-16 16:58:10 +01:00
Kevin Papst
3621b8c27c fix invoice budget calculation (#3024) 2021-12-15 17:56:18 +01:00
Kevin Papst
358959522d release 1.16.9 (#3018)
* fix filter action display
* allow to set system configuration during runtime
* bump version
* use deepl pro free to translate missing keys
* replacing broken Github action
2021-12-14 02:29:06 +01:00
Weblate (bot)
19cd5962aa Translations update from Hosted Weblate (#3013)
Co-authored-by: Trần Công Minh <minhhp198x@gmail.com>
2021-12-14 00:10:26 +01:00
Kevin Papst
961336f35c fix project are not filtered after submit (#3016) 2021-12-11 15:51:23 +01:00
Kevin Papst
573fa9f7f3 fix create invoice token issue (#3007) 2021-12-09 01:36:58 +01:00
Kevin Papst
22ce6b047a new invoice template variables for budgets (#3005) 2021-12-08 22:15:07 +01:00
Kevin Papst
82525f382d fix invoice preview (#3002) 2021-12-08 14:21:15 +01:00
Kevin Papst
ec9dd08970 cleanup duplicate translation ids (#3001) 2021-12-08 01:49:44 +01:00
Kevin Papst
9ec0280334 improve translation test and fix error (#2998)
Co-authored-by: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>
2021-12-07 16:56:08 +01:00
Kevin Papst
0861dbd75d new command to work with translation files (#2993) 2021-12-05 14:54:02 +01:00
Kevin Papst
f5949b6b9a use new trustedAuthors flag in CI action (#2992) 2021-12-04 22:46:39 +01:00
Weblate (bot)
99905497e1 Translations update from Hosted Weblate (#2951)
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: BeckeBauer <berko@gmx.de>
Co-authored-by: Bogi Napoleon Wennerstrøm <bogi.wennerstrom@gmail.com>
Co-authored-by: Miovio <mgrundemar@gmail.com>
Co-authored-by: Roman Ondráček <ondracek.roman@centrum.cz>
Co-authored-by: Dronrs <Dutythinking@protonmail.com>
Co-authored-by: Michal Matúšov <kubof.hromoslav@gmail.com>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-12-04 02:37:04 +01:00
Kevin Papst
4ae18b73d1 bump version (#2991) 2021-12-04 02:27:32 +01:00
Kevin Papst
1da26e041d fix invoice create and search (#2990) 2021-12-04 01:18:49 +01:00
Kevin Papst
4e42911f3d more csrf protection for invoice and search (#2984) 2021-12-02 18:01:51 +01:00
Kevin Papst
b0045a910c prevent that lock files will be committed in PRs (#2983) 2021-12-02 13:06:23 +01:00
Kevin Papst
9491f07ade fix deleting invoice documents (#2980) 2021-11-29 15:57:39 +01:00
Kevin Papst
d994339de5 fix two opening form tags (#2972) 2021-11-29 15:49:54 +01:00
Kevin Papst
0464054a2b bump version 2021-11-24 12:55:38 +01:00
Kevin Papst
b062164277 allow to delete invoice documents (#2968) 2021-11-24 10:30:49 +01:00
Kevin Papst
ff9acab0fc improve permissison handling in invoice screen (#2965) 2021-11-21 16:41:03 +01:00
Kevin Papst
76e09447c8 make sure that markdown uses safe mode (#2961) 2021-11-19 23:07:27 +01:00
Kevin Papst
9470699798 escape data in calendar popover (#2960) 2021-11-19 22:57:03 +01:00
Kevin Papst
89bfa82c61 escape customer, project and activity name in javascript (#2959) 2021-11-19 19:45:37 +01:00
Kevin Papst
859131308a improve export filename (#2958) 2021-11-19 18:53:43 +01:00
tdozbun-reno
56d02673ed Update CSRF Token IDs for Issue kevinpapst/kimai2#2947 (#2948)
* bump version
* removed not needed token, as it is already contained in the form
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-11-18 18:32:00 +01:00
Kevin Papst
b28e9c120c version 1.16.2 (#2942)
* bump version
* include calendar week in week chooser
* table names in SQL
* show save flash message
* prevent migration warning
* drop default value to prevent error when server version is not set
* csrf token for duplicate actions
* updated translations
2021-11-18 12:33:13 +01:00
Kevin Papst
c858edf5c9 release 1.16.1 (#2938)
* optional csrf token name
* fix regression when selecting all projects as super user
* prevent invalid sql
2021-11-16 21:48:50 +01:00
Kevin Papst
99ebd1d503 deactivate codecov patch percentage check (#2937) 2021-11-16 12:09:41 +01:00
Kevin Papst
f63a2c8ef6 Release 1.16 (#2929)
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
2021-11-16 10:51:01 +01:00
Kevin Papst
95796ab256 improve csrf handling (#2936) 2021-11-16 10:17:26 +01:00
Kevin Papst
a1992494d3 fetch user preferences via API (#2905) 2021-11-15 21:14:45 +01:00
Kevin Papst
5896ae26c6 improve error handling during invoice generation (#2932)
* prevent that items will be marked as exported if invoice can not be generated
* check for existing invoice number to prevent that invalid invoices will be generated
* allow to add a unique id to invoice preview files on batch export
* hide delete invoice action with deactivated permission
* try to automatically fix duplicate invoice id
2021-11-15 19:21:22 +01:00
Weblate (bot)
8978c181ee Translations update from Weblate (#2915)
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Anna Gonzalez Mellado <annagm615@gmail.com>
Co-authored-by: Gil <almontegil@gmail.com>
2021-11-15 00:57:59 +01:00
Kevin Papst
ae975d07db submit invoice search after changing the template (#2931) 2021-11-15 00:20:43 +01:00
Kevin Papst
6b49535b52 prevent csrf to flush logs (#2930) 2021-11-14 20:39:22 +01:00
Kevin Papst
8b0962e192 configure am/pm time-format as user preference (#2789) 2021-11-14 18:18:26 +01:00
pkaltenboeck
dce0578a2b new ProjectConstraint to add dynamic project validation (#2747) 2021-11-14 16:56:52 +01:00
Kevin Papst
a483184372 PDF memory optimizations (#2736) 2021-11-14 02:51:52 +01:00
Kevin Papst
6e6c60b29a added new invoice status: canceled (#2922) 2021-11-10 12:37:36 +01:00
Kevin Papst
21dbfdb4f9 do not reset password for LDAP and SAML users or rehash on API calls (#2916) 2021-11-10 11:34:50 +01:00
Kevin Papst
73ab26c7b7 added resname for tool compatibility (#2912) 2021-11-05 14:40:31 +01:00
Weblate (bot)
3e61b60c4e Translations update from Weblate (#2850)
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Anders Johansson <johansson@aljmedia.se>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Roman Shabanov <romash2605@gmail.com>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Artem <Localizer_in_Russian@protonmail.com>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: KanI <twinklingnerd@gmail.com>
Co-authored-by: ButterflyOfFire <ButterflyOfFire@protonmail.com>
2021-11-05 14:18:37 +01:00
Kevin Papst
bd2fe32d5a optimizations (#2904)
* calc once, then re-use
* prevent invalid theme switch
* allow to turn off weekly-quick-entries by permissions
* remove 00:00 from date-times that likely do not need a time
* fix datepicker out of window
2021-11-05 10:28:48 +01:00
Kevin Papst
c8854b0775 change data filter on project month report (#2911) 2021-11-05 09:45:12 +01:00
iusgit
042c119058 extend project orderNumber to 50 characters (#2828) 2021-11-03 16:48:35 +01:00
Kevin Papst
b92488e32f include roles and teams in user create form (#2849) 2021-11-03 16:24:22 +01:00
Kevin Papst
2bc76e7adc prevent empty migration warning (#2901) 2021-11-03 15:48:42 +01:00
Kevin Papst
d4278996ae composer upgrade, prevent dbal upgrade, new phpstan version (#2900) 2021-11-03 14:58:10 +01:00
Kevin Papst
eb63dae405 added invoice replacer for currently logged-in user (#2899) 2021-11-03 12:00:52 +01:00
Kevin Papst
1b35356f81 activate bleeding edge phpstan rules (#2898) 2021-11-02 13:33:21 +01:00
Kevin Papst
36c08b0dea fix weekly view day format (#2893)
* make duplicate project action available on details page
* move "weekly hours" form to main menu
* changed label of week chooser
* hide quick entries menu for punch mode users
2021-11-01 20:23:17 +01:00
Kevin Papst
1d32e4ecee use token in invoice delete route (#2889) 2021-10-30 15:17:06 +02:00
Kevin Papst
40061e43bb simplify building theme independent plugins (#2888) 2021-10-30 14:48:05 +02:00
Kevin Papst
7ed1998d04 fixes for new quick-entry week form (#2887) 2021-10-29 21:35:48 +02:00
Kevin Papst
fd2490c135 added workflow to trigger new docker images on release (#2882) 2021-10-28 10:42:53 +02:00
Kevin Papst
9ab098af86 weekly quick-entry form (#2793) 2021-10-18 11:12:46 +02:00
Kevin Papst
64893e0a95 release 1.15.6 (#2863) 2021-10-18 00:30:35 +02:00
Kevin Papst
6fdc304313 improve sunday FDOW handling (#2862) 2021-10-17 19:17:47 +02:00
Kevin Papst
fb265ed732 make sure that minute_increment is not zero (#2860) 2021-10-16 13:38:28 +02:00
Kevin Papst
e2be5b401c improve summary rows in reports (#2861) 2021-10-16 13:38:08 +02:00
Kevin Papst
8539938b8a use new codecov action (#2854) 2021-10-14 17:23:45 +02:00
Kevin Papst
bbf25823b8 release 1.15.5 (#2848) 2021-10-13 18:31:28 +02:00
Kevin Papst
6b066046c6 default value for billable flag and support in batch update (#2851) 2021-10-13 15:49:20 +02:00
Weblate (bot)
9226daa891 Translations update from Weblate (#2823)
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Péter Gyetvai <gyetpet@mailbox.org>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Eric <spice2wolf@gmail.com>
Co-authored-by: Frank.wu <me@wuzhiping.top>
Co-authored-by: web chigusa <chigusaweb66@gmail.com>
Co-authored-by: KasukeLp <kasukelp23@yahoo.com>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-10-13 14:09:15 +02:00
Kevin Papst
843cd8fb67 refactor system configuration title and wording (#2847) 2021-10-13 13:37:44 +02:00
Kevin Papst
6d7d441d42 fix missing meta fields in duplicate timesheet action (#2845) 2021-10-12 23:41:27 +02:00
Kevin Papst
1c4da30b61 fix version number 2021-10-07 16:42:17 +02:00
Kevin Papst
84e25851d3 set security options on cookies (#2825) 2021-10-07 12:40:06 +02:00
Kevin Papst
3a52daedab fix open budget calculation (#2821) 2021-10-07 11:46:48 +02:00
Kevin Papst
b7cf9cd776 added croatian language (#2817) 2021-10-06 13:41:05 +02:00
Kevin Papst
ccb184b17f Release 1.15.3 (#2813) 2021-10-05 15:30:29 +02:00
Weblate (bot)
162ff07bd5 Translations update from Weblate (#2791)
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Daniel' Ishmaev <dan.samara@gmail.com>
Co-authored-by: Luna Jernberg <droidbittin@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-10-05 15:22:45 +02:00
Kevin Papst
7326a452c3 re-added lock threads app 2021-10-04 17:09:59 +02:00
Kevin Papst
9453947309 export budget, timeBudget and budgetType (#2812) 2021-10-04 16:57:45 +02:00
Kevin Papst
d25653b6ed removed export and system-config subtitles (#2811) 2021-10-04 14:36:17 +02:00
Kevin Papst
ea415e33f5 do not apply rate factor multiple times (#2807) 2021-10-03 17:40:36 +02:00
Kevin Papst
b6430d5622 allow to customize dashboard permissions for latest row (#2806) 2021-10-03 17:17:01 +02:00
Kevin Papst
6fcd50ecdf hide not started projects in widget (#2805) 2021-10-03 13:53:52 +02:00
Kevin Papst
6857d92c4f respect customer visibility in project-overview report (#2804) 2021-10-03 13:41:14 +02:00
Weblate (bot)
4bb9edb2b5 Translations update from Weblate (#2781)
Co-authored-by: frooog in raain <sadsatan211@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Mokhtar Garmehi <Mokhtar_garmeh@yahoo.com>
Co-authored-by: Pham Mina <phamthinhalinh93@gmail.com>
Co-authored-by: Ana Carla Vasconcelos <anacarlavgs@gmail.com>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: Kevin Papst <kevinpapst@users.noreply.github.com>
2021-09-24 15:16:36 +02:00
Input-BDF
dd881bb856 prevent whitespace on line endings in created docx invoices (#2756) 2021-09-24 15:02:01 +02:00
Kevin Papst
204e0bc179 1.15.2 (#2782)
* fix division by zero
* cleanup required directories, check configured data directory, do not check for freetype support
* bump version number
2021-09-24 14:47:40 +02:00
Guillaume-Duc-95
d026460106 copy the billable status when restarting timesheet (#2778) 2021-09-20 16:23:23 +02:00
Kevin Papst
934a7855b9 remove duplicate statistic events (#2776) 2021-09-18 13:15:23 +02:00
Kevin Papst
54d7c4490f added customer number in invoice export (#2775) 2021-09-18 02:49:47 +02:00
Kevin Papst
fa6af3d148 fix api doc (teams) (#2773) 2021-09-17 14:31:37 +02:00
Kevin Papst
063753b569 improve upgrade docs (for LDAP users in 1.15) (#2772) 2021-09-17 13:42:55 +02:00
Kevin Papst
baff2d78d9 prepare release 1.15 (#2707)
* bump version
* fix invisible class on labels
* fail safe removal of foreign key
* check if optional form field exists before accessing it
* silently ignore stopped timesheets
* prevent colliding parameter names
* make sure decimal duration is always rendered with two decimals
* simplify translation
* fix #2751 ANSI_QUOTES
* rename composer task
* fix billable statistic rates
* added missing translation for export
2021-09-17 00:58:25 +02:00
Weblate (bot)
8f832856a5 Translations update from Weblate (#2739)
Co-authored-by: Sérgio Morais <lalocas@protonmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: Yan Kazachkov <yankazachkov@gmail.com>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: pisquan8 <cimurro@outlook.de>
Co-authored-by: Maamon AlHaqli <mamon321@hotmail.com>
Co-authored-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Co-authored-by: Krishna Chand <krishna_chand67@naver.com>
Co-authored-by: Anders Johansson <johansson@aljmedia.se>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-09-16 17:16:29 +02:00
Kevin Papst
f2eec4f315 API fixes (#2766) 2021-09-16 17:06:32 +02:00
Weblate (bot)
2536105ad0 Translations update from Weblate (#2717)
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Ville Kovacs <regpile@mailbox.org>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Andrea Martini <andrea.martini.7002@gmail.com>
Co-authored-by: Лолло Нуб <lollo.samp@mail.ru>
Co-authored-by: Peter Valo <pvalo@abcom.sk>
Co-authored-by: A M <augim3@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Ana Carla Vasconcelos <anacarlavgs@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-08-26 02:08:50 +02:00
Kevin Papst
98a3fc99a2 store search in session (#2735)
* allow to detect used query filters
* allow to set label in action buttons
* allow to reset last search from session
* migrate invoice archive to new search system
* display number of used search filters
2021-08-26 01:37:40 +02:00
Kevin Papst
56524a9773 data-table sorting icons and alignment (#2734) 2021-08-26 00:56:36 +02:00
Kevin Papst
fae525c82f fix duplicating timesheet if allow overlapping is deactivated (#2732) 2021-08-25 19:31:48 +02:00
Kevin Papst
5023fa6189 prevent email or username from being non-unique (#2730) 2021-08-25 15:18:46 +02:00
Kevin Papst
f743503705 added search modal for timesheet export (#2728) 2021-08-24 19:01:48 +02:00
Kevin Papst
f6a82ba119 fix team edit with deactivated users (#2716) 2021-08-11 01:23:55 +02:00
Weblate (bot)
305d3ba6fe Translations update from Weblate (#2672)
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Victor Cleaner <victor.cleaner@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: edo-2313 <edo2313@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Jack-Benny Persson <jack-benny@cyberinfo.se>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: Nathan <bonnemainsnathan@gmail.com>
Co-authored-by: dottypottylotty <muzzbuzzer@outlook.com>
Co-authored-by: Adam K <uz@zu.uz>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-08-10 15:14:30 +02:00
Kevin Papst
7873bd812e fix statistics in user profile for first year not starting in january (#2712) 2021-08-10 14:39:52 +02:00
Kevin Papst
b31ded22b9 minor restyling of login screen (#2711) 2021-08-10 14:25:36 +02:00
Toby Batch
f80fe0e4d0 allow to prefill timesheet description by get param (#2580) 2021-08-08 14:29:12 +02:00
Kevin Papst
c063aed867 fixes for 1.15 (#2704) 2021-08-08 12:38:19 +02:00
Kevin Papst
b2d3272151 support multiple teamleads in each team (#2702)
* fix jumping avatars
* fix line-break after color dot for long names
2021-08-07 18:05:41 +02:00
Kevin Papst
e9986c92d6 code cleanup (#2700)
* fix doctrine definition
* do not count api calls as login
* remove unknown form options
* fix annotations
* cleanup deprecations in tests
2021-08-07 01:36:59 +02:00
Kevin Papst
3a7dba437c move supported languages logic to service (#2701) 2021-08-07 01:11:42 +02:00
Kevin Papst
cefd747e91 monthly budget, monthly report, unified report calculation (#2684) 2021-08-06 18:38:41 +02:00
Jelle Sebreghts
21f785638c added calendar configuration event (#2698) 2021-08-06 18:35:37 +02:00
Kevin Papst
df62c8a428 improved play and stop button (#2692)
* improved play and stop button if only one record is allowed
* stop button first in action menu
* fix skin colors
* autofocus term field in search form
* fix responsive column layout in invoice listing
* improve responsive header for small screens
2021-07-30 19:57:57 +02:00
Kevin Papst
37e02365c7 importer supports merge of multiple Kimai 1 installations (#2691) 2021-07-28 14:16:49 +02:00
Kevin Papst
7352c9a394 allow 65535 character in meta fields (#2690) 2021-07-27 19:41:12 +02:00
Kevin Papst
5b8510be56 fix ldap issues due to new security components (#2689) 2021-07-27 19:31:49 +02:00
Kevin Papst
6d5244aa5d LDAP: fixing issues for re-authenticating users (#2681) 2021-07-23 16:12:38 +02:00
Kevin Papst
f1f60042d8 bugfixes (#2669)
* allow storage of multiple .env without git
* clarify requirements
* fail safe statistic queries
* remove unused translations
* reduce customer statistic calls by 50%
2021-07-23 15:15:54 +02:00
Weblate (bot)
6558bcae1d Translations update from Weblate (#2665)
Co-authored-by: Viktor Żakowski <pocomito250@gmail.com>
Co-authored-by: phlostically <phlostically@mailinator.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Tur <tur+translate@simplelogin.fr>
Co-authored-by: Adaś <adam.prosniak@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Eugenia Russell <eugenia.russell2019@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-07-19 01:02:11 +02:00
Kevin Papst
828b9c8b4a added account number field to user (#2671) 2021-07-19 00:13:39 +02:00
Kevin Papst
7d052eba00 make sure that timezone is properly validated (#2663) 2021-07-13 23:23:18 +02:00
Weblate (bot)
43a31efeac updated french (#2661)
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
2021-07-13 16:16:20 +02:00
Kevin Papst
f12f1ae60d bugfixes and improvements (#2660) 2021-07-13 15:51:27 +02:00
Weblate (bot)
9dc94084c1 Translations update from Weblate (#2613)
Co-authored-by: phlostically <phlostically@mailinator.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: Yan Kazachkov <yankazachkov@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-07-13 14:49:46 +02:00
Kevin Papst
03d5d3c70c better readability for drag and drop boxes (#2659) 2021-07-13 12:12:10 +02:00
Kevin Papst
27cea996c0 configurable print export (#2657) 2021-07-13 10:11:20 +02:00
Kevin Papst
7661d43327 improve permission checks for report access (#2658) 2021-07-13 06:21:31 +02:00
Kevin Papst
a1f90ffaba limit amount of items in calendar drag and drop boxes (#2291) 2021-07-11 15:03:18 +02:00
Kevin Papst
2583fdf20e small bugfixes (#2655)
* improve report visibility
* fix timesheet duration, which breaks validation
* added contributing section in README
* do not allow to change project for existing activities - fixes #2576
* bump theme version to fix FOSUserBundle dependency
* use entity color instead of inherited one - fixes #2200
2021-07-10 00:37:03 +02:00
Kevin Papst
9ddb87a6fd added project detail report (#2651)
- avatars via css only
- random colors for entities
- improves print view
- added colors for teams
- added color to tag
2021-07-06 22:01:20 +02:00
Kevin Papst
cc6031bfde invoice number pattern for customer-name and number (#2640) 2021-06-30 17:23:20 +02:00
Kevin Papst
6d196879b4 refactor configurations (#2626)
* composition instead of inheritance
* refactored some twig extensions to runtime extensions
2021-06-26 13:03:54 +02:00
Kevin Papst
3d1fba650b improve color chooser and name validation (#2622) 2021-06-25 16:35:16 +02:00
Kevin Papst
0d5e0b3e80 fix url under certain environments (#2621) 2021-06-25 09:48:38 +02:00
Kevin Papst
7460647d58 added setting to limit the maximum length of a timesheet record (#2612) 2021-06-12 01:05:33 +02:00
Weblate (bot)
53e01177d9 Translations update from Weblate (#2577)
Co-authored-by: Maamon AlHaqli <mamon321@hotmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Tymofij Lytvynenko <till.svit@gmail.com>
Co-authored-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Co-authored-by: Nerdiin <dznissei10@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Richard Mangahas <richard.mangahas.aeom@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: phlostically <phlostically@mailinator.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-06-12 00:56:24 +02:00
Kevin Papst
6709ef4c4c removed soft_limit setting (#2611) 2021-06-10 16:01:09 +02:00
Kevin Papst
0b519e9d08 fix datepicker appears out of screen (#2610) 2021-06-10 15:51:26 +02:00
Kevin Papst
7f20cb045c Refactor authentication system (#2602)
Make auth configuration available via UI, remove FOSUserBundle and SAML-Bundle dependency
2021-06-10 15:34:13 +02:00
Kevin Papst
286b63e2c8 allow to configure timezone for the lockdown period (#2593) 2021-06-02 00:05:44 +02:00
Kevin Papst
c1eb5ba90a lint container, workflows and composer update (#2591) 2021-06-01 19:20:12 +02:00
Kevin Papst
4859ac8ecb Support for PHP 8 (#2158)
painful 66 commits later: required PHP version bumped to 7.3, plugin updates using migrations necessary!
2021-05-31 14:53:22 +02:00
Kevin Papst
df6bd30d03 fix calendar totals for empty weeks (#2581) 2021-05-21 15:27:10 +02:00
Kevin Papst
70fd0ae269 show revenues in dashboard to admins only, not teamleads (#2573) 2021-05-16 20:36:43 +02:00
Kevin Papst
dd83872339 new permission to hide user choice in report (#2572) 2021-05-16 00:52:42 +02:00
Kevin Papst
f7aa3c1e13 financial year setting + new users working time per year report (#2547) 2021-05-14 18:40:48 +02:00
dkstiler
a9da5f8476 added greek language (#2568) 2021-05-14 18:04:46 +02:00
Weblate (bot)
06f3a1ecd4 Translations update from Weblate (#2546)
Co-authored-by: Guilherme Dimas <guilhermedimasrosa@gmail.com>
Co-authored-by: dkstiler <dkstiler@gmail.com>
Co-authored-by: P-A Lindkvist <pa.lindkvist@gmail.com>
Co-authored-by: Henrik Dankvardt <dankvardt@gmail.com>
Co-authored-by: 김주열 <quick3377@gmail.com>
Co-authored-by: Nerdiin <dznissei10@gmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: whenwesober <naomi16i_1298q@cikuh.com>
Co-authored-by: Ido Ido <kobid88923@mxcdd.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-05-14 17:06:37 +02:00
Kevin Papst
bed3ade221 Improve progressbar values in report (#2569) 2021-05-14 11:45:03 +02:00
Kevin Papst
f2b32b211b use dialog to duplicate timesheet (#2567)
* fix: display time budget in customer listing if set
* updated api methods with annotations
* do not require checkboxes for system configurations
* open dialog for duplicated timesheets
2021-05-12 22:32:08 +02:00
Kevin Papst
f81f9ba492 added API route to fetch infos about installed plugins (#2561) 2021-05-12 14:03:46 +02:00
Kevin Papst
f10aad927f fix timesheet collection fetch via API with end datetime set (#2552) 2021-05-05 13:02:09 +02:00
Kevin Papst
4fcd97b142 do not include running entries in invoices (#2551) 2021-05-04 12:29:20 +02:00
Kevin Papst
dad1b8b772 version 1.14.1 (#2532)
* no back links in modal pages
* remove unused service links to bountysource and gitter
* add validation for budget and time-budget fields
* display time budget if set
* remove console log
* sanitize DDE payloads
* do not show status and name in version string
2021-04-29 18:29:03 +02:00
Weblate (bot)
22af82cb15 Translations update from Weblate (#2528)
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: phlostically <phlostically@mailinator.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
2021-04-29 12:00:27 +02:00
Kevin Papst
e4b176a4d5 use events for budget calculation (#2544) 2021-04-29 11:50:48 +02:00
Kevin Papst
bb94b11e37 support tags in invoices (#2526) 2021-04-23 17:06:42 +02:00
Weblate (bot)
67d23ec6b2 Translations update from Weblate (#2474)
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: phlostically <phlostically@mailinator.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Bogi Napoleon Wennerstrøm <bogi.wennerstrom@gmail.com>
Co-authored-by: Martin Didriksen <martindidriksen@hotmail.com>
Co-authored-by: Christian Eichert <c@zp1.net>
Co-authored-by: Gontzal Manuel Pujana Onaindia <thadahdenyse@gmail.com>
Co-authored-by: DJScias <djscias@gmail.com>
Co-authored-by: Bruno Oliveira Rosa <brunokauaoliveira@gmail.com>
Co-authored-by: Mohammad Firuzabadi <mohmmad.fi@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-04-22 01:22:39 +02:00
Kevin Papst
ff7a402bd4 fix locale date format in report header and more (#2520)
* fix problem with empty end datetime in edit time
* fixed calendar creation with tags in "pre-defined tags" mode
* fix locale date format in report header
2021-04-21 22:23:32 +02:00
Kevin Papst
305a2fd4f6 show daily sum in calendar week and day view (#2519) 2021-04-21 16:11:31 +02:00
Kevin Papst
09c9a95fcf added activity events for plugins (#2516) 2021-04-21 15:56:17 +02:00
Kevin Papst
08a144ac31 drag & drop to delete entries from the calendar (#2513) 2021-04-20 14:50:23 +02:00
Kevin Papst
7ddcde62dd fix sunday being first day of week (#2483) 2021-04-19 18:32:21 +02:00
Kevin Papst
b6462b406d updated all packages (#2512) 2021-04-19 17:25:06 +02:00
Kevin Papst
0330f45c6a billable timesheets, inactive projects report, bookmark export search (#2503) 2021-04-18 21:51:27 +02:00
Kevin Papst
8664d94ea6 release 1.14 (#2498) 2021-04-11 14:11:09 +02:00
Kevin Papst
af9dea9226 prepare release 1.14 (#2495)
* removed un-maintained docker file
* update all packages
* fix deprecations
* only show one line descriptions for customer, projects and activities
* allow to show export column in timesheet listing
2021-04-08 18:07:57 +02:00
Kevin Papst
2ce6e815ff new report: week for users (#2494) 2021-04-07 22:20:19 +02:00
Kevin Papst
cdad5913ca highlight invisible items (#2493) 2021-04-07 19:14:33 +02:00
Kevin Papst
68bb01d064 allow to pre-define colors to choose from (#2481) 2021-04-06 00:45:54 +02:00
Weblate (bot)
f4dbdbb427 Translations update from Weblate (#2401) 2021-03-29 11:45:03 +02:00
Philipp
d84beb957c add subtotal and payment date to invoices (#2450) 2021-03-29 00:51:34 +02:00
Kevin Papst
7029bde555 improve project overview (#2467) 2021-03-28 14:46:45 +02:00
Kevin Papst
7427187647 fix api 404 on page parameter (#2468) 2021-03-28 11:30:35 +02:00
Kevin Papst
f8a5ff7315 create multiple invoices at once (#2465) 2021-03-27 20:47:53 +01:00
Kevin Papst
87d07ffaaf save default search options (#2445)
* set default times for daterange objects
* allow to show order and order by fields
* move search to modal
* more options for page size
* save export visibility in cookie
2021-03-20 01:10:45 +01:00
Kevin Papst
954ba7c937 improve project view table (#2441) 2021-03-16 15:59:31 +01:00
Kevin Papst
16e8e8a5e5 fix deprecations (move same controller) (#2440) 2021-03-16 14:06:15 +01:00
Kevin Papst
75e62b800c added version ID for simpler comparison (#2439) 2021-03-16 11:24:19 +01:00
Kevin Papst
e1c9af795c refactored page actions to event subscriber (#2420) 2021-03-15 14:18:44 +01:00
Kevin Papst
9a2fd9ba91 allow increasing invoice numbers per day (#2433) 2021-03-14 13:53:36 +01:00
Kevin Papst
c0378b4f51 add user preference: default report (#2430) 2021-03-14 13:32:47 +01:00
Kevin Papst
0a6ea6be42 hide expired projects in team-projects widget (#2432) 2021-03-14 13:24:24 +01:00
Kevin Papst
ec0eca39ff show budget and time-budget columns in listing views (#2429) 2021-03-13 20:44:10 +01:00
Kevin Papst
3e9371bd6a Timesheet validator: prevent overbooking budgets (#2422) 2021-03-13 14:41:29 +01:00
Kevin Papst
db1344573f search and export from invoice archive (#2408) 2021-03-10 01:50:27 +01:00
Willian Gustavo Veiga
c34e9f576d added new report: project view (#1738) 2021-03-09 23:19:11 +01:00
Kevin Papst
0b7d551048 added more columns to spreadsheet exports (#2413) 2021-03-08 18:32:11 +01:00
Kevin Papst
30ac5e4c24 Drop SQLite support (#2405) 2021-03-08 16:06:22 +01:00
Kevin Papst
70f7f35009 allow to select reports as initial view (#2403) 2021-03-06 12:59:13 +01:00
Kevin Papst
5583caa9e4 User profile layout (#2402) 2021-03-06 12:34:34 +01:00
Kevin Papst
d3099aca39 remove redundant translation key (#2394) 2021-03-03 13:19:06 +01:00
Weblate (bot)
765ea63aed Translations update from Weblate (#2293) 2021-03-03 12:58:42 +01:00
Kevin Papst
adf8c09fd4 refactored permission templates to match controller (#2391) 2021-03-03 11:31:29 +01:00
Maxim Butakov
5a90b36734 fix unreadable notice for delete modals (#2379) 2021-02-28 15:20:05 +01:00
Kevin Papst
2e7bfc822c Widget fixes (#2373)
* fix click on row in team-projects
* hide deactivated users in team listing
2021-02-21 00:51:46 +01:00
Kevin Papst
607d09aefb performance improvements (#2329)
* remove work from constructor
* refactor twig extensions
* upgrade theme
* replace sub-request with direct template rendering
2021-02-20 23:52:01 +01:00
Kevin Papst
9eb25c412e prevent duplicate if overlapping records are disabled (#2311) 2021-02-06 17:31:14 +01:00
Kevin Papst
8d41fa20bd prepare release 1.13 (#2290)
* make voters a final class
* upgrade dependencies
* sort project alphabetically in dashboard widget
* open detail page on row click
* do not break on null tag name
* added max height to scrollable widgets on dashboard
* added timesheet duplicate event
* allow to deactivate browser title update
* improve comment box
* moved role permissions to own menu
* removed tabs in user screen
* fix user can remove super-admin from own account
2021-02-01 23:43:47 +01:00
Kevin Papst
a034b3519e added de_AT and pt as languages (#2292) 2021-01-23 00:00:30 +01:00
Weblate (bot)
ebf0b4de51 Translations update from Weblate (#2253)
Co-authored-by: MikKrz <mik.zly@gmail.com>
Co-authored-by: badlop <badlop@process-one.net>
Co-authored-by: Peter Donka <peter.donka@gmail.com>
Co-authored-by: 知者无涯 <wasd_jkl@outlook.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Omer I.S <omeritzicschwartz@gmail.com>
Co-authored-by: Nathan <bonnemainsnathan@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2021-01-22 20:45:39 +01:00
Kevin Papst
c9ccdb5f77 replace "freelancer" invoice template with pdf version (#2289) 2021-01-22 19:47:05 +01:00
Kevin Papst
88b4d3842f improve API validation error messages (#2278) 2021-01-20 18:57:16 +01:00
Kevin Papst
3cd7e01a2c show calculated lockdown date in config screen (#2274) 2021-01-20 17:50:50 +01:00
Kevin Papst
bd39666759 do not break excel invoice templates with replacer inside formulas (#2272) 2021-01-19 17:25:16 +01:00
Kevin Papst
67d5cba09f improve permission checks for timesheets with activated lockdown (#2271) 2021-01-17 17:50:37 +01:00
Kevin Papst
8d72d114c7 improved duration and minute selector (#2264)
* do not close modal if form is dirty
* deprecated TimesheetConfiguration
* inject timezone in form types
* cleanup usage of UserDateTimeFactory
* allow to configure increment steps for minutes
* use 15 minutes step for datetimepicker in project edit form
* use rounding rules for increments in minute select for begin and end
* allow duration in multi user and admin timesheet forms
* make dropdown values configurable
2021-01-17 14:04:13 +01:00
Kevin Papst
e2324b7d51 fix calendar problem with UTC (#2268) 2021-01-16 00:00:47 +01:00
Kevin Papst
1eae149c75 remove drag&drop on calendar for print views (#2261) 2021-01-14 20:53:18 +01:00
Kevin Papst
2a986517f7 fix pagination on invoice templates page (#2260) 2021-01-14 13:12:34 +01:00
Kevin Papst
bf47bb1840 hide multi update in tags view if delete_tag permission is missing (#2259) 2021-01-14 12:44:56 +01:00
Kevin Papst
cb6924e6d6 added event for recent activities (#2254) 2021-01-11 19:13:14 +01:00
Philipp Strobel
1de6b5d385 use the correct javascript event name (#2210) 2021-01-08 16:27:00 +01:00
Philipp Strobel
4c73fc825c Fix dropdowns on the bottom of a page (#2212) 2021-01-08 15:42:09 +01:00
Weblate (bot)
d0a0786cce Translations update from Weblate (#2226)
* Translated using Weblate (Polish)
* Translated using Weblate (Swedish)
* Translated using Weblate (Portuguese (Brazil))
* Translated using Weblate (Slovak)

Co-authored-by: Michał Jastrzębski <michu9010@gmail.com>
Co-authored-by: Andreas Håll <ante_skalman@hotmail.com>
Co-authored-by: Augusto Milão <augusto.milao01@gmail.com>
Co-authored-by: Aris <aatiger2007@gmail.com>
2021-01-08 15:22:54 +01:00
Kevin Papst
b7390ece39 week numbers by ISO (#2248) 2021-01-08 15:20:35 +01:00
Kevin Papst
1aae4f4d0f fix first week in year shows wrong year (#2239) 2021-01-08 15:12:42 +01:00
Kevin Papst
244169d6d5 make sure to generate valid filenames (#2238) 2021-01-08 14:50:23 +01:00
Kevin Papst
a5fdf81df5 fix deprecations (#2225) 2020-12-27 20:47:09 +01:00
Kevin Papst
c1a54abc58 simplify html timesheet exporter (#2224) 2020-12-27 20:44:39 +01:00
Weblate (bot)
7e649dff3b Translations update from Weblate (#2195)
Co-authored-by: Jan Hladik <jan.hladik@iquentin.cz>
Co-authored-by: Anaa Ara <martakanuu@protonmail.com>
Co-authored-by: LL Magical <lolayami2004@gmail.com>
Co-authored-by: Jakub Fabijan <animatorzPolski@gmail.com>
Co-authored-by: Hahato Toshino <ameer.amino95@gmail.com>
Co-authored-by: Nathan <bonnemainsnathan@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: ikmaak <info@ikmaak.nl>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
2020-12-26 16:57:37 +01:00
Kevin Papst
40eda01c22 added export context (#2216) 2020-12-22 18:41:00 +01:00
Kevin Papst
74b3917e69 wrong decimal duration for more than 1000 hours (#2214) 2020-12-21 13:08:43 +01:00
Kevin Papst
6ada0b649c dashboard: fix years with 53 weeks (#2206) 2020-12-18 13:09:28 +01:00
Kevin Papst
e21fc656e4 replace striptags with validator (#2192) 2020-12-14 00:28:30 +01:00
Kevin Papst
f4f5c8fa88 escape configurable fields (#2191) 2020-12-13 03:15:46 +01:00
Kevin Papst
64d1aecf16 support mysqli in connection string (#2190) 2020-12-13 03:13:04 +01:00
Kevin Papst
26c2d5aa81 prepare release 1.12 (#2183)
* updated dependencies (#2125)
* display application name and version in console (#2150)
2020-12-10 16:25:14 +01:00
Weblate (bot)
78d8212e57 Translations update from Weblate (#2136)
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: koffevar <egor.kafisov@gmail.com>
Co-authored-by: Anaa Ara <martakanuu@protonmail.com>
Co-authored-by: 朱伟 <2676988242@qq.com>
Co-authored-by: yn <bilisenyou@outlook.com>
Co-authored-by: Woodyx <shiposhouyou@gmail.com>
Co-authored-by: thekeymethod <csokan.andras87@protonmail.ch>
Co-authored-by: Daniel de Souza Melo <jxzk@protonmail.com>
Co-authored-by: João Tiago Antunes <jtiago.cbr@gmail.com>
2020-12-10 15:06:10 +01:00
Kevin Papst
7a3388646b allow custom export repositories (#2182) 2020-12-10 15:00:14 +01:00
Kevin Papst
c3fe8d1c39 access custom-fields in twig invoice templates (#2168) 2020-12-09 10:49:48 +01:00
Kevin Papst
fcd9974a7c suppress notice for tempnam (#2166) 2020-12-09 10:01:50 +01:00
Kevin Papst
53dc322fd1 improve permission screen (#2177) 2020-12-09 01:17:48 +01:00
Kevin Papst
4cab1d323c remove support as issue types (#2173) 2020-12-08 23:11:48 +01:00
Kevin Papst
686d55de6e added config for issue templates (#2172) 2020-12-08 20:23:15 +01:00
Kevin Papst
0d2d40791a allow to reassign timesheets from delete-user form (#2159) 2020-12-03 22:52:58 +01:00
Kevin Papst
4302ecd6ea fixed broken test (#2151) 2020-11-29 19:40:51 +01:00
Weblate (bot)
fc12056ba2 updated polish translations (#2135)
Co-authored-by: Piotr Bub <pbubacz@live.com>
2020-11-21 11:43:42 +01:00
Weblate (bot)
72edce86ba Translations update from Weblate - Slovak 89% Romanian 100% (#2106)
Co-authored-by: MikeSierraRO <razvan@zeces.ro>
Co-authored-by: Anaa Ara <martakanuu@protonmail.com>
2020-11-17 11:51:42 +01:00
Kevin Papst
288fc5dd08 fix timezone for timesheets created by other users (#1509) 2020-11-13 17:46:32 +01:00
Kevin Papst
7503899a9b re-order fields in search form (#2120) 2020-11-12 11:14:43 +01:00
Kevin Papst
49a4d1069a sort teams alphabetically in team_list (#2119) 2020-11-12 11:03:37 +01:00
Kevin Papst
f916e0ce25 fix timesheet importer for entries passing midnight (#2098) 2020-11-10 16:02:30 +01:00
Kevin Papst
bd4efad22b added event to manage javascript translations (#2104) 2020-11-09 13:28:22 +01:00
Weblate (bot)
66865b553e updated Hebrew translations (#2102) 2020-11-09 10:08:09 +01:00
Weblate (bot)
62bfe0af2b updated Korean translations (#2093)
Co-authored-by: BeckeBauer <berko@gmx.de>
Co-authored-by: 김옥현 <dhrgusdlrns3@gmail.com>
2020-11-07 20:05:40 +01:00
Kevin Papst
db8714a87b fix styling issues in PDF invoice (#2097) 2020-11-07 19:31:18 +01:00
Kevin Papst
5868741fe3 use different event to reload recent activities (#2096) 2020-11-07 16:51:30 +01:00
Kevin Papst
08e284c51b sort composer packages in doctor (#2089) 2020-11-03 23:59:44 +01:00
Kevin Papst
1757ffd8ee improved api docs styling (#2085) 2020-11-02 10:58:38 +01:00
Weblate (bot)
2d3c46957f Translations update from Weblate (#2081)
Co-authored-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
2020-11-02 10:35:34 +01:00
Kevin Papst
ae0a6ebfb5 fix Sunday as first dow of week in date-picker (#2084) 2020-11-02 10:32:46 +01:00
Kevin Papst
aba06ba3f0 improve customer validation (#2083) 2020-11-02 00:50:26 +01:00
Weblate (bot)
b012332d82 Translations update from Weblate (#2071)
* Translated using Weblate (Portuguese (Brazil))
* Translated using Weblate (Dutch)
* Translated using Weblate (Portuguese)
* Translated using Weblate (Spanish)

Co-authored-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Co-authored-by: Leonardo Ferreira <miwibib401@ezeca.com>
Co-authored-by: Bruno Arakaki <brn.arakaki@gmail.com>
Co-authored-by: IxFail <mitchelnijkamp1@msn.com>
2020-10-30 13:22:34 +01:00
Kevin Papst
4a94525320 prepare release 1.11.1 (#2073) 2020-10-28 20:35:27 +01:00
Kevin Papst
1444593bbd validate color (#2072) 2020-10-28 20:01:08 +01:00
Kevin Papst
82e1d6b917 fix assertion deprecation (#2068) 2020-10-28 16:56:09 +01:00
Kevin Papst
61c0cbc887 fix auto-stop when starting timesheet with tags (#2067) 2020-10-27 18:35:22 +01:00
Weblate (bot)
8c39b4197e Translated using Weblate (French) (#2066)
Co-authored-by: Nathan <bonnemainsnathan@gmail.com>
2020-10-27 13:36:45 +01:00
Kevin Papst
e24c647b18 release 1.11 (#2063) 2020-10-26 12:55:24 +01:00
Kevin Papst
6db21d7b34 fix xss (#2060) 2020-10-26 11:35:31 +01:00
Kevin Papst
7ae55c1980 switch to php workflow v2 (#2061) 2020-10-26 11:21:03 +01:00
IxFail
bd167b6088 Dutch translation update (#2058) 2020-10-26 01:28:46 +01:00
vilu85
b9b7bf845c Finnish translations (#2046) 2020-10-26 00:27:10 +01:00
Weblate (bot)
fc5ebb619e Translations update from Weblate (#2011)
Co-authored-by: Bruno Arakaki <brn.arakaki@gmail.com>
Co-authored-by: Katarzyna Sobolewska <kasia.sobolewska1@gmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: aquilesi8 <adamdavies7@protonmail.com>
Co-authored-by: koffevar <egor.kafisov@gmail.com>
Co-authored-by: Nathan <bonnemainsnathan@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Oğuz Ersen <oguzersen@protonmail.com>
Co-authored-by: David Ordás <davorpatech@gmail.com>
Co-authored-by: iglv <ilv0609@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2020-10-25 23:15:46 +01:00
Kevin Papst
abd31e3785 allow to configure database version via ENV var (#2055) 2020-10-24 21:00:43 +02:00
Kevin Papst
8a8f5cb6ce Fix Composer 2 compatibility (#2056) 2020-10-24 19:33:49 +02:00
Kevin Papst
2ad8f8a4bb prevent export and invoice from breaking on equal sign (#2054) 2020-10-23 02:00:50 +02:00
Kevin Papst
4533c994a3 SQL and performance improvements (#2017) 2020-10-23 00:31:53 +02:00
Kevin Papst
6ed7ee76e7 support custom fields in timesheet batch update (#2043) 2020-10-21 17:10:11 +02:00
Kevin Papst
167a826f50 improved timesheet importer (#2049) 2020-10-21 11:44:07 +02:00
Kevin Papst
032db11b48 added dateformat and timezone options to project importer (#2042) 2020-10-16 12:53:33 +02:00
Kevin Papst
996f05c73a added project importer and grandtotal converter (#1468) 2020-10-11 22:08:00 +02:00
Kevin Papst
0ce02b4f06 some arbitrary improvements (#2032)
* show version in doctor
* added flag to import activities as global
2020-10-08 17:17:21 +02:00
Kevin Papst
fb31319fcf open create form for activity/project/customer in modals (#2025) 2020-10-08 01:12:34 +02:00
Kevin Papst
46bf01d93e lifecycle events for projects (#2013) 2020-10-07 19:44:55 +02:00
Kevin Papst
c2ec15aeb3 add a i18n api field for the users "now" datetime (#2007) 2020-10-07 00:04:20 +02:00
Kacper Rogula
bb97611349 Execute migrations in kimai:reset-dev command (#1982) 2020-10-03 14:56:51 +02:00
Kevin Papst
825e492891 Notifications by SweetAlert2 (#1508) 2020-10-02 19:37:30 +02:00
Kevin Papst
0aa6baea2f explain limited access if project or customer has team permission (#2006) 2020-10-01 19:16:31 +02:00
Weblate (bot)
cafd84cee4 Translations update from Weblate (#1994)
Co-authored-by: Nathan <bonnemainsnathan@gmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Balázs Fülöp <fulopbalazs91@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Juri Grabowski <hosted-weblate@jugra.de>
Co-authored-by: Katarzyna Sobolewska <kasia.sobolewska1@gmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: Péter Gyetvai <gyetpet@mailbox.org>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2020-10-01 10:52:11 +02:00
Kevin Papst
0751c14907 highlight reporting in navigation for user-by-week report (#2005) 2020-09-30 18:47:17 +02:00
Kevin Papst
de0a9f8303 Fix user-email validation (#2004) 2020-09-30 18:38:34 +02:00
Kevin Papst
145116f657 fix backdrop location of sweetalert2 modals (#1997) 2020-09-28 19:22:53 +02:00
Kevin Papst
6a8c820e09 Update issue templates 2020-09-25 23:58:22 +02:00
Kevin Papst
2b033710e2 events: extend system configurations and set invoice formatter (#1995) 2020-09-25 19:51:23 +02:00
Kevin Papst
23f484a14d fix restart timesheet with meta-fields (#1993) 2020-09-24 16:55:23 +02:00
Kevin Papst
4cfa7347e9 ascending order for invoice items in command (#1980) 2020-09-18 12:08:09 +02:00
Toby Batch
aa1ea98579 added cwd in kimai:reload command (#1951) 2020-09-18 11:53:53 +02:00
Kevin Papst
38249e6b5e base plugin installation command (#1953) 2020-09-18 01:10:48 +02:00
Kevin Papst
c02a882eff allow to decrement invoice counter (#1947)
* added increment for cc, ccy, ccn, ccd
2020-09-17 02:53:38 +02:00
Kevin Papst
9ef32e75c5 added drag and drop for new records via calendar (#1962) 2020-09-17 01:13:48 +02:00
Kevin Papst
14b3de4300 translation fixes for weblate compatibility (#1970) 2020-09-13 12:18:46 +02:00
Kevin Papst
02d54fd208 weblate compatibility (#1969) 2020-09-13 12:06:01 +02:00
Kevin Papst
d1e9e3e43f fixing "translation id" in hebrew and romanian (#1968) 2020-09-13 10:57:10 +02:00
Kevin Papst
f279302009 adjusted translation file references (#1966) 2020-09-13 01:44:45 +02:00
Kevin Papst
e2a742b5c1 cleanup global context (#1943) 2020-09-08 20:35:14 +02:00
Kevin Papst
217960de60 configure first day of week for calendar and date-picker (#1952) 2020-09-05 18:31:37 +02:00
Kevin Papst
ed528eb19a bump tests to phpstan level 5 (#1922) 2020-09-05 16:48:19 +02:00
Kevin Papst
b69ea0648c bugfix release 1.10.2 (#1942) 2020-08-30 12:19:20 +02:00
IxFail
193d193352 Dutch translation update (#1939) 2020-08-30 11:37:04 +02:00
Kevin Papst
8e801c6829 added support for ordering meta fields (#1940) 2020-08-30 11:24:12 +02:00
Kevin Papst
e7da2b408a fixing formatting issues for money without currency (#1932) 2020-08-29 16:30:35 +02:00
Luca Buoncristiani
14255d71f7 Update italian translations (1.10) (#1929)
Co-authored-by: Luca Buoncristiani <luca.buoncristiani@bonificaumbra.it>
2020-08-27 13:33:46 +02:00
2092 changed files with 148381 additions and 59523 deletions

View File

@@ -1,33 +1,30 @@
codecov:
notify:
require_ci_to_pass: yes
notify:
require_ci_to_pass: yes
coverage:
precision: 2
round: down
range: "80...100"
status:
project:
default:
threshold: 0.5%
patch:
default:
threshold: 50%
changes: no
precision: 2
round: down
range: "80...100"
status:
project:
default:
threshold: 0.5%
patch: off
changes: no
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "diff, flags, files"
behavior: default
require_changes: yes
require_base: no
require_head: yes
branches: null
layout: "diff, flags, files"
behavior: default
require_changes: yes
require_base: no
require_head: yes
branches: null

View File

@@ -1,34 +1,16 @@
# This file is a "template" of which env vars need to be defined for your application
# Copy this file to .env file for development, create environment variables when deploying to production
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
###> symfony/framework-bundle ###
APP_ENV=prod
APP_SECRET=change_this_to_something_unique
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
#TRUSTED_HOSTS=localhost,example.com
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data/kimai.sqlite"
# Configure your db driver and server_version in config/packages/doctrine.yaml
# DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/kimai.sqlite
###< doctrine/doctrine-bundle ###
###> nelmio/cors-bundle ###
CORS_ALLOW_ORIGIN=^https?://localhost(:[0-9]+)?$
###< nelmio/cors-bundle ###
### Email configuration
# SMTP: smtp://localhost:25?encryption=&auth_mode=
# Google: gmail://username:password@default
# Amazon: ses://ACCESS_KEY:SECRET_KEY@default?region=eu-west-1
# Mailchimp: mandrill://KEY@default
# Mailgun: mailgun://KEY:DOMAIN@default
# Postmark: postmark://ID@default
# Sendgrid: sendgrid://KEY@default
# Disable emails: null://null
MAILER_URL=null://null
# Configure your database connection and set the correct server version:
# for MySQL "serverVersion=5.7" and for MariaDB "serverVersion=mariadb-10.5.8"
DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8&serverVersion=5.7
# Email will be sent with this address as sender
MAILER_FROM=kimai@example.com
# Email connection (disabled by default) more info at https://www.kimai.org/documentation/emails.html
MAILER_URL=null://null
# do not change, unless you are developing for Kimai
APP_ENV=prod
# should be changed to a unique character sequence
APP_SECRET=change_this_to_something_unique
# unlikely, that you need to change this one
CORS_ALLOW_ORIGIN=^https?://localhost(:[0-9]+)?$
# Running behind reverse proxies? Use those:
# TRUSTED_PROXIES=127.0.0.1,127.0.0.2
# TRUSTED_HOSTS=localhost,example.com

View File

@@ -1,34 +0,0 @@
---
name: Bug report
about: Create a report to help us improve Kimai
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. See error
**Logfile**
```
Add the last lines from your logfile at var/log/prod.log, around the time when the problem happened.
```
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop/Smartphone**
Please complete the following information if this seems to be a frontend issue:
- Device: [e.g. iPhone6s]
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
- Kimai version
- PHP version

87
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,87 @@
name: Bug report
description: Create a report to help us improve Kimai
labels: [ "bug" ]
body:
- type: markdown
attributes:
value: |
Thank you for reporting an issue on Kimai! This form will guide you to create a useful issue report.
- type: textarea
id: what-happened
attributes:
label: Describe the issue
description: A clear and concise description of the problem you are facing.
placeholder: Tell us what you see!
validations:
required: true
- type: checkboxes
id: tried
attributes:
label: I already tried
description: If you didnt try already, try to search the documentation and existing issues what you wrote above.
options:
- label: I've read and searched [the documentation](https://www.kimai.org/documentation/).
required: true
- label: I've searched for similar issues in this repository.
required: true
- label: I've searched for similar issues in [the discussions](https://github.com/kevinpapst/kimai2/discussions).
required: true
- type: input
id: version
attributes:
label: Kimai version
description: Which version of Kimai are you running (check Doctor or About screen)
placeholder: 1.xx.x
validations:
required: true
- type: dropdown
id: php
attributes:
label: Which PHP version are you using?
options:
- "7.3"
- "7.4"
- "8.0"
- "8.1"
- "8.2"
- Other (please mention below)
validations:
required: true
- type: dropdown
id: installation
attributes:
label: How do you run Kimai?
options:
- kimai.cloud service
- Self-Hosted
- Synology
- Other (please mention below)
validations:
required: true
- type: textarea
id: reproducer
attributes:
label: Steps to reproduce the behavior
value: |
1. Go to '...'
2. Scroll down to '...'
3. Click on '...'
4. See error
- type: textarea
id: logs
attributes:
label: Logfile
description: Please paste the last lines from your logfile at "var/log/prod.log" or "Doctor > Logs", around the time when the problem happened.
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to better explain your problem.
- type: textarea
id: additional
attributes:
label: Additional context
description: Add any other context about the problem here.
value: |
Device: [Ubuntu Laptop 16 inch, Windows Desktop 27 inch, iPhone 6s]
Browser [e.g. Firefox 81, Chrome 85, Safari 14]

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Read our documentation
url: https://www.kimai.org/documentation/
about: Save your time! There is an instant solution for many issues in the documentation.
- name: Docker image issue tracker
url: https://github.com/tobybatch/kimai2/issues
about: For issues specific for Kimai Docker deployment
- name: Ask a Question
url: https://github.com/kevinpapst/kimai2/discussions
about: Want to discuss something with a community? Do it in discussions!
- name: Get Professional support
url: https://www.kimai.org/store/custom-plugins.html
about: As a customer, you will always receive fast and helpful replies from the developer.

View File

@@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea to make Kimai better
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,34 @@
name: Feature request
description: Suggest an idea to make Kimai better
labels: [ "feature request" ]
body:
- type: markdown
attributes:
value: |
Thank you for reporting an issue on Kimai! This form will guide you to create a useful issue report.
- type: textarea
id: describe
attributes:
label: Describe the problem
description: >
Is your feature request related to a problem? If so, please provide
a clear and concise description of what the issue is.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what the new feature should do.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to better explain your problem.

24
.github/lock.yml vendored
View File

@@ -1,24 +0,0 @@
# Configuration for lock-threads - https://github.com/dessant/lock-threads
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 60
# Issues and pull requests with these labels will not be locked. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
If you use Kimai on a daily basis, please [consider donating](https://www.kimai.org/donate/) to
support further development of Kimai.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: false
# Limit to only `issues` or `pulls`
# only: pulls

47
.github/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
name-template: '$RESOLVED_VERSION'
tag-template: '$RESOLVED_VERSION'
categories:
- title: 'Enhancements'
labels:
- 'feature request'
- 'technical debt'
- 'translation'
- title: 'Fixed bugs'
labels:
- 'bug'
- title: 'Infrastructure'
labels:
- 'infrastructure'
exclude-labels:
- 'duplicate'
- 'invalid'
- 'wontfix'
- 'release'
exclude-contributors:
- 'dependabot'
change-template: '- $TITLE (#$NUMBER)'
change-title-escapes: '\<*_&`#@'
version-resolver:
minor:
labels:
- 'feature request'
- 'release'
patch:
labels:
- 'technical debt'
- 'bug'
- 'translation'
default: patch
template: |
[Upgrade Kimai](https://www.kimai.org/documentation/updates.html) - [Install Kimai](https://www.kimai.org/documentation/installation.html) - [Docker](https://tobybatch.github.io/kimai2/)
**PHP Version compatibility:**
- PHP 7.3 is [end-of-life](https://www.php.net/supported-versions.php)
- PHP 7.4 is [end-of-life](https://www.php.net/supported-versions.php) in a few days!
- PHP 8.0 and PHP 8.1 are supported
**Next release will be PHP 8 ONLY, as [announced one year ago](https://www.kimai.org/blog/2021/sunsetting-php-7/).**
$CHANGES
Involved in this release: $CONTRIBUTORS - thank you!

View File

@@ -1,4 +1,4 @@
name: CI
name: Coverage
on:
pull_request: null
push:
@@ -7,29 +7,63 @@ on:
jobs:
tests:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
env:
MYSQL_ALLOW_EMPTY_PASSWORD: false
MYSQL_ROOT_PASSWORD: kimai
MYSQL_DATABASE: kimai
ports:
- 3306/tcp
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
matrix:
php: ['7.3']
php: ['8.0']
name: Coverage - PHP ${{ matrix.php }}
name: Coverage (${{ matrix.php }})
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v1
- name: Clone Kimai
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: pcov
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, mysql, zip, gd, ldap
- run: |
composer install --no-progress
composer require laminas/laminas-ldap
extensions: mbstring, xml, ctype, iconv, intl, mysql, zip, gd, ldap
- name: Determine composer cache directory
id: composer-cache
run: "echo \"::set-output name=directory::$(composer config cache-dir)\""
- name: Cache Composer dependencies
uses: actions/cache@v2
with:
path: "${{ steps.composer-cache.outputs.directory }}"
key: ${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
- name: Install dependencies
run: composer install
- name: Install LDAP package
run: composer require laminas/laminas-ldap
- name: Setup problem matchers for PHPUnit
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- name: Run tests
run: vendor/bin/phpunit tests/ --coverage-clover=coverage.xml
env:
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?serverVersion=5.7
APP_ENV: dev
MAILER_URL: null://localhost
TEST_WITH_BUNDLES: 1
- name: Upload code coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
files: ./coverage.xml
fail_ci_if_error: true

17
.github/workflows/docker.yaml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: 'Docker Build'
on:
release:
types: [released]
jobs:
build:
name: Dispatch release event to tobybatch
runs-on: ubuntu-latest
steps:
- name: Emit repository_dispatch
uses: mvasigh/dispatch-action@1.1.6
with:
token: ${{ secrets.DOCKER_ACCESS_TOKEN }}
repo: kimai2
owner: tobybatch
event_type: kimai_release

View File

@@ -1,28 +0,0 @@
name: CI
on:
pull_request: null
push:
branches:
- master
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['7.4']
name: Linting - PHP ${{ matrix.php }}
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v1
with:
php-version: ${{ matrix.php }}
coverage: none
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, mysql, zip, gd, ldap
tools: cs2pr:1.1.0
- run: composer install --no-progress
- run: composer validate --no-check-all --strict
- run: vendor/bin/php-cs-fixer fix --dry-run --verbose --config=.php_cs.dist --using-cache=no --show-progress=none --format=checkstyle | cs2pr
- run: vendor/bin/phpstan analyse src -c phpstan.neon --level=5 --no-progress --error-format=checkstyle | cs2pr
- run: vendor/bin/phpstan analyse tests -c tests/phpstan.neon --level=4 --no-progress --error-format=checkstyle | cs2pr
- run: composer kimai:code-lint

56
.github/workflows/lock.yaml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: 'Lock Threads'
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
concurrency:
group: lock
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v3
with:
github-token: ${{ github.token }}
issue-inactive-days: '180'
exclude-issue-created-before: ''
exclude-issue-created-after: ''
exclude-issue-created-between: ''
exclude-issue-closed-before: ''
exclude-issue-closed-after: ''
exclude-issue-closed-between: ''
include-any-issue-labels: ''
include-all-issue-labels: ''
exclude-any-issue-labels: ''
add-issue-labels: ''
remove-issue-labels: ''
issue-comment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
If you use Kimai on a daily basis, please [consider donating](https://www.kimai.org/donate/) to
support further development of Kimai.
issue-lock-reason: 'resolved'
pr-inactive-days: '180'
exclude-pr-created-before: ''
exclude-pr-created-after: ''
exclude-pr-created-between: ''
exclude-pr-closed-before: ''
exclude-pr-closed-after: ''
exclude-pr-closed-between: ''
include-any-pr-labels: ''
include-all-pr-labels: ''
exclude-any-pr-labels: ''
add-pr-labels: ''
remove-pr-labels: ''
pr-comment: ''
pr-lock-reason: ''
process-only: ''
log-output: false

21
.github/workflows/lockfiles.yaml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Check .lock files
on:
pull_request: null
push:
branches:
- master
jobs:
lockfiles:
runs-on: ubuntu-latest
name: Verify lock file integrity
steps:
- name: Clone Kimai
uses: actions/checkout@v2
- name: Prevent file change
uses: xalvarez/prevent-file-change-action@v1
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
pattern: .*.lock
trustedAuthors: kevinpapst, dependabot

30
.github/workflows/release-drafter.yaml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Release Drafter
on:
push:
branches:
- master
permissions:
contents: read
jobs:
correct_repository:
permissions:
contents: none
runs-on: ubuntu-latest
steps:
- name: fail on fork
if: github.repository_owner != 'kevinpapst'
run: exit 1
update_release_draft:
permissions:
contents: write # for release-drafter/release-drafter to create a github release
pull-requests: write # for release-drafter/release-drafter to add label to PR
needs: correct_repository
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,11 +1,11 @@
name: CI
name: Tests
on:
pull_request: null
push:
branches:
- master
jobs:
tests:
integration:
runs-on: ubuntu-latest
services:
mysql:
@@ -19,40 +19,83 @@ jobs:
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
matrix:
php: ['7.2', '7.3', '7.4']
php: ['7.4', '8.0', '8.1']
name: Tests - PHP ${{ matrix.php }}
name: Integration (${{ matrix.php }})
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v1
- name: Clone Kimai
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, mysql, zip, gd, ldap
- run: |
composer install --no-progress
composer require laminas/laminas-ldap
extensions: mbstring, xml, ctype, iconv, intl, mysql, zip, gd, ldap
tools: cs2pr:1.1.0, symfony-cli
- name: Determine composer cache directory
id: composer-cache
run: "echo \"::set-output name=directory::$(composer config cache-dir)\""
- name: Cache Composer dependencies
uses: actions/cache@v2
with:
path: "${{ steps.composer-cache.outputs.directory }}"
key: ${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
- name: Install dependencies
run: composer install
- name: Validate Composer
run: composer validate --strict
- name: Warmup cache for PHPStan
run: APP_ENV=dev bin/console kimai:reload -n
- name: Check codestyles
run: vendor/bin/php-cs-fixer fix --dry-run --verbose --config=.php-cs-fixer.dist.php --using-cache=no --show-progress=none --format=checkstyle | cs2pr
- name: Run PHPStan on Codebase
run: vendor/bin/phpstan analyse src -c phpstan.neon --level=5 --no-progress --error-format=checkstyle | cs2pr
- name: Run PHPStan on Tests
run: vendor/bin/phpstan analyse tests -c tests/phpstan.neon --level=5 --no-progress --error-format=checkstyle | cs2pr
- name: Lint codebase
run: composer linting
- name: Check for security issues in packages
run: symfony security:check
- name: Install LDAP package
run: composer require laminas/laminas-ldap
- name: Setup problem matchers for PHPUnit
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- name: Run unit tests
run: composer kimai:tests-unit
env:
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?serverVersion=5.7
APP_ENV: dev
MAILER_URL: null://localhost
- name: Run integration tests
run: composer kimai:tests-integration
env:
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?serverVersion=5.7
APP_ENV: dev
MAILER_URL: null://localhost
- name: Run migrations on MySQL
run: |
bin/console doctrine:database:drop --if-exists --force -n
bin/console doctrine:database:create --if-not-exists -n
bin/console doctrine:migrations:migrate -n
bin/console doctrine:migrations:migrate first -n
env:
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?serverVersion=5.7
APP_ENV: dev
MAILER_URL: null://localhost
- name: Run migrations on SQLite
run: |
bin/console doctrine:database:create -n
bin/console doctrine:migrations:migrate -n
bin/console doctrine:migrations:migrate first -n
env:
DATABASE_URL: sqlite:///%kernel.project_dir%/var/data/kimai_migrations.sqlite
APP_ENV: dev
MAILER_URL: null://localhost
- name: Run integration tests
run: composer kimai:tests-integration

View File

@@ -1,5 +1,5 @@
unreleased=true
future-release=1.10.1
exclude-labels=duplicate,question,invalid,wontfix,release
enhancement_labels=>enhancement,Enhancement,feature request,translation i18n,technical debt
future-release=1.20
exclude-labels=duplicate,support,question,invalid,wontfix,release,waiting for feedback,documentation
enhancement_labels=>feature request,translation,technical debt,documentation
issues-wo-labels=false

32
.gitignore vendored
View File

@@ -1,45 +1,37 @@
# ========== KIMAI ==========
# some hosters require a htaccess to change the PHP version
.htaccess
.env-*
.idea/
.DS_Store
# for symfony local webserver
php.ini
!.gitkeep
/bin/*
!bin/console
/config/packages/local.yaml
/config/packages/*-local.yaml
/config/packages/*/local.yaml
/config/packages/*/*-local.yaml
!/bin/console
*local.yaml
/config/bundles-local.php
public/avatars/*.png
/public/avatars/*.png
templates/invoice/renderer/.~lock*
/templates/invoice/renderer/.~lock*
/translations/branding.*.xlf
/var/data/*
!/var/data/.gitkeep
!/var/data/kimai_test.sqlite
/var/coverage/
/var/cache/*
!var/cache/.gitkeep
/var/invoices/*
/var/export/*
/var/packages/*
!var/packages/.gitkeep
/var/plugins/*
!var/plugins/.gitkeep
/var/log/*
!var/log/.gitkeep
/var/sessions/*
!var/sessions/.gitkeep
/var/packages/*
/var/plugins/*
*.disabled
# ========== KIMAI ==========
###> symfony/framework-bundle ###
@@ -56,11 +48,11 @@ templates/invoice/renderer/.~lock*
###> friendsofphp/php-cs-fixer ###
.php_cs
.php_cs.cache
.php-cs-fixer.cache
###< friendsofphp/php-cs-fixer ###
###> symfony/phpunit-bridge ###
.phpunit
/phpunit.xml
###< symfony/phpunit-bridge ###
###> symfony/webpack-encore-bundle ###

View File

@@ -7,7 +7,8 @@ For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
COMMENT;
return PhpCsFixer\Config::create()
$fixer = new PhpCsFixer\Config();
$fixer
->setRiskyAllowed(true)
->setRules([
'encoding' => true,
@@ -19,7 +20,7 @@ return PhpCsFixer\Config::create()
'function_declaration' => true,
'indentation_type' => true,
'line_ending' => true,
'lowercase_constants' => true,
'constant_case' => ['case' => 'lower'],
'lowercase_keywords' => true,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'header_comment' => ['header' => $fileHeaderComment, 'separate' => 'both'],
@@ -46,7 +47,7 @@ return PhpCsFixer\Config::create()
'statements' => ['return'],
],
'cast_spaces' => true,
'class_attributes_separation' => ['elements' => ['method']],
'class_attributes_separation' => ['elements' => ['method' => 'one']],
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => true,
'function_typehint_space' => true,
@@ -100,7 +101,7 @@ return PhpCsFixer\Config::create()
],
'phpdoc_annotation_without_dot' => true,
'phpdoc_indent' => true,
'phpdoc_inline_tag' => true,
'phpdoc_inline_tag_normalizer' => true,
'phpdoc_no_access' => true,
'phpdoc_no_alias_tag' => true,
'phpdoc_no_empty_return' => false,
@@ -130,7 +131,7 @@ return PhpCsFixer\Config::create()
'standardize_increment' => true,
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline_array' => false,
'trailing_comma_in_multiline' => false,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'whitespace_after_comma_in_array' => true,
@@ -163,3 +164,5 @@ return PhpCsFixer\Config::create()
)
->setFormat('checkstyle')
;
return $fixer;

View File

@@ -1,135 +1,3 @@
# Changelog
## [1.10](https://github.com/kevinpapst/kimai2/tree/1.10)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.9...1.10)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.10)
## [1.9](https://github.com/kevinpapst/kimai2/tree/1.9)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.8...1.9)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.9)
## [1.8](https://github.com/kevinpapst/kimai2/tree/1.8)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.7...1.8)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.8)
## [1.7](https://github.com/kevinpapst/kimai2/tree/1.7)
[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)
## [1.6.2](https://github.com/kevinpapst/kimai2/tree/1.6.2)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.6.1...1.6.2)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.6.2)
## [1.6.1](https://github.com/kevinpapst/kimai2/tree/1.6.1)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.6...1.6.1)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.6.1)
## [1.6](https://github.com/kevinpapst/kimai2/tree/1.6)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.5...1.6)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.6)
## [1.5](https://github.com/kevinpapst/kimai2/tree/1.5)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.4.2...1.5)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.5)
## [1.4.2](https://github.com/kevinpapst/kimai2/tree/1.4)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.4.1...1.4.2)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.4.2)
## [1.4.1](https://github.com/kevinpapst/kimai2/tree/1.4)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.4...1.4.1)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.4.1)
## [1.4](https://github.com/kevinpapst/kimai2/tree/1.4)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.3...1.4)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.4)
## [1.3](https://github.com/kevinpapst/kimai2/tree/1.3)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.2...1.3)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.3)
## [1.2](https://github.com/kevinpapst/kimai2/tree/1.2)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.1...1.2)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.2)
## [1.1](https://github.com/kevinpapst/kimai2/tree/1.1)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.0.1...1.1)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.1)
## [1.0.1](https://github.com/kevinpapst/kimai2/tree/1.0.1)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/1.0...1.0.1)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.0.1)
## [1.0](https://github.com/kevinpapst/kimai2/tree/1.0)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.9...1.0)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/1.0)
## [0.9](https://github.com/kevinpapst/kimai2/tree/0.9)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.8.1...0.9)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.9)
## [0.8.1](https://github.com/kevinpapst/kimai2/tree/0.8.1)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.8...0.8.1)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.8.1)
## [0.8](https://github.com/kevinpapst/kimai2/tree/0.8)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.7...0.8)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.8)
## [0.7](https://github.com/kevinpapst/kimai2/tree/0.7)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.6.1...0.7)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.7)
## [0.6.1](https://github.com/kevinpapst/kimai2/tree/0.6.1)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.6...0.6.1)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.6.1)
## [0.6](https://github.com/kevinpapst/kimai2/tree/0.6)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.5...0.6)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.6)
## [0.5](https://github.com/kevinpapst/kimai2/tree/0.5)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.4...0.5)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.5)
## [0.4](https://github.com/kevinpapst/kimai2/tree/0.4)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.3...0.4)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.4)
## [0.3](https://github.com/kevinpapst/kimai2/tree/0.3)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.2...0.3)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.3)
## [0.2](https://github.com/kevinpapst/kimai2/tree/0.2)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.1...0.2)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.2)
## [0.1](https://github.com/kevinpapst/kimai2/tree/0.1)
Release notes including the changelog can be found [here](https://github.com/kevinpapst/kimai2/releases/tag/0.1)
See [GitHub release page](https://github.com/kevinpapst/kimai2/releases).

View File

@@ -1,55 +0,0 @@
# 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.
FROM php:7.2.9-apache-stretch AS tmp_kimai2_base
RUN apt update && \
apt install -y --allow-unauthenticated \
git \
haveged \
libicu-dev \
libjpeg-dev \
libldap2-dev \
libldb-dev \
libpng-dev \
mysql-client \
unzip \
wget \
zip \
&& \
EXPECTED_SIGNATURE="$(wget -q -O - https://composer.github.io/installer.sig)" && \
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
ACTUAL_SIGNATURE="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" && \
if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ]; then >&2 echo 'ERROR: Invalid installer signature'; rm composer-setup.php; exit 1; fi && \
php composer-setup.php --quiet && \
rm composer-setup.php && \
mv /var/www/html/composer.phar /usr/bin/composer && \
docker-php-ext-install \
gd \
intl \
ldap \
pdo_mysql \
zip && \
apt remove -y wget && \
apt -y autoremove && \
apt clean && \
cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini
FROM tmp_kimai2_base
RUN git clone https://github.com/kevinpapst/kimai2.git /opt/kimai && \
sed "s/prod/dev/g" /opt/kimai/.env.dist > /opt/kimai/.env && \
composer install --working-dir=/opt/kimai --dev --optimize-autoloader && \
/opt/kimai/bin/console doctrine:database:create && \
/opt/kimai/bin/console doctrine:schema:create && \
/opt/kimai/bin/console doctrine:migrations:version --add --all && \
/opt/kimai/bin/console cache:warmup && \
chown -R www-data:www-data /opt/kimai/var && \
chown www-data:www-data /opt/kimai/vendor/mpdf/mpdf/tmp
WORKDIR /opt/kimai
EXPOSE 8001
USER www-data
CMD /opt/kimai/bin/console server:run 0.0.0.0:8001

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017-2019 Kevin Papst @ https://www.kevinpapst.de
Copyright (c) 2017-2022 Kevin Papst @ https://www.kevinpapst.de
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,5 +1,3 @@
<h1 align="center">Kimai 2 - online time-tracker</h1>
<p align="center">
<img src="https://raw.githubusercontent.com/kimai/images/master/repository-header.png" alt="Kimai logo">
</p>
@@ -9,37 +7,41 @@
<a href="https://codecov.io/gh/kevinpapst/kimai2"><img alt="Code Coverage" src="https://codecov.io/gh/kevinpapst/kimai2/branch/master/graph/badge.svg"></a>
<a href="https://packagist.org/packages/kevinpapst/kimai2"><img alt="Latest stable version" src="https://poser.pugx.org/kevinpapst/kimai2/v/stable"></a>
<a href="https://packagist.org/packages/kevinpapst/kimai2"><img alt="License" src="https://poser.pugx.org/kevinpapst/kimai2/license"></a>
<a href="https://gitter.im/kimai2/support"><img alt="Gitter" src="https://badges.gitter.im/kimai2/support.svg"></a>
<a href="https://www.bountysource.com/teams/kimai2"><img alt="Bountysource" src="https://img.shields.io/bountysource/team/kimai2/activity"></a>
<a href="https://twitter.com/kimai_org" rel="me"><img alt="Twitter" src="https://img.shields.io/badge/follow-%40kimai__org-00acee"></a>
<a href="https://phpc.social/@kimai" rel="me"><img alt="Mastodon" src="https://img.shields.io/badge/toot-%40kimai-8c8dff"></a>
</p>
<h1 align="center">Kimai - time-tracker</h1>
Kimai is a free, open source and online time-tracking software designed for small businesses and freelancers.
It is built with modern technologies such as Symfony, Bootstrap, RESTful API, Doctrine, AdminLTE, Webpack, ES6 etc.
It is built with modern technologies such as [Symfony](https://github.com/symfony/symfony), [Bootstrap](https://github.com/twbs/bootstrap),
[RESTful API](https://github.com/FriendsOfSymfony/FOSRestBundle), [Doctrine](https://github.com/doctrine/),
[AdminLTE](https://github.com/kevinpapst/AdminLTEBundle/), [Webpack](https://github.com/webpack/webpack), ES6 and [many](composer.json) [more](package.json).
## Introduction
- [Home](https://www.kimai.org) - The house of Kimai
- [Blog](https://www.kimai.org/blog/) - Get the latest news
- [Documentation](https://www.kimai.org/documentation/) - Learn how to use
- [Translations](https://www.kimai.org/documentation/translations.html) - Kimai in your language
- [Migration](https://www.kimai.org/documentation/migration-v1.html) - Import data from v1
- [Home](https://www.kimai.org) - Kimai project homepage
- [Blog](https://www.kimai.org/blog/) - Read the latest news
- [Documentation](https://www.kimai.org/documentation/) - Learn how to use Kimai
- [Translations](https://hosted.weblate.org/projects/kimai/#languages) - Kimai in your language
- [Migration](https://www.kimai.org/documentation/migration-v1.html) - Import data from Kimai 1
### Requirements
- PHP 7.2.9 or higher
- Database (MySQL/MariaDB, SQLite for development)
- Webserver (nginx, Apache)
- A modern browser
- [Other libraries](https://www.kimai.org/download/)
- PHP 7.4, 8.0 or 8.1
- MariaDB or MySQL
- A webserver and subdomain
- PHP extensions: `gd`, `intl`, `json`, `mbstring`, `pdo`, `xsl`, `zip`
### About
This is the new version of the open source timetracker Kimai. It is stable and production ready, ships
with most advanced features from Kimai 1 and many new ones, including but not limited to:
The evolution of the most known(?) open source project time-tracker Kimai. It is stable, production ready and ships
with many advanced features, including but not limited to:
JSON API, invoicing, data exports, multi-timer and punch-in punch-out mode, tagging, multi-user and multi-timezones,
authentication via SAML/LDAP/Database, customizable role permissions, responsive and ready for your mobile device,
user specific rates, advanced search & filtering, money and time budgets with report, support for plugins and many more.
authentication via SAML/LDAP/Database, customizable role and team permissions, responsive and ready for your mobile device,
user/customer/project specific rates, advanced search & filtering, money and time budgets, reporting, support for plugins
and so many more.
## Installation
@@ -47,11 +49,10 @@ user specific rates, advanced search & filtering, money and time budgets with re
- [Docker](https://www.kimai.org/documentation/docker.html) - containerized
- [Development](https://www.kimai.org/documentation/installation.html#development-installation) - on your local machine
- [1-click installer](https://www.kimai.org/documentation/installation.html#hosting-and-1-click-installations) - hosted environments
- [FTP](https://www.kimai.org/documentation/installation.html#ftp-installation) - unfortunately still widely used ;-)
### Updating Kimai
- [Update Kimai](https://www.kimai.org/documentation/updates.html) - the documentation
- [Update Kimai](https://www.kimai.org/documentation/updates.html) - get the latest version
- [UPGRADING guide](UPGRADING.md) - version specific steps
### Plugins
@@ -64,19 +65,26 @@ user specific rates, advanced search & filtering, money and time budgets with re
You can see a rough development roadmap in the [Milestones](https://github.com/kevinpapst/kimai2/milestones) sections.
It is open for changes and input from the community, your [ideas and questions](https://github.com/kevinpapst/kimai2/issues) are welcome.
> Kimai 2 uses a rolling release concept for delivering updates.
> You can upgrade Kimai at any time, you don't need to wait for the next official release.
> The master branch is always deployable, release tags are only snapshots of the current development version.
> Kimai uses a rolling release concept for delivering updates.
> You don't have to wait for the next official release, upgrade it at any time from the master branch,
> which is always deployable - release tags are simple snapshots of the development version.
Release versions will be created on a regular base (approx. one release every 4-8 weeks).
Every code change, whether it's a new feature or a bug fix, will be done on the master branch.
Kimai is actively developed in my spare time and I put my effort into the software instead of backporting changes for old versions.
The only exception is a critical security issue, which I would fix in the latest stable version as well.
Release versions will be created on a regular basis, every couple of weeks.
Every code change, whether it's a new feature or a bugfix, will be done on the master branch.
Kimai is actively developed in my spare time, I put my effort into the software instead of back-porting changes.
## Credits
## Contributing
Kimai 2 is developed with modern frameworks like
[Symfony v4](https://github.com/symfony/symfony),
[Doctrine](https://github.com/doctrine/),
[AdminLTEBundle](https://github.com/kevinpapst/AdminLTEBundle/) (based on [AdminLTE theme](https://github.com/almasaeed2010/AdminLTE)) and
[many](composer.json) [more](package.json).
You want to contribute to this repository? This is so great!
The best way to start is to [open a new issue](https://github.com/kevinpapst/kimai2/issues) for bugs or feature requests or a [discussion](https://github.com/kevinpapst/kimai2/discussions) for questions, support and such.
In case you want to contribute, but you wouldn't know how, here are some suggestions:
- Spread the word: More user means more people testing and contributing to Kimai - which in turn means better stability and more and better features. Please vote for Kimai on platforms like Slant, Product Hunt, Softpedia or AlternativeTo, you can tweet about it, share it on LinkedIn, reddit or any of your favorite social media platforms. Every bit helps!
- Answer questions: You know the answer to another user's problem? Share your knowledge!
- Make a feature request: Something can be done better? Something essential missing? Let us know!
- Report bugs
- You don't have to be programmer to help. The documentation and translation could use some love as well.
- Sponsor the project, free software still costs money
There is one simple rule in our "Code of conduct": Don't be an ass!

View File

@@ -4,20 +4,21 @@
As announced in the [README](README.md) I only support the latest available release and master.
| Version | Supported |
| ------- | ------------------ |
| master | :white_check_mark: |
| 1.10 | :white_check_mark: |
| < 1.10 | :x: |
| Version | Supported |
|----------------------|--------------------|
| main/master branch | :white_check_mark: |
| latest minor release | :white_check_mark: |
| older releases | :x: |
## Reporting a Vulnerability
Please report any security related vulnerability in the [advisories section at GitHub](https://github.com/kevinpapst/kimai2/security/advisories) or via email to info@keleo.de or kpapst@gmx.net.
Please read the [Bughunter](https://www.kimai.org/documentation/bughunter.html) documentation before posting.
Xou can report any security related vulnerability in the [advisories section at GitHub](https://github.com/kevinpapst/kimai2/security/advisories) or via email to kpapst@gmx.net.
I will work as fast as I can to fix the problem and publish a bugfix release / security update.
Depending on the size of the required fixes, this might take a couple of hours or a couple of days.
You can expect that your message will be answered ASAP, but please take into account that I am living in the timezone Europe/Berlin.
You can expect that your message will be answered ASAP.
If your issue is valid and after I verified and fixed it, you will be mentioned in the release notes.
I am grateful for any (discrete) disclosure of vulnerabilities!
You will be mentioned in the release notes if your issue is valid.
I am grateful for any (discrete) disclosure of vulnerabilities!

View File

@@ -8,6 +8,65 @@ you can upgrade your Kimai installation to the latest stable release.
Check below if there are more version specific steps required, which need to be executed after the normal update process.
Perform EACH version specific task between your version and the new one, otherwise you risk data inconsistency or a broken installation.
## [1.16](https://github.com/kevinpapst/kimai2/releases/tag/1.16)
**DEVELOPER**
- Removed `formDateTime` field from API model `I18nConfig`
## [1.15](https://github.com/kevinpapst/kimai2/releases/tag/1.15)
**Many database changes: don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
Updating the database might take quite a while, depending on the amount of timesheet entries and speed of your database server (~1 minute per 100k records).
**ATTENTION**
- This release bumps the minimum required [PHP version to 7.3](https://www.kimai.org/blog/2021/php8-support-php72-dropped/)
- Self-registration is disabled by default
- Self-registration now always requires email confirmation
- All plugins that use own databases need to be updated as well
- Removed the YearChart widget and the related configs named `userRecapThisYear`, `userRecapLastYear`, `userRecapTwoYears`, `userRecapThreeYears`
**LDAP & SAML**
Please verify your config with the [LDAP](https://www.kimai.org/documentation/ldap.html) and [SAML](https://www.kimai.org/documentation/saml.html) documentation, especially:
- SAML users: activate it by setting the `kimai.saml.activate: true` config key
- LDAP users: activate it by setting the `kimai.ldap.activate: true` config key
- LDAP and SAML users need to remove the complete `security` section from their `local.yaml`
**DEVELOPER**
PHP 8 compatibility forced to upgrade MANY libraries, including but not limited to:
- Removed FOSUserBundle and hslavich/oneloginsaml
- Doctrine Migrations, whose new major version forces plugin updates
- Gedmo v3 (which include BC breaks in definitions)
- Doctrine DBAL and others, which required PHP 7.3 as well
**API BC break**: Due to team structure changes, it was impossible to keep the (writing) API structure. Please adjust your code accordingly!
## [1.14](https://github.com/kevinpapst/kimai2/releases/tag/1.14)
**CRITICAL BC break**: SQLite support was removed. If you are using SQLite, you have to [read this blog post](https://www.kimai.org/blog/2021/sqlite-and-ftp-support-removed/) and migrate to MySQL/MariaDB first!
**New database tables and fields: don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
Permission changes:
- `history_invoice` - removed permission entirely
## [1.13](https://github.com/kevinpapst/kimai2/releases/tag/1.13)
- Deprecated `now` variable in export templates: create it yourself with `{% set now = create_date('now', app.user) %}`
- Changed invoice filename generation (check if you use cronjob for invoices)
- **BC break**: duration entered as plain numbers will now be treated as decimal duration in hours instead of seconds
## [1.12](https://github.com/kevinpapst/kimai2/releases/tag/1.12)
- Export templates can now include items from plugins (eg. Expenses).
## [1.10](https://github.com/kevinpapst/kimai2/releases/tag/1.10)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
@@ -16,7 +75,7 @@ Perform EACH version specific task between your version and the new one, otherwi
- Sessions are now stored in the database (all users have to re-login after upgrade)
- New permissions: `lockdown_grace_timesheet`, `lockdown_override_timesheet`, `view_all_data`
- Fixed team permissions on user queries: depending on your previous team & permission setup your users might see less data (SUPER_ADMINS see all data, but new: ADMINS only see all data if they own the `view_all_data` permission)
- Markdown does not support headings any more, text like `# foo` is not converted to `<h1 id="foo">foo</h1>` anymore
- Markdown does not support headings anymore, text like `# foo` is not converted to `<h1 id="foo">foo</h1>` anymore
### Developer

View File

@@ -17,16 +17,22 @@ require('select2/dist/js/i18n/ar');
require('select2/dist/js/i18n/cs');
require('select2/dist/js/i18n/da');
require('select2/dist/js/i18n/de');
require('select2/dist/js/i18n/el');
require('select2/dist/js/i18n/es');
require('select2/dist/js/i18n/eu');
require('select2/dist/js/i18n/fa');
require('select2/dist/js/i18n/fi');
require('select2/dist/js/i18n/fr');
require('select2/dist/js/i18n/he');
require('select2/dist/js/i18n/hr');
require('select2/dist/js/i18n/hu');
require('select2/dist/js/i18n/it');
require('select2/dist/js/i18n/ja');
require('select2/dist/js/i18n/ko');
require('select2/dist/js/i18n/nb');
require('select2/dist/js/i18n/nl');
require('select2/dist/js/i18n/pl');
require('select2/dist/js/i18n/pt');
require('select2/dist/js/i18n/pt-BR');
require('select2/dist/js/i18n/ro');
require('select2/dist/js/i18n/ru');
@@ -42,18 +48,26 @@ require('moment/locale/ar');
require('moment/locale/cs');
require('moment/locale/da');
require('moment/locale/de');
require('moment/locale/de-at');
require('moment/locale/de-ch');
require('moment/locale/el');
require('moment/locale/eo');
require('moment/locale/es');
require('moment/locale/eu');
require('moment/locale/fa');
require('moment/locale/fi');
require('moment/locale/fo');
require('moment/locale/fr');
require('moment/locale/he');
require('moment/locale/hr');
require('moment/locale/hu');
require('moment/locale/it');
require('moment/locale/ja');
require('moment/locale/ko');
require('moment/locale/nb');
require('moment/locale/nl');
require('moment/locale/pl');
require('moment/locale/pt');
require('moment/locale/pt-br');
require('moment/locale/ro');
require('moment/locale/ru');
@@ -65,9 +79,6 @@ require('moment/locale/zh-cn');
require('daterangepicker');
const Sortable = require('sortablejs/Sortable.min');
global.Sortable = Sortable;
// ------ AdminLTE framework ------
require('./sass/bootstrap.scss');
require('./sass/fontawesome.scss');
@@ -87,6 +98,8 @@ require('./sass/app.scss');
require('./js/KimaiWebLoader.js');
global.KimaiPaginatedBoxWidget = require('./js/widgets/KimaiPaginatedBoxWidget').default;
global.KimaiReloadPageWidget = require('./js/widgets/KimaiReloadPageWidget').default;
global.KimaiCookies = require('./js/widgets/KimaiCookies').default;
global.KimaiStorage = require('./js/widgets/KimaiStorage').default;
// ------ Autocomplete for tags only ------
require('jquery-ui/ui/widgets/autocomplete');

View File

@@ -1,4 +1,7 @@
// can be removed, once fullcalendar was updated and works without draggable jquery ui objects
require('jquery-ui/ui/widgets/draggable');
require('fullcalendar');
require('fullcalendar/dist/gcal.min');
@@ -6,17 +9,24 @@ require('fullcalendar/dist/locale/ar');
require('fullcalendar/dist/locale/cs');
require('fullcalendar/dist/locale/da');
require('fullcalendar/dist/locale/de');
require('fullcalendar/dist/locale/de-at');
require('fullcalendar/dist/locale/de-ch');
require('fullcalendar/dist/locale/el');
require('fullcalendar/dist/locale/es');
require('fullcalendar/dist/locale/eu');
require('fullcalendar/dist/locale/fa');
require('fullcalendar/dist/locale/fi');
require('fullcalendar/dist/locale/fr');
require('fullcalendar/dist/locale/he');
require('fullcalendar/dist/locale/hr');
require('fullcalendar/dist/locale/hu');
require('fullcalendar/dist/locale/it');
require('fullcalendar/dist/locale/ja');
require('fullcalendar/dist/locale/ko');
require('fullcalendar/dist/locale/nb');
require('fullcalendar/dist/locale/nl');
require('fullcalendar/dist/locale/pl');
require('fullcalendar/dist/locale/pt');
require('fullcalendar/dist/locale/pt-br');
require('fullcalendar/dist/locale/ro');
require('fullcalendar/dist/locale/ru');

View File

@@ -36,6 +36,7 @@ import KimaiDatePicker from "./plugins/KimaiDatePicker";
import KimaiConfirmationLink from "./plugins/KimaiConfirmationLink";
import KimaiMultiUpdateTable from "./plugins/KimaiMultiUpdateTable";
import KimaiDateUtils from "./plugins/KimaiDateUtils";
import KimaiEscape from "./plugins/KimaiEscape";
export default class KimaiLoader {
@@ -48,19 +49,20 @@ export default class KimaiLoader {
new KimaiTranslation(translations)
);
kimai.registerPlugin(new KimaiEscape());
kimai.registerPlugin(new KimaiEvent());
kimai.registerPlugin(new KimaiAPI());
kimai.registerPlugin(new KimaiAlert());
kimai.registerPlugin(new KimaiDateUtils());
kimai.registerPlugin(new KimaiFormSelect('.selectpicker'));
kimai.registerPlugin(new KimaiConfirmationLink('confirmation-link'));
kimai.registerPlugin(new KimaiActiveRecordsDuration('[data-since]'));
kimai.registerPlugin(new KimaiActiveRecordsDuration());
kimai.registerPlugin(new KimaiDatatableColumnView('data-column-visibility'));
kimai.registerPlugin(new KimaiDateRangePicker('input[data-daterangepickerenable="on"]'));
kimai.registerPlugin(new KimaiDateTimePicker('input[data-datetimepicker="on"]'));
kimai.registerPlugin(new KimaiDatePicker('input[data-datepickerenable="on"]'));
kimai.registerPlugin(new KimaiDatatable('section.content', 'table.dataTable'));
kimai.registerPlugin(new KimaiToolbar('form.header-search', 'toolbar-action'));
kimai.registerPlugin(new KimaiToolbar('form.searchform', 'toolbar-action'));
kimai.registerPlugin(new KimaiSelectDataAPI('select[data-related-select]'));
kimai.registerPlugin(new KimaiAlternativeLinks('.alternative-link'));
kimai.registerPlugin(new KimaiAjaxModalForm('.modal-ajax-form'));

View File

@@ -42,7 +42,7 @@ export default class KimaiPlugin {
}
/**
* This function returns null, if xou call it BEFORE init().
* This function returns null, if you call it BEFORE init().
*
* @returns {KimaiContainer}
*/
@@ -50,4 +50,27 @@ export default class KimaiPlugin {
return this._core;
}
/**
* @param {string} name
* @returns {(string|number|boolean)}
*/
getConfiguration(name) {
return this.getContainer().getConfiguration().get(name);
}
/**
* @param {string} name
* @returns {KimaiPlugin}
*/
getPlugin(name) {
return this.getContainer().getPlugin(name);
}
/**
* @param {string} title
* @returns {string}
*/
escape(title) {
return this.getPlugin('escape').escapeForHtml(title);
};
}

View File

@@ -11,14 +11,25 @@
export default class KimaiTranslation {
/**
* @param {Array<string, string>} translations
*/
constructor(translations) {
this._translations = translations;
}
/**
* @param {string} name
* @returns {string}
*/
get(name) {
return this._translations[name];
}
/**
* @param {string} name
* @returns {boolean}
*/
has(name) {
return name in this._translations;
}

View File

@@ -33,7 +33,30 @@ export default class KimaiAPI extends KimaiPlugin {
});
}
post(url, data, callbackSuccess, callbackError) {
if (callbackError === null || callbackError === undefined) {
callbackError = this.getPostErrorHandler();
}
jQuery.ajax({
url: url,
headers: {
'X-AUTH-SESSION': true,
'Content-Type':'application/json'
},
method: 'POST',
data: data,
dataType: 'json',
success: callbackSuccess,
error: callbackError
});
}
patch(url, data, callbackSuccess, callbackError) {
if (callbackError === null || callbackError === undefined) {
callbackError = this.getPatchErrorHandler();
}
jQuery.ajax({
url: url,
headers: {
@@ -49,6 +72,10 @@ export default class KimaiAPI extends KimaiPlugin {
}
delete(url, callbackSuccess, callbackError) {
if (callbackError === null || callbackError === undefined) {
callbackError = this.getDeleteErrorHandler();
}
jQuery.ajax({
url: url,
headers: {
@@ -62,4 +89,64 @@ export default class KimaiAPI extends KimaiPlugin {
});
}
getDeleteErrorHandler() {
const self = this;
return function(xhr, err) {
self.handleError('action.delete.error', xhr, err);
};
}
getPatchErrorHandler() {
const self = this;
return function(xhr, err) {
self.handleError('action.update.error', xhr, err);
};
}
getPostErrorHandler() {
const self = this;
return function(xhr, err) {
self.handleError('action.update.error', xhr, err);
};
}
/**
* @param {string} message
* @param {jqXHR} xhr
* @param {string} err
*/
handleError(message, xhr, err) {
let resultError = err;
if (xhr.responseJSON && xhr.responseJSON.message) {
resultError = xhr.responseJSON.message;
// find validation errors
if (xhr.status === 400 && xhr.responseJSON.errors) {
let collected = ['<u>' + resultError + '</u>'];
// form errors that are not attached to a field (like extra fields)
if (xhr.responseJSON.errors.errors) {
for (let error of xhr.responseJSON.errors.errors) {
collected.push(error);
}
}
if (xhr.responseJSON.errors.children) {
for (let field in xhr.responseJSON.errors.children) {
let tmpField = xhr.responseJSON.errors.children[field];
if (tmpField.hasOwnProperty('errors') && tmpField.errors.length > 0) {
for (let error of tmpField.errors) {
collected.push(error);
}
}
}
}
if (collected.length > 0) {
resultError = collected;
}
}
} else if (xhr.status && xhr.statusText) {
resultError = '[' + xhr.status + '] ' + xhr.statusText;
}
this.getPlugin('alert').error(message, resultError);
}
}

View File

@@ -75,10 +75,7 @@ export default class KimaiAPILink extends KimaiPlugin {
if (attributes.msgError) {
message = attributes.msgError;
}
if (xhr.responseJSON && xhr.responseJSON.message) {
err = xhr.responseJSON.message;
}
alert.error(message, err);
API.handleError(message, xhr, err);
};
if (method === 'PATCH') {
@@ -87,6 +84,12 @@ export default class KimaiAPILink extends KimaiPlugin {
data = attributes.payload;
}
API.patch(url, data, successHandle, errorHandle);
} else if (method === 'POST') {
let data = {};
if (attributes.payload) {
data = attributes.payload;
}
API.post(url, data, successHandle, errorHandle);
} else if (method === 'DELETE') {
API.delete(url, successHandle, errorHandle);
}

View File

@@ -24,37 +24,39 @@ export default class KimaiActiveRecords extends KimaiPlugin {
}
init() {
const menu = document.querySelector(this.selector);
this.menu = document.querySelector(this.selector);
// the menu can be hidden if user has no permissions to see it
if (menu === null) {
if (this.menu === null) {
return;
}
const dropdown = menu.querySelector('ul.dropdown-menu');
this.attributes = dropdown.dataset;
this.itemList = dropdown.querySelector('li > ul.menu');
this.label = menu.querySelector('a > span.label');
this.attributes = this.menu.dataset;
const self = this;
const handle = function() { self.reloadActiveRecords(); };
document.addEventListener('kimai.timesheetUpdate', handle);
document.addEventListener('kimai.timesheetDelete', handle);
document.addEventListener('kimai.activityUpdate', handle);
document.addEventListener('kimai.activityDelete', handle);
document.addEventListener('kimai.projectUpdate', handle);
document.addEventListener('kimai.projectDelete', handle);
document.addEventListener('kimai.customerUpdate', handle);
}
emptyList() {
this.itemList.innerHTML = '';
document.addEventListener('kimai.customerDelete', handle);
}
_toggleMenu(hasEntries) {
const menu = document.querySelector(this.selector);
const menuEmpty = document.querySelector(this.selectorEmpty);
this.menu.style.display = hasEntries ? 'inline-block' : 'none';
if (!hasEntries) {
// make sure that template entries in the menu are removed, otherwise they
// might still be shown in the browsers title
for (let record of this.menu.querySelectorAll('[data-since]')) {
record.dataset['since'] = '';
}
}
menu.style.display = hasEntries ? 'inline-block' : 'none';
const menuEmpty = document.querySelector(this.selectorEmpty);
if (menuEmpty !== null) {
menuEmpty.style.display = !hasEntries ? 'inline-block' : 'none';
}
@@ -63,42 +65,52 @@ export default class KimaiActiveRecords extends KimaiPlugin {
setEntries(entries) {
this._toggleMenu(entries.length > 0);
const template = this.menu.querySelector('[data-template="active-record"]');
const label = this.menu.querySelector('a > span.label');
if (label !== null) {
label.innerText = entries.length === 0 ? '' : entries.length;
}
if (entries.length === 0) {
this.label.innerText = '';
this.emptyList();
return;
}
let htmlToInsert = '';
const durations = this.getContainer().getPlugin('timesheet-duration');
for (let timesheet of entries) {
htmlToInsert +=
`<li>` +
`<a href="${ this.attributes['href'].replace('000', timesheet.id) }" data-event="kimai.timesheetStop kimai.timesheetUpdate" class="api-link" data-method="PATCH" data-msg-error="timesheet.stop.error" data-msg-success="timesheet.stop.success">` +
`<div class="pull-left">` +
`<i class="${ this.attributes['icon'] } fa-2x"></i>` +
`</div>` +
`<h4>` +
`<span>${ timesheet.activity.name }</span>` +
`<small>` +
`<span data-title="true" data-since="${ timesheet.begin }" data-format="${ this.attributes['format'] }">${ durations.formatDuration(timesheet.duration, this.attributes['format']) }</span>` +
`</small>` +
`</h4>` +
`<p>${ timesheet.project.name } (${ timesheet.project.customer.name })</p>` +
`</a>` +
`</li>`;
}
if (this.label.dataset.warning < entries.length) {
this.label.classList = 'label label-danger';
if (template === null) {
this._replaceInNode(this.menu, entries[0]);
} else {
this.label.classList = 'label label-warning';
}
this.label.innerText = entries.length;
this.itemList.innerHTML = htmlToInsert;
const container = template.parentElement;
container.innerHTML = '';
durations.updateRecords();
for (let timesheet of entries) {
const newNode = template.cloneNode(true);
container.appendChild(this._replaceInNode(newNode, timesheet));
}
}
this.getContainer().getPlugin('timesheet-duration').updateRecords();
}
_replaceInNode(node, timesheet) {
const date = this.getContainer().getPlugin('date');
const allReplacer = node.querySelectorAll('[data-replacer]');
for (let node of allReplacer) {
const replacerName = node.dataset['replacer'];
if (replacerName === 'url') {
node.href = this.attributes['href'].replace('000', timesheet.id);
} else if (replacerName === 'activity') {
node.innerText = timesheet.activity.name;
} else if (replacerName === 'project') {
node.innerText = timesheet.project.name;
} else if (replacerName === 'customer') {
node.innerText = timesheet.project.customer.name;
} else if (replacerName === 'duration') {
node.dataset['since'] = timesheet.begin;
node.innerText = date.formatDuration(timesheet.duration);
}
}
return node;
}
reloadActiveRecords() {

View File

@@ -9,21 +9,16 @@
* [KIMAI] KimaiActiveRecordsDuration: activate the updates for all active timesheet records on this page
*/
import moment from 'moment';
import KimaiPlugin from '../KimaiPlugin';
export default class KimaiActiveRecordsDuration extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
getId() {
return 'timesheet-duration';
}
init() {
this.updateBrowserTitle = !!this.getConfiguration('updateBrowserTitle');
this.updateRecords();
const self = this;
const handle = function() { self.updateRecords(); };
@@ -38,20 +33,29 @@ export default class KimaiActiveRecordsDuration extends KimaiPlugin {
updateRecords() {
let durations = [];
const activeRecords = document.querySelectorAll(this.selector);
const activeRecords = document.querySelectorAll('[data-since]:not([data-since=""])');
if (activeRecords.length === 0) {
document.title = document.querySelector('body').dataset['title'];
if (this.updateBrowserTitle) {
if (document.body.dataset['title'] === undefined) {
this.updateBrowserTitle = false;
} else {
document.title = document.body.dataset['title'];
}
}
return;
}
for(let record of activeRecords) {
const since = record.getAttribute('data-since');
const format = record.getAttribute('data-format');
const duration = this.formatDuration(since, format);
if (record.getAttribute('data-title') !== null && duration !== '?') {
const DATE = this.getPlugin('date');
for (let record of activeRecords) {
const since = record.dataset['since'];
const duration = DATE.formatDuration(since);
// only use the ones from the menu for the title
if (record.dataset['replacer'] !== undefined && record.dataset['title'] !== null && duration !== '?') {
durations.push(duration);
}
// but update all on the page (running entries in list pages)
record.textContent = duration;
}
@@ -59,6 +63,10 @@ export default class KimaiActiveRecordsDuration extends KimaiPlugin {
return;
}
if (!this.updateBrowserTitle) {
return;
}
let title = durations.shift();
let prefix = ' | ';
@@ -67,23 +75,4 @@ export default class KimaiActiveRecordsDuration extends KimaiPlugin {
}
document.title = title;
}
formatDuration(since, format) {
const duration = moment.duration(moment(new Date()).diff(moment(since)));
let hours = parseInt(duration.asHours()).toString();
let minutes = duration.minutes();
let seconds = duration.seconds();
if (hours < 0 || minutes < 0 || seconds < 0) {
return '?';
}
// special case for hours, as they can overflow the 24h barrier - Kimai does not support days as duration unit
if (hours.length === 1) {
hours = '0' + hours;
}
return format.replace('%h', hours).replace('%m', ('0'+minutes).substr(-2)).replace('%s', ('0'+seconds).substr(-2));
}
}

View File

@@ -28,24 +28,31 @@ export default class KimaiAjaxModalForm extends KimaiReducedClickHandler {
init() {
const self = this;
this.isDirty = false;
this.modal = jQuery('#remote_form_modal');
this.modal.on('hide.bs.modal', function () {
self.getContainer().getPlugin('event').trigger('modal-hide');
});
this.modal.on('hidden.bs.modal', function () {
// kill all references, so GC can kick in
self.getContainer().getPlugin('form').destroyForm(self._getFormIdentifier());
jQuery('#remote_form_modal .modal-body').replaceWith('');
});
this.modal.on('show.bs.modal', function () {
self.getContainer().getPlugin('event').trigger('modal-show');
});
this.modal.on('shown.bs.modal', function () {
// workaround for autofocus attribute, as the modal "steals" it
jQuery(self._getFormIdentifier()).find('input[type=text],textarea,select').filter(':not("[data-datetimepicker=on]")').filter(':visible:first').focus().delay(1000).focus();
});
this.modal
.on('hide.bs.modal', function (e) {
if (self.isDirty) {
if (jQuery('#remote_form_modal .modal-body .remote_modal_is_dirty_warning').length === 0) {
const msg = self.getContainer().getTranslation().get('modal.dirty');
jQuery('#remote_form_modal .modal-body').prepend('<p class="'+(self.modal.hasClass('modal-danger') ? 'well well-sm ' : '') + 'text-danger small remote_modal_is_dirty_warning">' + msg + '</p>');
}
e.preventDefault();
return;
}
jQuery(self._getFormIdentifier()).off('change', self._isDirtyHandler);
self.isDirty = false;
self.getContainer().getPlugin('event').trigger('modal-hide');
})
.on('hidden.bs.modal', function () {
// kill all references, so GC can kick in
self.getContainer().getPlugin('form').destroyForm(self._getFormIdentifier());
jQuery('#remote_form_modal .modal-body').replaceWith('');
})
.on('show.bs.modal', function () {
self.getContainer().getPlugin('event').trigger('modal-show');
});
this._addClickHandler(this.selector, function(href) {
self.openUrlInModal(href);
@@ -97,8 +104,8 @@ export default class KimaiAjaxModalForm extends KimaiReducedClickHandler {
form.off('submit');
// load new form from given content
if (jQuery(html).find('#form_modal .modal-content').length > 0 ) {
// switch classes, in case the modal type changed
if (jQuery(html).find('#form_modal .modal-content').length > 0) {
// Support changing modal importance/types
remoteModal.on('hidden.bs.modal', function () {
if (remoteModal.hasClass('modal-danger')) {
remoteModal.removeClass('modal-danger');
@@ -109,10 +116,24 @@ export default class KimaiAjaxModalForm extends KimaiReducedClickHandler {
remoteModal.addClass('modal-danger');
}
// Support changing modal sizes
let modalDialog = remoteModal.find('.modal-dialog');
let largeModal = jQuery(html).find('.modal-dialog').hasClass('modal-lg');
if (largeModal && !modalDialog.hasClass('modal-lg')) {
modalDialog.addClass('modal-lg');
}
if (!largeModal && modalDialog.hasClass('modal-lg')) {
modalDialog.removeClass('modal-lg');
}
jQuery('#remote_form_modal .modal-content').replaceWith(
jQuery(html).find('#form_modal .modal-content')
);
jQuery('#remote_form_modal [data-dismiss=modal]').on('click', function() {
self.isDirty = false;
});
// activate new loaded widgets
self.getContainer().getPlugin('form').activateForm(formIdentifier);
}
@@ -133,14 +154,24 @@ export default class KimaiAjaxModalForm extends KimaiReducedClickHandler {
});
// -----------------------------------------------------------------------
this.getContainer().getPlugin('toolbar').hide();
remoteModal.modal('show');
// the new form that was loaded via ajax
form = jQuery(formIdentifier);
this._isDirtyHandler = function(e) {
self.isDirty = true;
}
form.on('change', this._isDirtyHandler);
// click handler for modal save button, to send forms via ajax
form.on('submit', function(event){
form.on('submit', function(event) {
// if the form has a target, we let the normal HTML flow happen
if (form.attr('target') !== undefined) {
return true;
}
// otherwise we do some AJAX magic to process the form in the background
const btn = jQuery(formIdentifier + ' button[type=submit]').button('loading');
const eventName = form.attr('data-form-event');
const events = self.getContainer().getPlugin('event');
@@ -181,6 +212,7 @@ export default class KimaiAjaxModalForm extends KimaiReducedClickHandler {
if (msg === null || msg === undefined) {
msg = 'action.update.success';
}
self.isDirty = false;
remoteModal.modal('hide');
alert.success(msg);
}

View File

@@ -18,6 +18,10 @@ export default class KimaiAlert extends KimaiPlugin {
return 'alert';
}
/**
* @param {string} title
* @param {string|array} message
*/
error(title, message) {
const translation = this.getContainer().getTranslation();
if (translation.has(title)) {
@@ -26,14 +30,48 @@ export default class KimaiAlert extends KimaiPlugin {
if (translation.has(message)) {
message = translation.get(message);
}
Swal.fire({
icon: 'error',
title: title.replace('%reason%', ''),
text: message,
});
if (Array.isArray(message)) {
Swal.fire({
icon: 'error',
title: title.replace('%reason%', ''),
html: message.join('<br>'),
});
} else {
Swal.fire({
icon: 'error',
title: title.replace('%reason%', ''),
text: message,
});
}
}
warning(message) {
this._show('warning', message);
}
success(message) {
this._toast('success', message);
}
info(message) {
this._show('info', message);
}
_show(type, message) {
const translation = this.getContainer().getTranslation();
if (translation.has(message)) {
message = translation.get(message);
}
Swal.fire({
icon: type,
title: message,
});
}
_toast(type, message) {
const translation = this.getContainer().getTranslation();
if (translation.has(message)) {
@@ -46,7 +84,7 @@ export default class KimaiAlert extends KimaiPlugin {
toast: true,
position: 'top',
showConfirmButton: false,
icon: 'success',
icon: type,
title: message,
});
}

View File

@@ -20,7 +20,7 @@ export default class KimaiAutocomplete extends KimaiPlugin {
}
init() {
this.minChars = this.getContainer().getConfiguration().get('autoComplete');
this.minChars = this.getConfiguration('autoComplete');
}
getId() {

View File

@@ -48,7 +48,7 @@ export default class KimaiConfirmationLink extends KimaiPlugin {
if (value) {
if (form === null) {
document.location = url;
} else {
} else {
if (url !== null) {
form.action = url;
}

View File

@@ -35,6 +35,8 @@ export default class KimaiDatatable extends KimaiPlugin {
const attributes = dataTable.dataset;
const events = attributes['reloadEvent'];
this.fixDropdowns();
if (events === undefined) {
return;
}
@@ -46,15 +48,12 @@ export default class KimaiDatatable extends KimaiPlugin {
document.addEventListener(eventName, handle);
}
if (this.getContainer().getConfiguration().get('autoReloadDatatable')) {
document.addEventListener('toolbar-change', handle);
} else {
document.addEventListener('pagination-change', handle);
document.addEventListener('filter-change', handle);
}
document.addEventListener('pagination-change', handle);
document.addEventListener('filter-change', handle);
}
reloadDatatable() {
const self = this;
const contentArea = this.contentArea;
const durations = this.getContainer().getPlugin('timesheet-duration');
const toolbarSelector = this.getContainer().getPlugin('toolbar').getSelector();
@@ -66,7 +65,7 @@ export default class KimaiDatatable extends KimaiPlugin {
// remove the empty fields to prevent errors
let formData = jQuery(toolbarSelector + ' :input')
.filter(function(index, element) {
return jQuery(element).val() != '';
return jQuery(element).val() !== '';
})
.serialize();
@@ -79,6 +78,7 @@ export default class KimaiDatatable extends KimaiPlugin {
jQuery(html).find(contentArea)
);
durations.updateRecords();
self.fixDropdowns();
},
error: function(xhr, err) {
form.submit();
@@ -86,4 +86,21 @@ export default class KimaiDatatable extends KimaiPlugin {
});
}
/**
* show dropdown menu upwards, if it is outside the visible viewport
*/
fixDropdowns() {
const docHeight = jQuery(document).height();
jQuery(this.selector + ' [data-toggle=dropdown]').each(function() {
const parent = jQuery(this).parent();
const menu = parent.find('.dropdown-menu');
if (parent && menu) {
if ((parent.offset().top + parent.outerHeight() + menu.outerHeight()) > docHeight) {
parent.addClass('dropup').removeClass('dropdown');
}
}
});
}
}

View File

@@ -44,7 +44,7 @@ export default class KimaiDatatableColumnView extends KimaiPlugin {
});
for (let checkbox of this.modal.querySelectorAll('form input[type=checkbox]')) {
checkbox.addEventListener('click', function () {
self.changeVisibility(checkbox.getAttribute('name'));
self.changeVisibility(checkbox.getAttribute('name'), checkbox.checked);
});
}
}
@@ -55,7 +55,7 @@ export default class KimaiDatatableColumnView extends KimaiPlugin {
for (let checkbox of form.querySelectorAll('input[type=checkbox]')) {
settings[checkbox.getAttribute('name')] = checkbox.checked;
}
Cookies.set(form.getAttribute('name'), JSON.stringify(settings), {expires: 365});
Cookies.set(form.getAttribute('name'), JSON.stringify(settings), {expires: 365, SameSite: 'Strict'});
jQuery(this.modal).modal('toggle');
}
@@ -70,24 +70,40 @@ export default class KimaiDatatableColumnView extends KimaiPlugin {
jQuery(this.modal).modal('toggle');
}
changeVisibility(columnName) {
const table = document.getElementById('datatable_' + this.id).getElementsByClassName('dataTable')[0];
let column = 0;
let foundColumn = false;
for (let columnElement of table.getElementsByTagName('th')) {
if (columnElement.getAttribute('data-field') === columnName) {
foundColumn = true;
break;
changeVisibility(columnName, checked) {
const tables = document.getElementsByClassName('datatable_' + this.id);
for (let tableBox of tables) {
let column = 0;
let foundColumn = false;
let table = tableBox.getElementsByClassName('dataTable')[0];
for (let columnElement of table.getElementsByTagName('th')) {
if (columnElement.getAttribute('data-field') === columnName) {
foundColumn = true;
break;
}
if (columnElement.getAttribute('colspan') !== null) {
console.log('Tables with colspans are not supported!');
}
column++;
}
column++;
}
if (!foundColumn) {
return;
}
if (!foundColumn) {
return;
}
for (let rowElement of table.getElementsByTagName('tr')) {
rowElement.children[column].classList.toggle('hidden');
for (let rowElement of table.getElementsByTagName('tr')) {
if (rowElement.children[column] === undefined) {
continue;
}
if (checked) {
rowElement.children[column].classList.remove('hidden');
} else {
rowElement.children[column].classList.add('hidden');
}
}
}
}

View File

@@ -11,7 +11,6 @@
import jQuery from 'jquery';
import KimaiPlugin from '../KimaiPlugin';
import moment from "moment";
export default class KimaiDatePicker extends KimaiPlugin {
@@ -27,6 +26,7 @@ export default class KimaiDatePicker extends KimaiPlugin {
activateDatePicker(selector) {
const TRANSLATE = this.getContainer().getTranslation();
const DATE_UTILS = this.getContainer().getPlugin('date');
const firstDow = this.getConfiguration('first_dow_iso') % 7;
jQuery(selector + ' ' + this.selector).each(function(index) {
let localeFormat = jQuery(this).data('format');
@@ -34,9 +34,10 @@ export default class KimaiDatePicker extends KimaiPlugin {
singleDatePicker: true,
showDropdowns: true,
autoUpdateInput: false,
drops: 'down',
locale: {
format: localeFormat,
firstDay: moment().startOf('week').format('d'),
firstDay: firstDow,
applyLabel: TRANSLATE.get('confirm'),
cancelLabel: TRANSLATE.get('cancel'),
customRangeLabel: TRANSLATE.get('customRange'),
@@ -45,6 +46,14 @@ export default class KimaiDatePicker extends KimaiPlugin {
}
});
jQuery(this).on('show.daterangepicker', function (ev, picker) {
if (picker.element.offset().top - jQuery(window).scrollTop() + picker.container.outerHeight() + 30 > jQuery(window).height()) {
// "up" is not possible here, because the code is triggered on many mobile phones and the picker then appears out of window
picker.drops = 'auto';
picker.move();
}
});
jQuery(this).on('apply.daterangepicker', function(ev, picker) {
jQuery(this).val(picker.startDate.format(localeFormat));
jQuery(this).trigger("change");
@@ -55,7 +64,6 @@ export default class KimaiDatePicker extends KimaiPlugin {
destroyDatePicker(selector) {
jQuery(selector + ' ' + this.selector).each(function(index) {
if (jQuery(this).data('daterangepicker') !== undefined) {
jQuery(this).daterangepicker('destroy');
jQuery(this).data('daterangepicker').remove();
}
});

View File

@@ -27,6 +27,7 @@ export default class KimaiDateRangePicker extends KimaiPlugin {
activateDateRangePicker(selector) {
const TRANSLATE = this.getContainer().getTranslation();
const DATE_UTILS = this.getContainer().getPlugin('date');
const firstDow = this.getConfiguration('first_dow_iso') % 7;
jQuery(selector + ' ' + this.selector).each(function(index) {
let localeFormat = jQuery(this).data('format');
@@ -35,8 +36,12 @@ export default class KimaiDateRangePicker extends KimaiPlugin {
rangesList[TRANSLATE.get('today')] = [moment(), moment()];
rangesList[TRANSLATE.get('yesterday')] = [moment().subtract(1, 'days'), moment().subtract(1, 'days')];
rangesList[TRANSLATE.get('thisWeek')] = [moment().startOf('week'), moment().endOf('week')];
rangesList[TRANSLATE.get('lastWeek')] = [moment().subtract(1, 'week').startOf('week'), moment().subtract(1, 'week').endOf('week')];
rangesList[TRANSLATE.get('thisWeek')] = [moment().startOf('isoWeek'), moment().endOf('isoWeek')];
rangesList[TRANSLATE.get('lastWeek')] = [moment().subtract(1, 'week').startOf('isoWeek'), moment().subtract(1, 'week').endOf('isoWeek')];
if (firstDow === 0) { // sunday = 0
rangesList[TRANSLATE.get('thisWeek')] = [moment().startOf('isoWeek').subtract(1, 'day'), moment().endOf('isoWeek').subtract(1, 'day')];
rangesList[TRANSLATE.get('lastWeek')] = [moment().subtract(1, 'week').startOf('isoWeek').subtract(1, 'day'), moment().subtract(1, 'week').endOf('isoWeek').subtract(1, 'day')];
}
rangesList[TRANSLATE.get('thisMonth')] = [moment().startOf('month'), moment().endOf('month')];
rangesList[TRANSLATE.get('lastMonth')] = [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')];
rangesList[TRANSLATE.get('thisYear')] = [moment().startOf('year'), moment().endOf('year')];
@@ -46,11 +51,12 @@ export default class KimaiDateRangePicker extends KimaiPlugin {
showDropdowns: true,
autoUpdateInput: false,
autoApply: false,
linkedCalendars: false,
linkedCalendars: true,
drops: 'down',
locale: {
separator: separator,
format: localeFormat,
firstDay: moment().startOf('week').format('d'),
firstDay: firstDow,
applyLabel: TRANSLATE.get('confirm'),
cancelLabel: TRANSLATE.get('cancel'),
customRangeLabel: TRANSLATE.get('customRange'),
@@ -61,6 +67,14 @@ export default class KimaiDateRangePicker extends KimaiPlugin {
alwaysShowCalendars: true
});
jQuery(this).on('show.daterangepicker', function (ev, picker) {
if (picker.element.offset().top - jQuery(window).scrollTop() + picker.container.outerHeight() + 30 > jQuery(window).height()) {
// "up" is not possible here, because the code is triggered on many mobile phones and the picker then appears out of window
picker.drops = 'auto';
picker.move();
}
});
jQuery(this).on('apply.daterangepicker', function(ev, picker) {
jQuery(this).val(picker.startDate.format(localeFormat) + ' - ' + picker.endDate.format(localeFormat));
jQuery(this).data('begin', picker.startDate.format(localeFormat));
@@ -73,7 +87,6 @@ export default class KimaiDateRangePicker extends KimaiPlugin {
destroyDateRangePicker(selector) {
jQuery(selector + ' ' + this.selector).each(function(index) {
if (jQuery(this).data('daterangepicker') !== undefined) {
jQuery(this).daterangepicker('destroy');
jQuery(this).data('daterangepicker').remove();
}
});

View File

@@ -25,20 +25,22 @@ export default class KimaiDateTimePicker extends KimaiPlugin {
activateDateTimePicker(selector) {
const TRANSLATE = this.getContainer().getTranslation();
const CONFIG = this.getContainer().getConfiguration();
const DATE_UTILS = this.getContainer().getPlugin('date');
const firstDow = this.getConfiguration('first_dow_iso') % 7;
const is24hours = this.getConfiguration('twentyFourHours');
jQuery(selector + ' ' + this.selector).each(function(index) {
let localeFormat = jQuery(this).data('format');
jQuery(this).daterangepicker({
singleDatePicker: true,
timePicker: true,
timePicker24Hour: CONFIG.get('twentyFourHours'),
timePicker24Hour: is24hours,
showDropdowns: true,
autoUpdateInput: false,
drops: 'down',
locale: {
format: localeFormat,
firstDay: moment().startOf('week').format('d'),
firstDay: firstDow,
applyLabel: TRANSLATE.get('confirm'),
cancelLabel: TRANSLATE.get('cancel'),
customRangeLabel: TRANSLATE.get('customRange'),
@@ -47,6 +49,14 @@ export default class KimaiDateTimePicker extends KimaiPlugin {
}
});
jQuery(this).on('show.daterangepicker', function (ev, picker) {
if (picker.element.offset().top - jQuery(window).scrollTop() + picker.container.outerHeight() + 30 > jQuery(window).height()) {
// "up" is not possible here, because the code is triggered on many mobile phones and the picker then appears out of window
picker.drops = 'auto';
picker.move();
}
});
jQuery(this).on('apply.daterangepicker', function(ev, picker) {
jQuery(this).val(picker.startDate.format(localeFormat));
jQuery(this).trigger("change");
@@ -57,7 +67,6 @@ export default class KimaiDateTimePicker extends KimaiPlugin {
destroyDateTimePicker(selector) {
jQuery(selector + ' ' + this.selector).each(function(index) {
if (jQuery(this).data('daterangepicker') !== undefined) {
jQuery(this).daterangepicker('destroy');
jQuery(this).data('daterangepicker').remove();
}
});

View File

@@ -18,6 +18,14 @@ export default class KimaiDateUtils extends KimaiPlugin {
return 'date';
}
/**
* @param {string} dateTime
* @returns {string}
*/
getFormattedDate(dateTime) {
return moment(dateTime).format(this.getConfiguration('formatDate'));
}
getWeekDaysShort() {
return moment.localeData().weekdaysShort();
}
@@ -26,4 +34,81 @@ export default class KimaiDateUtils extends KimaiPlugin {
return moment.localeData().months();
}
formatDuration(since) {
const duration = moment.duration(moment(new Date()).diff(moment(since)));
return this.formatMomentDuration(duration);
}
formatSeconds(seconds) {
const duration = moment.duration('PT' + seconds + 'S');
return this.formatMomentDuration(duration);
}
/**
* @param {moment.Duration} duration
* @returns {string|*}
*/
formatMomentDuration(duration) {
const hours = parseInt(duration.asHours());
const minutes = duration.minutes();
return this.formatTime(hours, minutes);
}
formatTime(hours, minutes) {
let format = this.getConfiguration('formatDuration');
if (hours < 0 || minutes < 0) {
hours = Math.abs(hours);
minutes = Math.abs(minutes);
if (minutes > 0 || hours > 0) {
format = '-' + format;
}
}
// special case for hours, as they can overflow the 24h barrier - Kimai does not support days as duration unit
if (hours < 10) {
hours = '0' + hours;
}
return format.replace('%h', hours).replace('%m', ('0' + minutes).substr(-2));
}
/**
* @param {string} duration
* @returns {int}
*/
getSecondsFromDurationString(duration)
{
duration = duration.trim().toUpperCase();
let momentDuration = moment.duration(NaN);
if (duration.indexOf(':') !== -1) {
momentDuration = moment.duration(duration);
} else if (duration.indexOf('.') !== -1 || duration.indexOf(',') !== -1) {
duration = duration.replace(/,/, '.');
duration = (parseFloat(duration) * 3600).toString();
momentDuration = moment.duration('PT' + duration + 'S');
} else if (duration.indexOf('H') !== -1 || duration.indexOf('M') !== -1 || duration.indexOf('S') !== -1) {
/* D for days does not work, because 'PT1H' but with days 'P1D' is used */
momentDuration = moment.duration('PT' + duration);
} else {
let c = parseInt(duration);
let d = parseInt(duration).toFixed();
if (!isNaN(c) && duration === d) {
duration = (c * 3600).toString();
momentDuration = moment.duration('PT' + duration + 'S');
}
}
if (!momentDuration.isValid()) {
return 0;
}
return momentDuration.asSeconds();
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.
*/
/*!
* [KIMAI] KimaiEscape: sanitize strings
*/
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiEscape extends KimaiPlugin {
getId() {
return 'escape';
}
/**
* @param {string} title
* @returns {string}
*/
escapeForHtml(title) {
const tagsToReplace = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
};
return title.replace(/[&<>]/g, function(tag) {
return tagsToReplace[tag] || tag;
});
};
}

View File

@@ -25,7 +25,7 @@ export default class KimaiEvent extends KimaiPlugin {
for(let event of name.split(' ')) {
let triggerEvent = new Event(event);
if (details !== undefined) {
triggerEvent = new CustomEvent(name, {detail: details});
triggerEvent = new CustomEvent(event, {detail: details});
}
document.dispatchEvent(triggerEvent);
}

View File

@@ -32,4 +32,25 @@ export default class KimaiForm extends KimaiPlugin {
this.getContainer().getPlugin('date-time-picker').destroyDateTimePicker(formSelector);
this.getContainer().getPlugin('date-range-picker').destroyDateRangePicker(formSelector);
}
/**
* @param {HTMLFormElement} form
* @param {Object} overwrites
* @returns {string}
*/
convertFormDataToQueryString(form, overwrites = {})
{
let serialized = [];
let data = new FormData(form);
for (const key in overwrites) {
data.set(key, overwrites[key]);
}
for (let row of data) {
serialized.push(encodeURIComponent(row[0]) + "=" + encodeURIComponent(row[1]));
}
return serialized.join('&');
}
}

View File

@@ -23,19 +23,21 @@ export default class KimaiFormSelect extends KimaiPlugin {
return 'form-select';
}
activateSelectPicker(selector, container) {
const elementSelector = this.selector;
let options = {};
if (container !== undefined) {
options = {
dropdownParent: $(container),
};
}
init() {
// selects the original value inside select2 dropdowns, as the "reset" event (the updated option)
// is not automatically catched by select2
jQuery('body').on('reset', 'form', function(event) {
setTimeout(function() {
jQuery(event.target).find(this.selector).trigger('change');
}, 10);
});
const self = this;
// Function to match the name of the parent and not only the names of the children
// Based on the original matcher function of Select2: https://github.com/select2/select2/blob/5765090318c4d382ae56463cfa25ba8ca7bdd495/src/js/select2/defaults.js#L272
// More information: https://select2.org/searching | https://github.com/select2/docs/blob/develop/pages/11.searching/docs.md
function matcher(params, data) {
this.matcher = function (params, data) {
// Always return the object if there is nothing to compare
if (jQuery.trim(params.term) === '') {
return data;
@@ -86,7 +88,7 @@ export default class KimaiFormSelect extends KimaiPlugin {
for (let c = data.children.length - 1; c >= 0; c--) {
let child = data.children[c];
let matches = matcher(newParams, child);
let matches = self.matcher(newParams, child);
// If there wasn't a match, remove the object in the array
if (matches === null) {
@@ -103,18 +105,56 @@ export default class KimaiFormSelect extends KimaiPlugin {
// If the option or its children do not contain the term, don't return anything
return null;
}
}
activateSelectPickerByElement(node, container) {
let options = {};
if (container !== undefined) {
options = {
dropdownParent: jQuery(container),
};
}
options = {...options, ...{
language: this.getContainer().getConfiguration().get('locale').replace('_', '-'),
language: this.getConfiguration('locale').replace('_', '-'),
theme: "bootstrap",
matcher: matcher
matcher: this.matcher,
dropdownAutoWidth: true,
width: "resolve"
}};
jQuery(selector + ' ' + elementSelector).select2(options);
jQuery('body').on('reset', 'form', function(event){
setTimeout(function() {
jQuery(event.target).find(elementSelector).trigger('change');
}, 10);
const element = jQuery(node);
if (node.dataset['renderer'] !== undefined && node.dataset['renderer'] === 'color') {
const templateResultFunc = function (state) {
return jQuery('<span><span style="background-color:'+state.id+'; width: 20px; height: 20px; display: inline-block; margin-right: 10px;">&nbsp;</span>' + state.text + '</span>');
};
const colorOptions = {...options, ...{
templateSelection: templateResultFunc,
templateResult: templateResultFunc
}};
element.select2(colorOptions);
} else {
element.select2(options);
}
// this is a bugfix for safari, which does render the dropdown only with correct width upon the second opening
// see https://github.com/select2/select2/issues/4678
element.on('select2:open', function (ev) {
if (element.data('performing-reopen') === undefined || element.data('performing-reopen') === null) {
element.data('performing-reopen', true);
element.select2('close');
element.select2('open');
}
});
}
activateSelectPicker(selector, container) {
const self = this;
jQuery(selector + ' ' + this.selector).each(function(i, el) {
self.activateSelectPickerByElement(el, container);
});
}
@@ -130,33 +170,57 @@ export default class KimaiFormSelect extends KimaiPlugin {
select.find('option').remove().end().find('optgroup').remove().end();
if (emptyOption.length !== 0) {
select.append('<option value="">' + emptyOption.text() + '</option>');
select.append(this._createOption(emptyOption.text(), ''));
}
let htmlOptions = '';
let emptyOptions = '';
let emptyOpts = [];
let options = [];
let titlePattern = null;
if (select[0] !== undefined && select[0].dataset !== undefined && select[0].dataset['optionPattern'] !== undefined) {
titlePattern = select[0].dataset['optionPattern'];
}
if (titlePattern === null || titlePattern === '') {
titlePattern = '{name}';
}
for (const [key, value] of Object.entries(data)) {
if (key === '__empty__') {
for (const entity of value) {
emptyOptions += '<option value="' + entity.id + '">' + entity.name + '</option>';
emptyOpts.push(this._createOption(this._getTitleFromPattern(titlePattern, entity), entity.id));
}
continue;
}
htmlOptions += '<optgroup label="' + key + '">';
let optGroup = this._createOptgroup(key);
for (const entity of value) {
htmlOptions += '<option value="' + entity.id + '">' + entity.name + '</option>';
optGroup.appendChild(this._createOption(this._getTitleFromPattern(titlePattern, entity), entity.id));
}
htmlOptions += '</optgroup>';
options.push(optGroup);
}
select.append(htmlOptions);
select.append(emptyOptions);
select.append(options);
select.append(emptyOpts);
// if available, re-select the previous selected option (mostly usable for global activities)
select.val(selectedValue);
// pre-select an option if it is the only available one
if (select.val() === '' || select.val() === null) {
const allOptions = select.find('option');
const optionLength = allOptions.length;
let selectOption = '';
if (optionLength === 1) {
selectOption = allOptions[0].value;
} else if (optionLength === 2 && emptyOption.length === 1) {
selectOption = allOptions[1].value;
}
if (selectOption !== '') {
select.val(selectOption);
}
}
// if we don't trigger the change, the other selects won't reset
select.trigger('change');
@@ -165,4 +229,70 @@ export default class KimaiFormSelect extends KimaiPlugin {
select.trigger('change.select2');
}
}
/**
* @param {string} pattern
* @param {array} entity
* @private
*/
_getTitleFromPattern(pattern, entity) {
const DATE_UTILS = this.getPlugin('date');
const regexp = new RegExp('{[^}]*?}','g');
let title = pattern;
let match = null;
while ((match = regexp.exec(pattern)) !== null) {
const field = match[0].substr(1, match[0].length - 2);
let value = entity[field] === undefined ? null : entity[field];
if ((field === 'start' || field === 'end')) {
if (value === null) {
value = '?';
} else {
value = DATE_UTILS.getFormattedDate(value);
}
}
title = title.replace(new RegExp('{' + field + '}', 'g'), value ?? '');
}
title = title.replace(/- \?-\?/, '');
title = title.replace(/\r\n|\r|\n/g, ' ');
title = title.substr(0, 110);
const chars = '- ';
let start = 0, end = title.length;
while (start < end && chars.indexOf(title[start]) >= 0) {
++start;
}
while (end > start && chars.indexOf(title[end - 1]) >= 0) {
--end;
}
return (start > 0 || end < title.length) ? title.substring(start, end) : title;
}
/**
* @param {string} label
* @param {string} value
* @returns {HTMLElement}
* @private
*/
_createOption(label, value) {
let option = document.createElement('option');
option.innerText = label;
option.value = value;
return option;
}
/**
* @param {string} label
* @returns {HTMLElement}
* @private
*/
_createOptgroup(label) {
let optGroup = document.createElement('optgroup');
optGroup.label = label;
return optGroup;
}
}

View File

@@ -40,10 +40,15 @@ export default class KimaiRecentActivities extends KimaiPlugin {
// don't block initial browser rendering
setTimeout(handle, 500);
document.addEventListener('kimai.timesheetStop', handle);
document.addEventListener('kimai.recentActivities', handle);
document.addEventListener('kimai.timesheetUpdate', handle);
document.addEventListener('kimai.timesheetDelete', handle);
document.addEventListener('kimai.activityUpdate', handle);
document.addEventListener('kimai.activityDelete', handle);
document.addEventListener('kimai.projectUpdate', handle);
document.addEventListener('kimai.projectDelete', handle);
document.addEventListener('kimai.customerUpdate', handle);
document.addEventListener('kimai.customerDelete', handle);
}
emptyList() {
@@ -60,9 +65,10 @@ export default class KimaiRecentActivities extends KimaiPlugin {
for (let timesheet of entries) {
let label = this.attributes['template']
.replace('%customer%', timesheet.project.customer.name)
.replace('%project%', timesheet.project.name)
.replace('%activity%', timesheet.activity.name);
.replace('%customer%', this.escape(timesheet.project.customer.name))
.replace('%project%', this.escape(timesheet.project.name))
.replace('%activity%', this.escape(timesheet.activity.name))
;
htmlToInsert +=
`<li>` +

View File

@@ -14,10 +14,10 @@ import KimaiPlugin from "../KimaiPlugin";
export default class KimaiReducedClickHandler extends KimaiPlugin {
_addClickHandler(selector, callback)  {
_addClickHandler(selector, callback) {
jQuery('body').on('click', selector, function(event) {
// just in case an inner element is editable, than this should not be triggered
if (event.target.parentNode.isContentEditable || event.target.isContentEditable) {
if (event.target.parentNode.isContentEditable || event.target.isContentEditable) {
return;
}
@@ -42,6 +42,10 @@ export default class KimaiReducedClickHandler extends KimaiPlugin {
href = jQuery(this).attr('href');
}
if (href === undefined || href === null || href === '') {
return;
}
callback(href);
});
}

View File

@@ -40,13 +40,13 @@ export default class KimaiSelectDataAPI extends KimaiPlugin {
return;
}
let formPrefix = jQuery(this).parents('form').first().attr('name');
let formPrefix = this.dataset['formPrefix'];
if (formPrefix === undefined || formPrefix === null) {
formPrefix = '';
} else {
} else if (formPrefix.length > 0) {
formPrefix += '_';
}
let newApiUrl = self._buildUrlWithFormFields(this.dataset['apiUrl'], formPrefix);
const selectValue = jQuery(this).val();
@@ -74,11 +74,11 @@ export default class KimaiSelectDataAPI extends KimaiPlugin {
let newApiUrl = apiUrl;
apiUrl.split('?')[1].split('&').forEach(item => {
let [key, value] = item.split('=');
let decoded = decodeURIComponent(value);
let test = decoded.match(/%(.*)%/);
const [key, value] = item.split('=');
const decoded = decodeURIComponent(value);
const test = decoded.match(/%(.*)%/);
if (test !== null) {
let targetField = jQuery('#' + formPrefix + test[1]);
const targetField = jQuery('#' + formPrefix + test[1]);
let newValue = '';
if (targetField.length === 0) {
// happens for example:
@@ -142,7 +142,9 @@ export default class KimaiSelectDataAPI extends KimaiPlugin {
ordered[key] = options[key];
});
this.getContainer().getPlugin('form-select').updateOptions(selectName, ordered);
/** @var {KimaiFormSelect} select */
const select = this.getContainer().getPlugin('form-select');
select.updateOptions(selectName, ordered);
}
}

View File

@@ -23,13 +23,38 @@ export default class KimaiThemeInitializer extends KimaiPlugin {
jQuery('[data-toggle="tooltip"]').tooltip();
// activate all form plugins
this.getContainer().getPlugin('form').activateForm('.content-wrapper form', 'body');
this.getContainer().getPlugin('form').activateForm('form.searchform', 'body');
this.registerModalAutofocus('#modal_search');
this.registerModalAutofocus('#remote_form_modal');
}
/**
* workaround for autofocus attribute, as the modal "steals" it
*
* @param {string} selector
*/
registerModalAutofocus(selector) {
let modal = jQuery(selector);
if (modal.length === 0) {
return;
}
modal.on('shown.bs.modal', function () {
let form = modal.find('form');
let formAutofocus = form.find('[autofocus]');
if (formAutofocus.length < 1) {
formAutofocus = form.find('input[type=text],textarea,select');
}
formAutofocus.filter(':not("[data-datetimepicker=on]")').filter(':visible:first').focus().delay(1000).focus();
});
}
/**
* redirect access denied / session timeouts to login page
*/
registerGlobalAjaxErrorHandler() {
const loginUrl = this.getContainer().getConfiguration().get('login');
const loginUrl = this.getConfiguration('login');
const alert = this.getContainer().getPlugin('alert');
const translation = this.getContainer().getTranslation().get('login.required');
jQuery(document).ajaxError(function(event, jqxhr, settings, thrownError) {

View File

@@ -32,32 +32,8 @@ export default class KimaiToolbar extends KimaiPlugin {
this._registerPagination(formSelector, EVENT);
this._registerSortableTables(formSelector, EVENT);
this._registerAlternativeSubmitActions(formSelector, this.actionClass);
this._registerSearchButtons(formSelector);
jQuery('body')
// prevent that the dropdown closes, when a form input is changed - eg. a select option was clicked
.on('click', formSelector + ' .dropdown-menu', function (event) {
event.stopPropagation();
})
// prevent that a click into the search field will close the dropdown
.on('click', '.select2-search__field', function (event) {
event.stopPropagation();
})
// prevent that the dropdown closes when a optgroup header is clicked
.on('click', '.select2-results__group', function (event) {
event.stopPropagation();
})
// prevent that a click into a daterangepicker will close the dropdown
.on('click', '.daterangepicker', function (event) {
event.stopPropagation();
})
// prevent that clicks in the dropdown elements, but outside of elements will close the dropdown (eg border besides the search field)
.on('click', '.select2-container', function (event) {
event.stopPropagation();
})
;
// Reset the page if filter values are changed, otherwise we might end up with a limited set of data,
// Reset the page if filter values are changed, otherwise we might end up with a limited set of data,
// which does not support the given page - and it would be just wrong to stay in the same page
jQuery(formSelector +' input').change(function (event) {
switch (event.target.id) {
@@ -95,38 +71,6 @@ export default class KimaiToolbar extends KimaiPlugin {
self.triggerChange();
}
});
// close all open selectpicker upon choosing any dropdown option
jQuery(formSelector + ' select.selectpicker').on('change', function(event) {
jQuery('.bootstrap-select.open').removeClass('open');
});
}
/**
* The search toggle button is not part of this component, but it is directly connected to it.
* @private
*/
_registerSearchButtons(formSelector) {
jQuery('body')
// only for mobile experience currently: show the search form field
.on('click', '.btn-search.search-toggle', function (event) {
event.preventDefault();
event.stopPropagation();
jQuery(formSelector).parent('section').toggleClass('search-open');
jQuery(formSelector).toggleClass('hidden-xs');
jQuery(formSelector + ' input#searchTerm').dropdown('toggle');
jQuery(formSelector + ' input#searchTerm').focus();
})
// hide the search form field
.on('click', formSelector + ' a.search-cancel', function (event) {
event.preventDefault();
event.stopPropagation();
jQuery(formSelector).parent('section').toggleClass('search-open');
jQuery(formSelector + ' input#searchTerm').dropdown('toggle');
jQuery(formSelector).toggleClass('hidden-xs');
})
;
}
/**
@@ -175,10 +119,14 @@ export default class KimaiToolbar extends KimaiPlugin {
if ($header.hasClass('sorting_desc')) {
order = 'ASC';
}
jQuery(formSelector + ' input#orderBy').val(orderBy);
jQuery(formSelector + ' input#order').val(order);
// triggers the page reset - see below
jQuery(formSelector + ' input#order').trigger('change');
jQuery(formSelector + ' #orderBy').val(orderBy);
jQuery(formSelector + ' #order').val(order);
// re-render the selectboxes
jQuery(formSelector + ' #orderBy').trigger('change');
jQuery(formSelector + ' #order').trigger('change');
// triggers the datatable reload - search for the event name
EVENT.trigger('filter-change');
});
@@ -206,13 +154,6 @@ export default class KimaiToolbar extends KimaiPlugin {
}
hide() {
const toggle = jQuery(this.getSelector() + ' #searchTerm.dropdown-toggle');
if (toggle.parent().hasClass('open')) {
toggle.dropdown('toggle');
}
}
/**
* Triggers an event, that everyone can listen for.
*/

View File

@@ -0,0 +1,28 @@
/*
* 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.
*/
/*!
* [KIMAI] KimaiCookies: simple wrapper to handle cookies
*/
import Cookies from 'js-cookie';
export default class KimaiCookies {
static set(name, values, options) {
Cookies.set(name, values, options);
}
static get(name) {
return Cookies.getJSON(name);
}
static remove(name) {
Cookies.remove(name);
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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.
*/
/*!
* [KIMAI] KimaiStorage: simple wrapper to handle localStorage access
*/
export default class KimaiStorage {
static set(name, values) {
window.localStorage.setItem(name, JSON.stringify(values));
}
static get(name) {
let value = window.localStorage.getItem(name);
if (value === undefined || value === null) {
return null;
}
return JSON.parse(value);
}
static remove(name) {
window.localStorage.removeItem(name);
}
}

View File

@@ -26,3 +26,9 @@
@import 'autocomplete';
@import 'selectpicker';
@import 'reporting';
@import 'forms';
@import 'modal';
@import 'progressbar';
@import 'avatar';
@import 'security';
@import 'tabs';

60
assets/sass/avatar.scss Normal file
View File

@@ -0,0 +1,60 @@
$avatar-base-size: 30;
.avatar {
text-align: center;
background-color: #d2d6de;
border-radius: 50%;
display: inline-block;
height: ($avatar-base-size)+px;
width: ($avatar-base-size)+px;
vertical-align: middle;
}
.initials {
line-height: 1;
position: relative;
font-weight: bold;
font-size: ceil($avatar-base-size / 2 - 2)+px;
top: floor($avatar-base-size / 4 - 1)+px;
}
$avatarSizes: "xs" .75, "sm" 1.25, "md" 1.5, "lg" 2;
@each $avatarSizeName, $avatarBaseSize in $avatarSizes {
.avatar-#{$avatarSizeName} {
width: ceil($avatar-base-size * $avatarBaseSize)+px;
height: ceil($avatar-base-size * $avatarBaseSize)+px;
.initials {
font-size: ceil($avatar-base-size * $avatarBaseSize / 2 - 2)+px;
top: ceil($avatar-base-size * $avatarBaseSize / 4 - 1)+px;
}
}
}
.widget-user-image {
border-radius: 50%;
border: 3px solid #fff;
.avatar {
width: ceil($avatar-base-size * 2.75)+px;
height: ceil($avatar-base-size * 2.75)+px;
.initials {
font-size: ceil($avatar-base-size * 2.75 / 2 - 2)+px;
top: ceil($avatar-base-size * 2.75 / 4 - 1)+px;
}
}
}
/* Detail tables like my teams (Dashboard) or */
table.dataTable.table > tbody > tr > td {
&.avatars {
.avatar {
margin: 1px;
}
}
}
.avatar.teamlead {
box-shadow: 0px 0px 5px 1px rgba(0,0,0,.4),0 0px 3px 0 rgba(0,0,0,0.3);
}

View File

@@ -1,6 +1,7 @@
.box {
/* used on detail pages for: customer, project and activity */
.box-body.no-padding div.comment {
.box-body.no-padding div.comment,
.box-body.no-padding .box-padding {
padding: 10px;
}

View File

@@ -6,3 +6,46 @@
}
}
}
/* Drag and Drop events with styling */
.external-events {
.external-event {
vertical-align: middle;
padding: 0 !important;
display: inline-block;
position: relative;
width: 100%;
}
.subtitle {
padding: 0 7px 4px 7px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.7em;
}
.title {
padding: 3px 7px 0;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.fc-bootstrap3 {
.table-bordered > tbody > tr > td,
.table-bordered > thead > tr > td,
.table-bordered > thead > tr > th {
border: 1px solid #ddd;
}
.fc-head {
background-color: #fafafa;
}
td.fc-today {
background-color: #fcf8e3!important;
}
}

View File

@@ -29,9 +29,22 @@
top: 0;
right: 0;
padding-left: 10px;
.btn {
span.label {
position: absolute;
top: 1px;
right: 1px;
text-align: center;
font-size: 9px;
padding: 2px 3px;
}
}
}
@media (max-width: $screen-md-min) {
@media (max-width: $screen-md-max) {
.content-header h1 {
font-size: 1.5em;
}
.content-header>.breadcrumb {
margin-top: 0;
}

View File

@@ -15,6 +15,12 @@
}
}
@media (min-width: $screen-lg-min) {
.content {
padding: 20px;
}
}
td {
&.timesheet-description {
ul {
@@ -36,18 +42,9 @@ td {
margin-right: 15px;
}
/* Profile */
.box-profile {
img.img-circle {
width: 100px;
}
.profile-username {
margin-top: 15px;
}
}
.label-gray {
background-color: $gray-lte;
color: #666;
}
/* Delete link in action dropdowns */
@@ -64,4 +61,22 @@ th.w-min,
td.w-min {
width: 1%;
white-space: nowrap;
}
table.dataTable thead > tr > th.hw-min {
width: 1%;
white-space: normal;
}
.badge {
font-weight: normal;
color: #000;
background-color: $kimai-default;
}
.label {
font-weight: normal;
}
a.link-black {
color: #000;
}

View File

@@ -13,4 +13,8 @@ section {
}
}
}
.box-body-scrollable {
overflow: auto;
max-height: 300px;
}
}

View File

@@ -5,13 +5,34 @@
* file that was distributed with this source code.
*/
@import "variables";
table.dataTable.table > tbody > tr > td {
vertical-align: middle;
.img-circle {
width: 30px;
height: 30px;
margin-right: 0;
&.teamlead {
box-shadow: 0 0 5px 3px $gray-lte;
}
}
}
span.label-color,
span.label-meta,
span.label-tag,
span.label-user,
span.label-activity,
span.label-project,
span.label-customer {
display: inline-block;
.name {
white-space: nowrap;
.name-inner {
white-space: normal;
}
}
.dot {
font-size: 9px;
margin-right: 3px;
@@ -35,7 +56,10 @@ table.dataTable {
width: 15px;
}
&.overlapping {
border-top: 2px dotted red;
border-top: 2px solid rgba(255, 0, 0, 0.1);
}
&.exported {
opacity: 0.7;
}
}
td {
@@ -48,7 +72,6 @@ table.dataTable {
}
.label {
font-size: 85%;
font-weight: 500;
padding: .3em .6em .3em;
line-height: 24px;
}
@@ -68,4 +91,45 @@ table.dataTable {
opacity: 0.8;
}
}
tfoot {
tr {
/* overwritten if used in tfoot, to switch the border from below to top */
&.summary td {
border-top: 1px solid #ccc;
border-bottom: 0;
}
}
}
th.weekend,
td.weekend {
background-color: #f9f9f9;
}
/* order is important, "today” should overwrite "weekend" therefor later in the file */
th.today,
td.today {
background-color: $highlight-today;
}
th.total,
td.total {
font-weight: bold;
}
}
/* Quick entry form */
.form-dataTable {
table.dataTable {
.form-group {
margin-bottom: 0;
}
}
}
table.table-hover {
tr {
&.exported {
&:hover {
opacity: 1.0;
}
}
}
}

View File

@@ -125,26 +125,28 @@ table.dataTable thead .sorting_desc_disabled {
position: relative;
}
table.dataTable thead .sorting:before,
table.dataTable thead .sorting_asc:before,
table.dataTable thead .sorting_desc:before {
position: absolute;
top: 10px;
left: 5px;
display: block;
font-family: 'Glyphicons Halflings';
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc {
font-weight: bold;
}
table.dataTable thead .sorting:after,
table.dataTable thead .sorting_asc:after,
table.dataTable thead .sorting_desc:after {
padding-left: 5px;
font-family: 'Font Awesome 5 Free';
opacity: 0.5;
font-size: 12px;
}
table.dataTable thead .sorting:before {
table.dataTable thead .sorting:after {
opacity: 0.2;
content: "\e150"; /* sort */
content: "\f0dc"; /* sort */
}
table.dataTable thead .sorting_asc:before {
content: "\e155"; /* sort-by-attributes */
table.dataTable thead .sorting_asc:after {
content: "\f062";
}
table.dataTable thead .sorting_desc:before {
content: "\e156"; /* sort-by-attributes-alt */
table.dataTable thead .sorting_desc:after {
content: "\f063";
}
div.dataTables_scrollBody table.dataTable thead .sorting:before,
div.dataTables_scrollBody table.dataTable thead .sorting_asc:before,
@@ -158,14 +160,10 @@ table.dataTable thead .sorting_desc_disabled:before {
}
table.dataTable thead > tr > th {
vertical-align: top;
white-space: nowrap;
}
/*
table.dataTable thead > tr > th {
padding-right: 30px;
}
*/
table.dataTable th:active {
outline: none;
}
@@ -265,22 +263,3 @@ div.dataTables_scrollHead table.table-bordered {
.table-striped.dataTable tbody tr.active:nth-child(odd) th {
background-color: #017ebc;
}
/* custom extension to make the column wide enough to show the sortable icons */
table.dataTable th.sortable {
padding-left: 22px;
}
table.dataTable.table > tbody > tr > td {
&.avatars {
line-height: 40px;
}
vertical-align: middle;
.img-circle {
max-width: 35px;
margin-right: 10px;
&.teamlead {
box-shadow: 0 0 5px 3px $gray-lte;
}
}
}

67
assets/sass/forms.scss Normal file
View File

@@ -0,0 +1,67 @@
/* Currently only used in batch-update form for timesheets, to highlight sections of combined fields */
form .box-body fieldset {
border-radius: $box-border-radius;
padding: 10px;
&:hover {
background-color: $highlight-bg;
}
}
/* To be used with .form-horizontal - to reduce the space between rows, eg. used in the search modals */
form.form-narrow {
.form-group {
margin: 0 0 5px 0;
}
}
/* Mark as exported checkbox in export and invoice create screen */
.form-horizontal {
.checkbox {
min-height: 20px;
}
}
/* bootstrap3 hack because the filter look plain ugly without it (see report: project month) */
.checkbox-menu li label {
display: block;
padding: 5px 15px 5px 10px !important;
clear: both;
font-weight: normal;
line-height: 1.42857143;
color: #333;
white-space: nowrap;
margin:0;
transition: background-color .4s ease;
}
.checkbox-menu li div.checkbox {
display: block;
width: 100%;
}
.checkbox-menu li div.radio {
display: block;
width: 100%;
}
.checkbox-menu li input {
margin: 0 5px !important;
position: relative;
}
.checkbox-menu li.active label {
background-color: #cbcbff;
font-weight:bold;
}
.checkbox-menu li label:hover,
.checkbox-menu li label:focus {
background-color: #f5f5f5;
}
.checkbox-menu li.active label:hover,
.checkbox-menu li.active label:focus {
background-color: #b8b8ff;
}
.duration-input {
min-width:50px;
padding: 6px;
}

View File

@@ -11,18 +11,32 @@ body {
margin: 0;
padding: 0;
}
table, tr, td, p {
table, tr, td, th, p, h1, h2, h3, h4, h5 {
padding: 0;
margin: 0;
}
th {
border: none;
font-weight: bold;
text-align: left;
}
td {
vertical-align: top;
}
p {
margin-bottom: 12px;
}
.text-small {
font-size: 7pt;
}
.padding-left {
padding-left: 15px;
}
.text-center {
text-align: center;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
@@ -38,20 +52,21 @@ td {
.wrapper {
margin: 4px;
}
table {
width: 100%;
border-spacing: 0;
}
table.addresses, p {
line-height: 14pt;
}
/* The address table */
table.addresses {
width: 100%;
margin-bottom: 30px;
}
/* The PDF header */
table.header {
border-spacing: 0;
padding-bottom: 4px;
border-bottom: 1px solid #ccc;
width: 100%;
border-bottom: 1px solid #999;
}
table.header .title {
font-weight: normal;
@@ -59,22 +74,19 @@ table.header .title {
}
/* The PDF footer */
table.footer {
border-spacing: 0;
border-top: 1px solid #ccc;
border-top: 1px solid #999;
font-size: 80%;
padding-top: 8px;
width: 100%;
line-height: 14px;
}
table.footer td {
vertical-align: bottom;
vertical-align: top;
}
/* The invoice items list */
table.items {
width: 100%;
border-collapse: collapse;
margin-top: 50px;
margin-bottom: 50px;
margin-bottom: 60px;
}
table.items thead th,
table.items tbody td {
@@ -86,7 +98,7 @@ table.items tbody td.first {
}
table.items thead th.last,
table.items tbody td.last,
table.items tfoot td.last{
table.items tfoot td.last {
padding-right: 0;
}
@@ -99,6 +111,9 @@ table.items tfoot th {
padding: 20px 0 0 0;
line-height: 1px;
}
table.items tfoot td.last {
padding-left: 10px;
}
table.items tr.odd {
background-color: #f5f5f5;
}

View File

@@ -19,280 +19,287 @@
@import "~bootstrap-sass/assets/stylesheets/bootstrap/utilities";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/responsive-utilities";
body.invoice_print {
background-color: #eee;
body {
font-family: $font-family-sans-serif;
&.invoice_print {
background-color: #eee;
.table.no-border, .table.no-border td, .table.no-border th {
border: 0;
}
h1, h2, h3 {
font-family: 'Source Sans Pro', sans-serif;
}
.invoice {
margin: 105px auto 30px auto;
padding: 50px 65px;
min-height: 297mm;
position: relative;
max-width: 210mm;
box-shadow: 0 0 20px rgba(80,80,80,0.7);
background: #fff;
border: none;
}
.page-header {
margin: 10px 0 20px 0;
font-size: 22px;
>small {
color: #666;
display: block;
margin-top: 5px;
.table.no-border, .table.no-border td, .table.no-border th {
border: 0;
}
h3 {
border-color: #ddd;
h1, h2, h3 {
font-family: $font-family-sans-serif;
}
}
/*
.page-header {
margin: 10px 0 20px 0;
font-size: 22px;
}
*/
div.invoice-address {
margin-top: 30px;
margin-bottom: 30px;
}
table.invoice-meta th {
padding-right: 40px;
}
table.invoice-sum th {
width: 70%;
}
table.invoice-sum th, table.invoice-sum td {
text-align: right;
}
.invoice {
margin: 105px auto 30px auto;
padding: 50px 65px;
min-height: 297mm;
position: relative;
max-width: 210mm;
box-shadow: 0 0 20px rgba(80, 80, 80, 0.7);
background: #fff;
border: none;
}
.invoice-items {
margin-top: 2em;
margin-bottom: 3em;
.page-header {
margin: 10px 0 20px 0;
font-size: 22px;
.table {
thead th {
font-weight: bold;
border-bottom: 1px solid #ddd;
padding-bottom: 15px
> small {
color: #666;
display: block;
margin-top: 5px;
}
tfoot {
border-top: 1px solid #ddd;
tr:first-child th,
tr:first-child td {
padding-top: 15px
h3 {
border-color: #ddd;
}
}
div.invoice-address {
margin-top: 30px;
margin-bottom: 30px;
}
table.invoice-meta th {
padding-right: 40px;
}
table.invoice-sum th {
width: 70%;
}
table.invoice-sum th, table.invoice-sum td {
text-align: right;
}
.invoice-items {
margin-top: 2em;
margin-bottom: 3em;
.table {
thead th {
font-weight: bold;
border-bottom: 1px solid #ddd;
padding-bottom: 15px
}
tr {
th,td {
border:none;
padding: 4px 8px;
tfoot {
border-top: 1px solid #ddd;
tr:first-child th,
tr:first-child td {
padding-top: 15px
}
tr {
th, td {
border: none;
padding: 4px 8px;
}
}
}
}
}
}
.footer {
border-top: 1px solid #ccc;
margin-top: 50px;
font-size: 0.8em;
padding-top: 10px;
width: 100%;
}
/* ================================ FREELANCER INVOICE ================================ */
#freelancer-invoice {
box-sizing: border-box;
h1 {
font: bold 100% sans-serif;
letter-spacing: 0.5em;
text-align: center;
text-transform: uppercase;
}
h2 {
font: bold 1.5em sans-serif;
margin-bottom: 1em;
}
/* table */
table {
width: 100%;
}
table {
border-collapse: separate;
border-spacing: 0;
}
/* header */
header {
&:after {
clear: both;
content: "";
display: table;
font-size: 1em;
}
address {
float: left;
font-style: normal;
line-height: 1.25;
margin: 0 1em 1em 0;
font-size: 0.7em;
}
}
article address {
font-size: 1em;
float: left;
}
article.address {
margin:1em 0 1.5em 0;
}
/* article */
article:after {
clear: both;
content: "";
display: table;
}
article h1 {
clip: rect(0 0 0 0);
position: absolute;
}
article p {
margin-bottom: 20px;
}
/* table meta & balance */
table.meta:after, table.balance:after {
clear: both;
content: "";
display: table;
}
/* table meta */
table.meta {
float: right;
width: 50%;
font-size: 85%;
th {
text-align: right;
font-weight: normal;
}
td {
width: 120px;
text-align: right;
}
}
/* table balance */
table.balance {
float: right;
margin-top: 1em;
th {
text-align: right;
font-weight: normal;
}
td {
width: 140px;
text-align: right;
line-height: 22px;
}
.total {
font-weight: bold;
}
}
/* table items */
table.inventory {
clear: both;
width: 100%;
margin-top: 2em;
border-bottom: 1px solid #000;
}
table.inventory th,
table.inventory td {
padding: 5px;
}
table.inventory thead th {
font-weight: bold;
border-width: 0 0 1px 0;
border-bottom: 1px solid #000;
padding-bottom: 15px
}
table.inventory tbody tr:first-child td {
padding-top: 15px
}
table.inventory tbody tr:last-child td {
padding-bottom: 15px
}
.footer {
border-color: #000;
border-top: 1px solid #ccc;
margin-top: 50px;
font-size: 0.8em;
padding-top: 10px;
width: 100%;
}
}
/* ================================ PRINTING RULES ================================ */
/* ================================ FREELANCER INVOICE ================================ */
@media print {
* {
-webkit-print-color-adjust: exact;
}
body, .wrapper {
margin: 0;
padding: 0;
background-color: white;
}
#freelancer-invoice {
span:empty {
display: none;
box-sizing: border-box;
h1 {
font: bold 100% sans-serif;
letter-spacing: 0.5em;
text-align: center;
text-transform: uppercase;
}
.add, .cut {
display: none;
h2 {
font: bold 1.5em sans-serif;
margin-bottom: 1em;
}
/* table */
table {
width: 100%;
}
table {
border-collapse: separate;
border-spacing: 0;
}
/* header */
header {
&:after {
clear: both;
content: "";
display: table;
font-size: 1em;
}
address {
float: left;
font-style: normal;
line-height: 1.25;
margin: 0 1em 1em 0;
font-size: 0.7em;
}
}
article address {
font-size: 1em;
float: left;
}
article.address {
margin: 1em 0 1.5em 0;
}
/* article */
article:after {
clear: both;
content: "";
display: table;
}
article h1 {
clip: rect(0 0 0 0);
position: absolute;
}
article p {
margin-bottom: 20px;
}
/* table meta & balance */
table.meta:after, table.balance:after {
clear: both;
content: "";
display: table;
}
/* table meta */
table.meta {
float: right;
width: 50%;
font-size: 85%;
th {
text-align: right;
font-weight: normal;
}
td {
width: 120px;
text-align: right;
}
}
/* table balance */
table.balance {
float: right;
margin-top: 1em;
th {
text-align: right;
font-weight: normal;
}
td {
width: 140px;
text-align: right;
line-height: 22px;
}
.total {
font-weight: bold;
}
}
/* table items */
table.inventory {
clear: both;
width: 100%;
margin-top: 2em;
border-bottom: 1px solid #000;
}
table.inventory th,
table.inventory td {
padding: 5px;
}
table.inventory thead th {
font-weight: bold;
border-width: 0 0 1px 0;
border-bottom: 1px solid #000;
padding-bottom: 15px
}
table.inventory tbody tr:first-child td {
padding-top: 15px
}
table.inventory tbody tr:last-child td {
padding-bottom: 15px
}
.footer {
border-color: #000;
}
}
.invoice {
margin: 1em 2em;
font-size: 90%;
width: unset;
padding: 0;
min-height: unset;
position: unset;
max-width: unset;
box-shadow: unset;
/* ================================ PRINTING RULES ================================ */
@media print {
* {
-webkit-print-color-adjust: exact;
}
body, .wrapper {
margin: 0;
padding: 0;
background-color: white;
}
#freelancer-invoice {
span:empty {
display: none;
}
.add, .cut {
display: none;
}
}
.invoice {
margin: 1em 2em;
font-size: 90%;
width: unset;
padding: 0;
min-height: unset;
position: unset;
max-width: unset;
box-shadow: unset;
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
@media (max-width: $screen-sm-min) {
@media (max-width: $screen-sm-max) {
.main-header .logo {
display: none;
}

9
assets/sass/modal.scss Normal file
View File

@@ -0,0 +1,9 @@
.modal-header,
.modal-footer {
padding-top: 10px;
padding-bottom: 10px;
}
.modal-content {
border-radius: 3px;
box-shadow: 0 10px 80px rgba(0, 0, 0, 0.6);
}

View File

@@ -5,14 +5,30 @@
* file that was distributed with this source code.
*/
.navbar-nav {
img.img-circle {
max-height: 26px;
margin-top: -2px;
.navbar-custom-menu {
.navbar-nav {
li>.ddt-small {
padding-top: 10px;
padding-bottom: 10px;
}
}
li>a.ddt-large {
padding: 15px 12px 11px 10px;
font-size: 10px;
}
.navbar-nav {
.avatar {
max-height: 30px;
max-width: 30px;
height: 30px;
width: 30px;
margin-top: 0;
.initials {
top: 5px;
left: 0;
}
}
li>.ddt-small {
padding-top: 10px;
padding-bottom: 10px;
}
li.messages-menu ul.menu li {
a:hover .pull-left i {
@@ -35,17 +51,13 @@
width: unset !important;
}
.user-menu {
margin-right: 10px;
ul {
li {
a {
color: #444;
&:hover {
background-color: #f4f4f4;
i {
color: $blue;
}
}
color: #444;
i {
padding-right: 10px;
}
@@ -56,41 +68,86 @@
}
}
}
.notifications-menu>.dropdown-menu>li .menu>li>a:hover i {
color: $green;
}
@keyframes ticktac-blink {
0% { opacity: 1; }
5% { opacity: 0.95; }
10% { opacity: 0.9; }
15% { opacity: 0.85; }
20% { opacity: 0.8; }
25% { opacity: 0.75; }
30% { opacity: 0.7; }
35% { opacity: 0.65; }
40% { opacity: 0.6; }
45% { opacity: 0.65; }
50% { opacity: 0.7; }
55% { opacity: 0.75; }
60% { opacity: 0.8; }
65% { opacity: 0.85; }
70% { opacity: 0.9; }
75% { opacity: 0.95; }
100% { opacity: 1; }
}
.ticktac-single {
display: block;
position: relative;
padding-left: 15px;
padding-right: 15px;
i {
animation: ticktac-blink 2s step-end infinite;
}
span {
font-size: 1.8em;
line-height: 1em;
padding-left: 5px;
padding-right: 0;
}
&:hover {
background: rgba(0,0,0,.3);
}
}
body.fixed {
.navbar-nav {
.user-menu {
margin-right: 10px;
}
}
}
@media (max-width: $screen-sm-min) {
@media (max-width: $screen-sm-max) {
.navbar-custom-menu>.navbar-nav>li>.dropdown-menu {
right: 0;
}
.navbar-nav .user-menu {
margin-right: 0;
body.fixed {
.navbar-nav {
.user-menu {
margin-right: 0;
}
}
}
.navbar-nav .user-menu.open .dropdown-menu > li > a {
padding: 5px 25px 5px 25px
}
}
/*
.ticktac:hover i.running{
color: #4ff131;
@media (max-width: $screen-sm-max) {
.ticktac-single {
padding-left: 5px;
padding-right: 5px;
}
.navbar-custom-menu .navbar-nav li>.ddt-small {
padding-left: 5px;
padding-right: 5px;
}
}
li.open .ticktac i.running{
color: #4ff131;
@media (max-width: $screen-md-max) {
.ticktac-single {
padding-left: 10px;
padding-right: 10px;
}
.navbar-custom-menu .navbar-nav li>.ddt-small {
padding-left: 10px;
padding-right: 10px;
}
}
.ticktac i.stopped{
color: #fff;
}
.ticktac:hover i.stopped{
color: #4ff131;
}
.user-panel>.info {
left: 40px;
padding-top: 0px;
}
*/

View File

@@ -6,5 +6,21 @@
*/
@media print{
.sf-toolbar, .control-sidebar {display: none !important;}
.sf-toolbar, .control-sidebar {
display: none !important;
}
.col-print-12{
width:100%;
}
.sidebar-mini.sidebar-collapse .content-wrapper, .sidebar-mini.sidebar-collapse .main-footer, .sidebar-mini.sidebar-collapse .right-side {
margin: 0!important;
}
section.content {
margin: 0;
padding: 0;
}
span i.dot {
display: none;
margin-right: 0!important;
}
}

View File

@@ -0,0 +1,20 @@
/*
make sure that the progressbar title does not wrap and does not need to be embedded in a container with white-space: nowrap
used for example in the project-overview report
*/
.progress-group {
.progress-title {
width: 100%;
white-space: nowrap;
.progress-text {
display: inline-block;
width: 1%;
}
.progress-number {
display: inline-block;
width: 98%;
text-align: right;
float: none;
}
}
}

View File

@@ -1,6 +1,7 @@
.dataTable {
.weekend {
background-color: #f9f9f9;
opacity: 0.6;
.form-reporting .box-header .form-group {
margin-right: 10px;
label {
font-size: $font-size-base;
}
}

35
assets/sass/security.scss Normal file
View File

@@ -0,0 +1,35 @@
body.login-page {
.alert {
margin-bottom: 0;
}
.login-box-body {
text-align: center;
padding: 30px 35px;
box-shadow: 0 10px 30px 0 rgba(172, 168, 168, 0.43);
.btn {
padding: 7px;
font-size: 115%;
}
}
.login-head {
margin-top: 0;
}
.login-actions a {
display: block;
}
.form-group {
input[type=password], input[type=text] {
padding: 20px 15px;
}
}
span.glyphicon {
display: none;
}
}
@media (max-width: $screen-sm-max) {
body.login-page {
.login-box-body {
padding: 20px 27px;
}
}
}

View File

@@ -20,4 +20,10 @@
/* empty <option> were too small to be noticed as clickable element */
.select2-container--bootstrap .select2-results__option {
min-height: 30px;
}
}
/* Fixes the size on quick-entry form */
.select2-container--bootstrap {
display: table;
table-layout: fixed;
}

View File

@@ -5,28 +5,6 @@
* file that was distributed with this source code.
*/
/* UserPanel is deactivated right now */
/*
.user-panel>.info {
left: 80px;
}
*/
/* Right sidebar with additional tabs for personal settings and "About Kimai" section */
/*
.control-sidebar {
select {
color: $input-color;
background-color: $input-bg;
}
div.image {
img.img-circle {
max-width: 34px;
}
}
}
*/
@media (min-width: $screen-sm-min) {
.sidebar-mini.sidebar-collapse .sidebar-menu li.header {
border-top-width: 1px;
@@ -39,13 +17,3 @@
}
}
}
/*
Simplify focus detection, when using keyboard tab navigation
Deactivated, as it looks weird when the link is clicked
*/
/*
.sidebar-menu > li > a:focus {
text-decoration: underline;
}
*/

View File

@@ -1,26 +1,69 @@
$skins: blue, blue, black, green, purple, red, yellow;
$skins:
"blue" $yellow #fff $yellow $red,
"black" $yellow #000 $green $red,
"green" $yellow #fff $yellow $red,
"purple" $yellow #fff $yellow $red,
"red" $yellow #fff $yellow $yellow,
"yellow" $blue #fff $green $red
;
@each $skinColor in $skins {
@media (max-width: $screen-sm-min) {
.skin-#{$skinColor} .main-header .navbar .dropdown-menu li.divider {
background-color: #ccc;
}
.skin-#{$skinColor} .main-header .navbar .dropdown-menu li a {
color: #444;
}
.skin-#{$skinColor} .main-header .navbar .dropdown-menu li a:hover {
background: #fff;
}
@each $skinColor, $navHighlight, $tickTacColor, $startButton, $stopButton in $skins {
@each $prefix in (".skin-#{$skinColor}", ".skin-#{$skinColor}-light") {
@media (max-width: $screen-sm-max) {
#{$prefix} {
.main-header .navbar .dropdown-menu li.divider {
background-color: #ccc;
}
.skin-#{$skinColor}-light .main-header .navbar .dropdown-menu li.divider {
background-color: #ccc;
.main-header .navbar .dropdown-menu li a {
color: #444;
}
.main-header .navbar .dropdown-menu li a:hover {
background: #fff;
}
}
}
.skin-#{$skinColor}-light .main-header .navbar .dropdown-menu li a {
color: #444;
}
.skin-#{$skinColor}-light .main-header .navbar .dropdown-menu li a:hover {
background: #fff;
#{$prefix} {
.navbar-nav {
.user-menu {
ul {
li {
a {
&:hover {
i {
color: $navHighlight;
}
}
}
}
}
}
.notifications-menu > .dropdown-menu > li .menu > li > a:hover i {
color: $navHighlight;
}
}
.ticktac-single {
i {
color: $tickTacColor;
}
span {
color: $tickTacColor;
}
&:hover {
.ticktac-stop {
i {
color: $stopButton;
}
}
.ticktac-start {
i {
color: $startButton;
}
}
}
}
}
}
}

View File

@@ -2,11 +2,15 @@
font-size: unset;
}
.swal2-container {
top: 95px !important;
body.swal2-toast-shown .swal2-container {
// never block the top two bars double-bars display (smaller displays)
@media only screen and (max-width: 768px) {
top: 95px !important;
width: 80%;
}
// never block the top bar on single-bar display (larger devices)
@media only screen and (min-width: 768px) {
top: 60px !important;
}
}

3
assets/sass/tabs.scss Normal file
View File

@@ -0,0 +1,3 @@
.tab-content {
margin-top: 20px;
}

View File

@@ -5,14 +5,9 @@
* file that was distributed with this source code.
*/
.toolbar-pad {
padding: 10px;
}
/* The filter form is available on most pages above the datatable */
@media (min-width: $screen-sm-min) {
.toolbar {
// @deprecated since 1.2 - using the toolbar is deprecated and will be removed with 2.0
// @deprecated since 1.2 - using the navbar-form is deprecated and will be removed with 2.0
form.navbar-form {
font-size: $font-size-base;
.form-control {
@@ -28,63 +23,4 @@
}
}
}
.toolbar-pad {
padding: 10px 0;
}
}
/* Search form with filter dropdown */
.content-header {
form {
width: 200px;
float: left;
.container-fluid {
padding-left: 0;
padding-right: 0;
}
.form-group {
margin: 0 0 5px 0;
}
input.search-has-error {
color: $red;
}
.input-group-addon.has-error {
color: $red;
border-color: $red;
}
input.has-error {
border-color: $red;
}
ul.dropdown-menu {
max-height: 100vh;
overflow-y: auto;
padding-top: 10px;
width: 500px;
box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
max-width: 90vw;
}
a.search-cancel {
margin-top: 8px;
}
}
}
@media (max-width: $screen-xs-min) {
.content-header.search-open {
h1 {
display: none;
}
.breadcrumb {
display: none;
}
form.header-search {
padding: 0 10px 0 0;
float: none;
width: 100%;
ul.dropdown-menu {
width: 100%;
max-width: 100%;
}
}
}
}

View File

@@ -7,8 +7,12 @@
@import "~bootstrap-sass/assets/stylesheets/bootstrap/variables";
/* For highlighting rows, fieldsets and so on */
$highlight-bg: #f5f5f5;
$highlight-today: #fcf8e3;
/**
* A simple one to one clone of /node_modules/admin-lte/build/less/variables.less
* BELOW: A simple one to one clone of /node_modules/admin-lte/build/less/variables.less
*/
// COLORS
@@ -22,7 +26,7 @@ $green: #00a65a;
// Info
//$aqua: #00c0ef;
// Warning
//$yellow: #f39c12;
$yellow: #f0ad4e;
$blue: #0073b7;
//$navy: #001F3F;
//$teal: #39CCCC;
@@ -34,6 +38,7 @@ $blue: #0073b7;
//$maroon: #D81B60;
//$black: #111;
$gray-lte: #d2d6de;
$kimai-default: $gray-lte;
// LAYOUT
// --------------------------------------------------------

View File

@@ -2,7 +2,7 @@
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use App\ConsoleApplication;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\ErrorHandler\Debug;
use Symfony\Component\Dotenv\Dotenv;
@@ -25,5 +25,5 @@ if ($debug) {
}
$kernel = new Kernel($env, $debug);
$application = new Application($kernel);
$application = new ConsoleApplication($kernel);
$application->run($input);

View File

@@ -2,7 +2,7 @@
"name": "kevinpapst/kimai2",
"license": "MIT",
"type": "project",
"description": "Kimai Time-Tracking 2",
"description": "Kimai - Time Tracking",
"authors": [
{
"name": "Kevin Papst",
@@ -10,40 +10,41 @@
}
],
"require": {
"php": "^7.2",
"php": "7.3.*||7.4.*||8.0.*||8.1.*",
"ext-gd": "*",
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-pdo": "*",
"ext-tokenizer": "*",
"ext-xml": "*",
"ext-xsl": "*",
"ext-zip": "*",
"beberlei/doctrineextensions": "^1.2",
"composer/package-versions-deprecated": "^1.8",
"doctrine/dbal": "^2.1",
"doctrine/doctrine-bundle": "^2.0",
"doctrine/doctrine-migrations-bundle": "^2.1",
"doctrine/orm": "^2.7",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.8",
"doctrine/persistence": "^2",
"erusev/parsedown": "^1.6",
"friendsofsymfony/rest-bundle": "^2.5",
"gedmo/doctrine-extensions": "^2.4",
"hslavich/oneloginsaml-bundle": "^1.4",
"friendsofsymfony/rest-bundle": "^3.0",
"gedmo/doctrine-extensions": "^3.6",
"handcraftedinthealps/rest-routing-bundle": "^1.0",
"jms/metadata": "^2.0",
"jms/serializer-bundle": "^3.2",
"kevinpapst/adminlte-bundle": "^3.0",
"kimai/kimai2-composer": "^0.1",
"kimai/user-bundle": "^1.1",
"laravolt/avatar": "^3.0",
"jms/serializer-bundle": "^4.0",
"kevinpapst/adminlte-bundle": "^3.5",
"league/csv": "^9.4",
"league/html-to-markdown": "^4.9",
"league/html-to-markdown": "^5.0",
"mpdf/mpdf": "^8.0",
"nelmio/api-doc-bundle": "^3.2",
"nelmio/cors-bundle": "^1.5",
"nelmio/cors-bundle": "^2.0",
"onelogin/php-saml": "^3.4",
"pagerfanta/pagerfanta": "^2.1",
"phpoffice/phpspreadsheet": "^1.10",
"phpoffice/phpword": "^0.17",
"phpoffice/phpspreadsheet": "^1.16",
"phpoffice/phpword": "^0.18",
"psr/log": "^1.1",
"sensio/framework-extra-bundle": "^5.2",
"sensio/framework-extra-bundle": "^6.0",
"symfony/amazon-mailer": "^4.4",
"symfony/asset": "^4.4",
"symfony/console": "^4.4",
@@ -66,6 +67,7 @@
"symfony/serializer": "^4.4",
"symfony/translation": "^4.4",
"symfony/twig-bundle": "^4.4",
"symfony/uid": "^5.0",
"symfony/validator": "^4.4",
"symfony/webpack-encore-bundle": "^1.5",
"symfony/yaml": "^4.4",
@@ -76,38 +78,44 @@
"twig/string-extra": "^3.0"
},
"require-dev": {
"ext-simplexml": "*",
"dama/doctrine-test-bundle": "^6.0",
"doctrine/doctrine-fixtures-bundle": "^3.2",
"friendsofphp/php-cs-fixer": "^2.10",
"fzaninotto/faker": "^1.8",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-doctrine": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpstan/phpstan-symfony": "^0.12",
"phpunit/phpunit": "^8.0",
"fakerphp/faker": "^1.15",
"friendsofphp/php-cs-fixer": "^3.2",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-doctrine": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpstan/phpstan-symfony": "^1.0",
"phpunit/phpunit": "^9.0",
"symfony/browser-kit": "^4.4",
"symfony/css-selector": "^4.4",
"symfony/debug-bundle": "^4.4",
"symfony/dom-crawler": "4.4.4",
"symfony/maker-bundle": "^1.12",
"symfony/phpunit-bridge": "^4.4",
"symfony/profiler-pack": "^1.0",
"symfony/var-dumper": "^4.4"
"symfony/stopwatch": "^4.4",
"symfony/var-dumper": "^4.4",
"symfony/web-profiler-bundle": "^4.4"
},
"repositories": [
{
"type": "artifact",
"url": "var/packages/"
}
],
],
"config": {
"platform": {
"php": "7.2.9"
"php": "7.3"
},
"preferred-install": {
"*": "dist"
},
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"composer/package-versions-deprecated": true,
"symfony/flex": true
}
},
"autoload": {
"psr-4": {
@@ -132,7 +140,6 @@
"symfony/polyfill-php54": "*"
},
"suggest": {
"ext-mbstring": "If ext-mbstring is not available you MUST install symfony/polyfill-mbstring",
"laminas/laminas-ldap": "For LDAP authentication with Kimai"
},
"scripts": {
@@ -149,7 +156,7 @@
"kimai:pre-commit": [
"@kimai:codestyle",
"@kimai:phpstan",
"@kimai:code-lint",
"@linting",
"@kimai:tests-unit"
],
"kimai:code-check": "@code-check",
@@ -157,20 +164,23 @@
"@kimai:pre-commit",
"@kimai:tests-integration"
],
"kimai:code-lint": [
"kimai:code-lint": "@linting",
"linting": [
"composer validate --strict",
"bin/console lint:container",
"bin/console lint:yaml config --parse-tags",
"bin/console lint:twig templates --show-deprecations",
"bin/console lint:xliff translations",
"bin/console doctrine:schema:validate --skip-sync -vvv --no-interaction"
],
"kimai:tests": "vendor/bin/phpunit tests/",
"tests": "vendor/bin/phpunit tests/",
"kimai:tests": "@tests",
"kimai:tests-unit": "vendor/bin/phpunit --exclude-group integration tests/",
"kimai:tests-integration": "vendor/bin/phpunit --group integration tests/",
"kimai:phpstan": "@phpstan",
"phpstan": [
"vendor/bin/phpstan analyse src -c phpstan.neon --level=5",
"vendor/bin/phpstan analyse tests -c tests/phpstan.neon --level=4"
"vendor/bin/phpstan analyse tests -c tests/phpstan.neon --level=5"
],
"kimai:codestyle": "@codestyle",
"codestyle": "vendor/bin/php-cs-fixer fix --dry-run --verbose --show-progress=none",

9164
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -15,10 +15,10 @@ return [
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
KevinPapst\AdminLTEBundle\AdminLTEBundle::class => ['all' => true],
JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
FOS\UserBundle\FOSUserBundle::class => ['all' => true],
FOS\RestBundle\FOSRestBundle::class => ['all' => true],
Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true],
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
HandcraftedInTheAlps\RestRoutingBundle\RestRoutingBundle::class => ['all' => true],
];

View File

@@ -7,7 +7,7 @@ admin_lte:
# default image for missing user avatar images
default_avatar: build/images/default_avatar.png
# the color skin
skin: skin-green
skin: skin-blue
# if activated, the boxed_layout will be deactivated
fixed_layout: true
# boxed layout (true) or full-screen (false)

View File

@@ -4,17 +4,20 @@ parameters:
# environment variables are not available yet.
# You should not need to change this value.
env(DATABASE_URL): ''
env(DATABASE_VERSION): ~
doctrine:
dbal:
default_connection: default
connections:
default:
url: '%env(resolve:DATABASE_URL)%'
# existing migrations will fail if the schema filter is activated
#schema_filter: ~^(?!(bundle_migration_|kimai2_sessions))~
url: '%env(DATABASE_URL)%'
driver: 'pdo_mysql'
# this setting prevents automatic database detection and finds a lot of false-negatives on doctrine:migrations:diff
# for null columns with MariaDB. Each migration tries to convert EVERY nullable column.
# server_version: '5.7'
server_version: '%env(string:DATABASE_VERSION)%'
charset: utf8mb4
default_table_options:
charset: utf8mb4
@@ -36,3 +39,125 @@ doctrine:
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Kimai
dql:
datetime_functions:
addtime: DoctrineExtensions\Query\Mysql\AddTime
convert_tz: DoctrineExtensions\Query\Mysql\ConvertTz
date: DoctrineExtensions\Query\Mysql\Date
date_format: DoctrineExtensions\Query\Mysql\DateFormat
dateadd: DoctrineExtensions\Query\Mysql\DateAdd
datesub: DoctrineExtensions\Query\Mysql\DateSub
datediff: DoctrineExtensions\Query\Mysql\DateDiff
day: DoctrineExtensions\Query\Mysql\Day
dayname: DoctrineExtensions\Query\Mysql\DayName
dayofweek: DoctrineExtensions\Query\Mysql\DayOfWeek
dayofyear: DoctrineExtensions\Query\Mysql\DayOfYear
div: DoctrineExtensions\Query\Mysql\Div
from_unixtime: DoctrineExtensions\Query\Mysql\FromUnixtime
hour: DoctrineExtensions\Query\Mysql\Hour
last_day: DoctrineExtensions\Query\Mysql\LastDay
makedate: DoctrineExtensions\Query\Mysql\MakeDate
minute: DoctrineExtensions\Query\Mysql\Minute
now: DoctrineExtensions\Query\Mysql\Now
month: DoctrineExtensions\Query\Mysql\Month
monthname: DoctrineExtensions\Query\Mysql\MonthName
period_diff: DoctrineExtensions\Query\Mysql\PeriodDiff
second: DoctrineExtensions\Query\Mysql\Second
sectotime: DoctrineExtensions\Query\Mysql\SecToTime
strtodate: DoctrineExtensions\Query\Mysql\StrToDate
time: DoctrineExtensions\Query\Mysql\Time
timediff: DoctrineExtensions\Query\Mysql\TimeDiff
timestampadd: DoctrineExtensions\Query\Mysql\TimestampAdd
timestampdiff: DoctrineExtensions\Query\Mysql\TimestampDiff
timetosec: DoctrineExtensions\Query\Mysql\TimeToSec
truncate: DoctrineExtensions\Query\Mysql\Truncate
week: DoctrineExtensions\Query\Mysql\Week
weekday: DoctrineExtensions\Query\Mysql\WeekDay
year: DoctrineExtensions\Query\Mysql\Year
yearmonth: DoctrineExtensions\Query\Mysql\YearMonth
yearweek: DoctrineExtensions\Query\Mysql\YearWeek
unix_timestamp: DoctrineExtensions\Query\Mysql\UnixTimestamp
utc_timestamp: DoctrineExtensions\Query\Mysql\UtcTimestamp
extract: DoctrineExtensions\Query\Mysql\Extract
numeric_functions:
acos: DoctrineExtensions\Query\Mysql\Acos
asin: DoctrineExtensions\Query\Mysql\Asin
atan2: DoctrineExtensions\Query\Mysql\Atan2
atan: DoctrineExtensions\Query\Mysql\Atan
bit_count: DoctrineExtensions\Query\Mysql\BitCount
bit_xor: DoctrineExtensions\Query\Mysql\BitXor
ceil: DoctrineExtensions\Query\Mysql\Ceil
cos: DoctrineExtensions\Query\Mysql\Cos
cot: DoctrineExtensions\Query\Mysql\Cot
degrees: DoctrineExtensions\Query\Mysql\Degrees
exp: DoctrineExtensions\Query\Mysql\Exp
floor: DoctrineExtensions\Query\Mysql\Floor
json_contains: DoctrineExtensions\Query\Mysql\JsonContains
json_depth: DoctrineExtensions\Query\Mysql\JsonDepth
json_length: DoctrineExtensions\Query\Mysql\JsonLength
log: DoctrineExtensions\Query\Mysql\Log
log10: DoctrineExtensions\Query\Mysql\Log10
log2: DoctrineExtensions\Query\Mysql\Log2
pi: DoctrineExtensions\Query\Mysql\Pi
power: DoctrineExtensions\Query\Mysql\Power
quarter: DoctrineExtensions\Query\Mysql\Quarter
radians: DoctrineExtensions\Query\Mysql\Radians
rand: DoctrineExtensions\Query\Mysql\Rand
round: DoctrineExtensions\Query\Mysql\Round
stddev: DoctrineExtensions\Query\Mysql\StdDev
sin: DoctrineExtensions\Query\Mysql\Sin
std: DoctrineExtensions\Query\Mysql\Std
tan: DoctrineExtensions\Query\Mysql\Tan
variance: DoctrineExtensions\Query\Mysql\Variance
string_functions:
aes_decrypt: DoctrineExtensions\Query\Mysql\AesDecrypt
aes_encrypt: DoctrineExtensions\Query\Mysql\AesEncrypt
any_value: DoctrineExtensions\Query\Mysql\AnyValue
ascii: DoctrineExtensions\Query\Mysql\Ascii
binary: DoctrineExtensions\Query\Mysql\Binary
cast: DoctrineExtensions\Query\Mysql\Cast
char_length: DoctrineExtensions\Query\Mysql\CharLength
collate: DoctrineExtensions\Query\Mysql\Collate
concat_ws: DoctrineExtensions\Query\Mysql\ConcatWs
countif: DoctrineExtensions\Query\Mysql\CountIf
crc32: DoctrineExtensions\Query\Mysql\Crc32
degrees: DoctrineExtensions\Query\Mysql\Degrees
field: DoctrineExtensions\Query\Mysql\Field
find_in_set: DoctrineExtensions\Query\Mysql\FindInSet
format: DoctrineExtensions\Query\Mysql\Format
from_base64: DoctrineExtensions\Query\Mysql\FromBase64
greatest: DoctrineExtensions\Query\Mysql\Greatest
group_concat: DoctrineExtensions\Query\Mysql\GroupConcat
hex: DoctrineExtensions\Query\Mysql\Hex
ifelse: DoctrineExtensions\Query\Mysql\IfElse
ifnull: DoctrineExtensions\Query\Mysql\IfNull
inet_aton: DoctrineExtensions\Query\Mysql\InetAton
inet_ntoa: DoctrineExtensions\Query\Mysql\InetNtoa
inet6_aton: DoctrineExtensions\Query\Mysql\Inet6Aton
inet6_ntoa: DoctrineExtensions\Query\Mysql\Inet6Ntoa
instr: DoctrineExtensions\Query\Mysql\Instr
is_ipv4: DoctrineExtensions\Query\Mysql\IsIpv4
is_ipv4_compat: DoctrineExtensions\Query\Mysql\IsIpv4Compat
is_ipv4_mapped: DoctrineExtensions\Query\Mysql\IsIpv4Mapped
is_ipv6: DoctrineExtensions\Query\Mysql\IsIpv6
lag: DoctrineExtensions\Query\Mysql\Lag
lead: DoctrineExtensions\Query\Mysql\Lead
least: DoctrineExtensions\Query\Mysql\Least
lpad: DoctrineExtensions\Query\Mysql\Lpad
match: DoctrineExtensions\Query\Mysql\MatchAgainst
md5: DoctrineExtensions\Query\Mysql\Md5
nullif: DoctrineExtensions\Query\Mysql\NullIf
over: DoctrineExtensions\Query\Mysql\Over
radians: DoctrineExtensions\Query\Mysql\Radians
regexp: DoctrineExtensions\Query\Mysql\Regexp
replace: DoctrineExtensions\Query\Mysql\Replace
rpad: DoctrineExtensions\Query\Mysql\Rpad
sha1: DoctrineExtensions\Query\Mysql\Sha1
sha2: DoctrineExtensions\Query\Mysql\Sha2
soundex: DoctrineExtensions\Query\Mysql\Soundex
str_to_date: DoctrineExtensions\Query\Mysql\StrToDate
substring_index: DoctrineExtensions\Query\Mysql\SubstringIndex
unhex: DoctrineExtensions\Query\Mysql\Unhex
uuid_short: DoctrineExtensions\Query\Mysql\UuidShort

View File

@@ -1,118 +0,0 @@
doctrine:
orm:
dql:
datetime_functions:
addtime: DoctrineExtensions\Query\Mysql\AddTime
date: DoctrineExtensions\Query\Mysql\Date
date_format: DoctrineExtensions\Query\Mysql\DateFormat
dateadd: DoctrineExtensions\Query\Mysql\DateAdd
datesub: DoctrineExtensions\Query\Mysql\DateSub
datediff: DoctrineExtensions\Query\Mysql\DateDiff
day: DoctrineExtensions\Query\Mysql\Day
dayname: DoctrineExtensions\Query\Mysql\DayName
dayofweek: DoctrineExtensions\Query\Mysql\DayOfWeek
dayofyear: DoctrineExtensions\Query\Mysql\DayOfYear
div: DoctrineExtensions\Query\Mysql\Div
from_unixtime: DoctrineExtensions\Query\Mysql\FromUnixtime
hour: DoctrineExtensions\Query\Mysql\Hour
last_day: DoctrineExtensions\Query\Mysql\LastDay
makedate: DoctrineExtensions\Query\Mysql\MakeDate
minute: DoctrineExtensions\Query\Mysql\Minute
now: DoctrineExtensions\Query\Mysql\Now
month: DoctrineExtensions\Query\Mysql\Month
monthname: DoctrineExtensions\Query\Mysql\MonthName
period_diff: DoctrineExtensions\Query\Mysql\PeriodDiff
second: DoctrineExtensions\Query\Mysql\Second
sectotime: DoctrineExtensions\Query\Mysql\SecToTime
strtodate: DoctrineExtensions\Query\Mysql\StrToDate
time: DoctrineExtensions\Query\Mysql\Time
timediff: DoctrineExtensions\Query\Mysql\TimeDiff
timestampadd: DoctrineExtensions\Query\Mysql\TimestampAdd
timestampdiff: DoctrineExtensions\Query\Mysql\TimestampDiff
timetosec: DoctrineExtensions\Query\Mysql\TimeToSec
week: DoctrineExtensions\Query\Mysql\Week
weekday: DoctrineExtensions\Query\Mysql\WeekDay
year: DoctrineExtensions\Query\Mysql\Year
yearmonth: DoctrineExtensions\Query\Mysql\YearMonth
yearweek: DoctrineExtensions\Query\Mysql\YearWeek
unix_timestamp: DoctrineExtensions\Query\Mysql\UnixTimestamp
utc_timestamp: DoctrineExtensions\Query\Mysql\UtcTimestamp
extract: DoctrineExtensions\Query\Mysql\Extract
numeric_functions:
acos: DoctrineExtensions\Query\Mysql\Acos
asin: DoctrineExtensions\Query\Mysql\Asin
atan2: DoctrineExtensions\Query\Mysql\Atan2
atan: DoctrineExtensions\Query\Mysql\Atan
bit_count: DoctrineExtensions\Query\Mysql\BitCount
bit_xor: DoctrineExtensions\Query\Mysql\BitXor
ceil: DoctrineExtensions\Query\Mysql\Ceil
cos: DoctrineExtensions\Query\Mysql\Cos
cot: DoctrineExtensions\Query\Mysql\Cot
degrees: DoctrineExtensions\Query\Mysql\Degrees
exp: DoctrineExtensions\Query\Mysql\Exp
floor: DoctrineExtensions\Query\Mysql\Floor
log: DoctrineExtensions\Query\Mysql\Log
log10: DoctrineExtensions\Query\Mysql\Log10
log2: DoctrineExtensions\Query\Mysql\Log2
pi: DoctrineExtensions\Query\Mysql\Pi
power: DoctrineExtensions\Query\Mysql\Power
quarter: DoctrineExtensions\Query\Mysql\Quarter
radians: DoctrineExtensions\Query\Mysql\Radians
rand: DoctrineExtensions\Query\Mysql\Rand
round: DoctrineExtensions\Query\Mysql\Round
stddev: DoctrineExtensions\Query\Mysql\StdDev
sin: DoctrineExtensions\Query\Mysql\Sin
std: DoctrineExtensions\Query\Mysql\Std
tan: DoctrineExtensions\Query\Mysql\Tan
variance: DoctrineExtensions\Query\Mysql\Variance
string_functions:
aes_decrypt: DoctrineExtensions\Query\Mysql\AesDecrypt
aes_encrypt: DoctrineExtensions\Query\Mysql\AesEncrypt
any_value: DoctrineExtensions\Query\Mysql\AnyValue
ascii: DoctrineExtensions\Query\Mysql\Ascii
binary: DoctrineExtensions\Query\Mysql\Binary
cast: DoctrineExtensions\Query\Mysql\Cast
char_length: DoctrineExtensions\Query\Mysql\CharLength
collate: DoctrineExtensions\Query\Mysql\Collate
concat_ws: DoctrineExtensions\Query\Mysql\ConcatWs
countif: DoctrineExtensions\Query\Mysql\CountIf
crc32: DoctrineExtensions\Query\Mysql\Crc32
degrees: DoctrineExtensions\Query\Mysql\Degrees
field: DoctrineExtensions\Query\Mysql\Field
find_in_set: DoctrineExtensions\Query\Mysql\FindInSet
format: DoctrineExtensions\Query\Mysql\Format
greatest: DoctrineExtensions\Query\Mysql\Greatest
group_concat: DoctrineExtensions\Query\Mysql\GroupConcat
hex: DoctrineExtensions\Query\Mysql\Hex
ifelse: DoctrineExtensions\Query\Mysql\IfElse
ifnull: DoctrineExtensions\Query\Mysql\IfNull
inet_aton: DoctrineExtensions\Query\Mysql\InetAton
inet_ntoa: DoctrineExtensions\Query\Mysql\InetNtoa
inet6_aton: DoctrineExtensions\Query\Mysql\Inet6Aton
inet6_ntoa: DoctrineExtensions\Query\Mysql\Inet6Ntoa
instr: DoctrineExtensions\Query\Mysql\Instr
is_ipv4: DoctrineExtensions\Query\Mysql\IsIpv4
is_ipv4_compat: DoctrineExtensions\Query\Mysql\IsIpv4Compat
is_ipv4_mapped: DoctrineExtensions\Query\Mysql\IsIpv4Mapped
is_ipv6: DoctrineExtensions\Query\Mysql\IsIpv6
lag: DoctrineExtensions\Query\Mysql\Lag
lead: DoctrineExtensions\Query\Mysql\Lead
least: DoctrineExtensions\Query\Mysql\Least
lpad: DoctrineExtensions\Query\Mysql\Lpad
match: DoctrineExtensions\Query\Mysql\MatchAgainst
md5: DoctrineExtensions\Query\Mysql\Md5
nullif: DoctrineExtensions\Query\Mysql\NullIf
over: DoctrineExtensions\Query\Mysql\Over
radians: DoctrineExtensions\Query\Mysql\Radians
regexp: DoctrineExtensions\Query\Mysql\Regexp
replace: DoctrineExtensions\Query\Mysql\Replace
rpad: DoctrineExtensions\Query\Mysql\Rpad
sha1: DoctrineExtensions\Query\Mysql\Sha1
sha2: DoctrineExtensions\Query\Mysql\Sha2
soundex: DoctrineExtensions\Query\Mysql\Soundex
str_to_date: DoctrineExtensions\Query\Mysql\StrToDate
substring_index: DoctrineExtensions\Query\Mysql\SubstringIndex
unhex: DoctrineExtensions\Query\Mysql\Unhex
uuid_short: DoctrineExtensions\Query\Mysql\UuidShort

View File

@@ -1,55 +0,0 @@
doctrine:
orm:
dql:
datetime_functions:
date: DoctrineExtensions\Query\Sqlite\Date
date_format: DoctrineExtensions\Query\Sqlite\DateFormat
#dateadd: DoctrineExtensions\Query\Sqlite\DateAdd
#datediff: DoctrineExtensions\Query\Sqlite\DateDiff
day: DoctrineExtensions\Query\Sqlite\Day
dayname: DoctrineExtensions\Query\Sqlite\DayName
hour: DoctrineExtensions\Query\Sqlite\Hour
julianday: DoctrineExtensions\Query\Sqlite\JulianDay
minute: DoctrineExtensions\Query\Sqlite\Minute
#month: DoctrineExtensions\Query\Sqlite\Month
#monthname: DoctrineExtensions\Query\Sqlite\MonthName
second: DoctrineExtensions\Query\Sqlite\Second
month: DoctrineExtensions\Query\Sqlite\Month
strftime: DoctrineExtensions\Query\Sqlite\StrfTime
#strtodate: DoctrineExtensions\Query\Sqlite\StrToDate
#time: DoctrineExtensions\Query\Sqlite\Time
#timestampadd: DoctrineExtensions\Query\Sqlite\TimestampAdd
#timestampdiff: DoctrineExtensions\Query\Sqlite\TimestampDiff
week: DoctrineExtensions\Query\Sqlite\Week
weekday: DoctrineExtensions\Query\Sqlite\WeekDay
year: DoctrineExtensions\Query\Sqlite\Year
string_functions:
# binary: DoctrineExtensions\Query\Sqlite\Binary
# char_length: DoctrineExtensions\Query\Sqlite\CharLength
concat_ws: DoctrineExtensions\Query\Sqlite\ConcatWs
# countif: DoctrineExtensions\Query\Sqlite\CountIf
# crc32: DoctrineExtensions\Query\Sqlite\Crc32
# degrees: DoctrineExtensions\Query\Sqlite\Degrees
# field: DoctrineExtensions\Query\Sqlite\Field
# find_in_set: DoctrineExtensions\Query\Sqlite\FindInSet
# group_concat: DoctrineExtensions\Query\Sqlite\GroupConcat
greatest: DoctrineExtensions\Query\Sqlite\Greatest
ifelse: DoctrineExtensions\Query\Sqlite\IfElse
ifnull: DoctrineExtensions\Query\Sqlite\IfNull
least: DoctrineExtensions\Query\Sqlite\Least
# match: DoctrineExtensions\Query\Sqlite\MatchAgainst
# md5: DoctrineExtensions\Query\Sqlite\Md5
# nullif: DoctrineExtensions\Query\Sqlite\NullIf
# radians: DoctrineExtensions\Query\Sqlite\Radians
random: DoctrineExtensions\Query\Sqlite\Random
# regexp: DoctrineExtensions\Query\Sqlite\Regexp
replace: DoctrineExtensions\Query\Sqlite\Replace
# sha1: DoctrineExtensions\Query\Sqlite\Sha1
# sha2: DoctrineExtensions\Query\Sqlite\Sha2
# soundex: DoctrineExtensions\Query\Sqlite\Soundex
# uuid_short: DoctrineExtensions\Query\Sqlite\UuidShort
numeric_functions:
round: DoctrineExtensions\Query\Sqlite\Round

View File

@@ -1,5 +1,9 @@
doctrine_migrations:
dir_name: '%kernel.project_dir%/src/Migrations'
# namespace is arbitrary but should be different from App\Migrations
# as migrations classes should NOT be autoloaded
namespace: DoctrineMigrations
storage:
table_storage:
table_name: 'migration_versions'
migrations_paths:
# namespace is arbitrary but should be different from App\Migrations
# as migrations classes should NOT be autoloaded
'DoctrineMigrations': '%kernel.project_dir%/src/Migrations'
transactional: false

View File

@@ -1,109 +1,50 @@
# TODO upgrade to 2.8
# https://github.com/FriendsOfSymfony/FOSRestBundle/releases/tag/2.8.0
fos_rest:
# disable_csrf_role: IS_AUTHENTICATED_ANONYMOUSLY
# unauthorized_challenge: null
param_fetcher_listener:
enabled: true
# force: false
# service: null
cache_dir: '%kernel.cache_dir%/fos_rest'
# allowed_methods_listener:
# enabled: false
# service: null
# TODO activate with 2.8
# routing_loader: false
routing_loader:
default_format: json
include_format: true
enabled: true
cache_dir: '%kernel.cache_dir%/fos_rest'
routing_loader: false
body_converter:
enabled: true
# validate: false
# validation_errors_argument: validationErrors
# service:
# router: router
# templating: templating
# serializer: null
# view_handler: fos_rest.view_handler.default
# inflector: fos_rest.inflector.doctrine
# validator: validator
enabled: true
serializer:
# version: null
# groups: []
serialize_null: true
serialize_null: true
view:
default_engine: twig
# force_redirects:
# name: ~
# mime_types:
# enabled: false
# service: null
# formats:
# name: ~
# formats:
# name: ~
# templating_formats:
# name: ~
formats:
json: true
xml: false
view_response_listener:
enabled: true
# force: true
# service: null
failed_validation: 400
# empty_content: 204
# serialize_null: false
# jsonp_handler:
# callback_param: callback
# mime_type: application/javascript+jsonp
enabled: true
failed_validation: 400
exception:
enabled: true
# TODO active with 2.8
# serialize_exceptions: false
# TODO deprecated with 2.8
# https://github.com/FriendsOfSymfony/FOSRestBundle/issues/2200#issuecomment-629150462
# https://github.com/FriendsOfSymfony/FOSRestBundle/issues/2224
exception_controller: 'fos_rest.exception.controller:showAction'
enabled: true
map_exception_codes: true
serializer_error_renderer: true
codes:
# 'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
# 'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
# 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException': 400
messages:
'Symfony\Component\Routing\Exception\ResourceNotFoundException': true
'Symfony\Component\HttpKernel\Exception\NotFoundHttpException': true
'Symfony\Component\HttpKernel\Exception\BadRequestHttpException': 400
'App\Validator\ValidationFailedException': 400
'Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException': 401
'Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException': 403
'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
'Symfony\Component\HttpKernel\Exception\NotFoundHttpException': 404
'App\API\NotFoundException': 404
body_listener:
enabled: true
# service: null
# default_format: null
# throw_exception_on_unsupported_content_type: false
# decoders:
# name: ~
enabled: true
decoders:
json: fos_rest.decoder.json
array_normalizer:
service: fos_rest.normalizer.camel_keys
forms: true
service: fos_rest.normalizer.camel_keys
forms: true
format_listener:
enabled: true
# service: null
rules:
- { path: ^/api, prefer_extension: true, fallback_format: json, priorities: [ json, xml ] }
# host: null # URL host name
# methods: null # Method for URL
# stop: false
# attributes: []
# versioning:
# enabled: false
# default_version: ~
# resolvers:
# query:
# enabled: true
# parameter_name: version
# custom_header:
# enabled: true
# header_name: X-Accept-Version
# media_type:
# enabled: true
# regex: /(v|version)=(?P<version>[0-9\.]+)/
# guessing_order:
# - query
# - custom_header
# - media_type
- { path: ^/api, prefer_extension: true, fallback_format: json, priorities: [ json ] }
zone:
- { path: ^/api/* }
handcraftedinthealps_rest_routing:
routing_loader:
default_format: 'json'
prefix_methods: true
include_format: false
formats:
json: true
xml: false

View File

@@ -1,15 +0,0 @@
fos_user:
db_driver: orm
firewall_name: secured_area
user_class: App\Entity\User
from_email:
address: '%env(MAILER_FROM)%'
sender_name: "Kimai 2"
registration:
confirmation:
enabled: false
resetting:
retry_ttl: 7200
token_ttl: 86400
service:
mailer: App\Mail\UserMails

View File

@@ -12,6 +12,9 @@ framework:
session:
handler_id: App\Security\SessionHandler
cookie_secure: auto
cookie_httponly: true
cookie_samesite: lax
#esi: ~
#fragments: ~

View File

@@ -10,16 +10,11 @@ jms_serializer:
xml_serialization:
format_output: '%kernel.debug%'
metadata:
directories:
FOSUB:
namespace_prefix: "FOS\\UserBundle"
path: "%kernel.root_dir%/../config/serializer/FOS/UserBundle"
warmup:
paths:
included:
- "%kernel.root_dir%/Entity/"
- "%kernel.root_dir%/API/Model/"
- "%kernel.root_dir%/../vendor/kimai/user-bundle/Model"
excluded: []
property_naming:
id: 'jms_serializer.identical_property_naming_strategy'

View File

@@ -1,6 +1,6 @@
# ---------------------------------------------------------------------------------------------
# DO NOT EDIT THIS FILE, INSTEAD CREATE THE FILE "local.yaml" AND ADD YOUR SETTINGS IN THERE.
# See https://www.kimai.org/documentation/configurations.html
# See https://www.kimai.org/documentation/local-yaml.html
#
# Be aware that this file is YAML format and the indentation is important.
# Each config level needs to be indented with 4 additional spaces.
@@ -9,19 +9,15 @@ kimai:
# --------------------------------------------------------------------------------
# AUTHENTICATION
# You can disable some user management functions in the authentication screens.
# Both settings default to "true", see https://www.kimai.org/documentation/users.html
# --------------------------------------------------------------------------------
# user:
# registration: false
# password_reset: false
# password_reset: true
# --------------------------------------------------------------------------------
# --------------------------------------------------------------------------------
# TIME-TRACKING
# All configs related to time-tracking, timesheets and record management
# Most settings can be configured in the System configuration screen
# --------------------------------------------------------------------------------
timesheet:
@@ -29,12 +25,19 @@ kimai:
# This setting can be changed through the Administration screen
# markdown_content: false
# Configures the duration drop-down select.
# null = use rounding rules, 0 = deactivate, every other number is used as minute/step increment
# duration_increment: ~
# Configures the minute select for begin and end date-time.
# null = use rounding rules, every number > 0 is used as minute/step increment
# time_increment: ~
# The time-tracking mode that should be used.
# See https://www.kimai.org/documentation/timesheet.html#tracking-modes
# mode: default
# The default time to pre-fill the "create timesheet" form (in some cases).
# This setting is only respected by some timetracking modes and not in all situations.
# This setting is only respected by some time-tracking modes and not in all situations.
#
# Accepted formats, see
# - https://www.php.net/manual/en/datetime.formats.php
@@ -43,7 +46,6 @@ kimai:
# Rounding rules are used to round the begin & end dates and the duration for timesheet records.
# The "default" rule will round "begin" down and "end" up to the full minute, the "duration" will not be rounded.
# Find out more about rounding rules at https://www.kimai.org/documentation/timesheet.html
# rounding:
# default:
# days: ['monday','tuesday','wednesday','thursday','friday','saturday','sunday']
@@ -54,52 +56,43 @@ kimai:
# If you want to apply different hourly rates for specific weekdays, you can uncomment the "rates" configuration.
# The "weekend" rule will add 50% to each timesheet entry that will be recorded on "saturdays" or "sundays".
# See documentation at: https://www.kimai.org/documentation/timesheet.html#rate-calculation
# rates:
# weekend:
# days: ['saturday','sunday']
# factor: 1.5
# If you want to limit the max. active entries per user, you can do it here.
# The soft_limit is used as theme setting and displays a warning color if the user has reached X active recordings
# The hard_limit is used to detect how many active records are allowed per user:
# - by default a user can only have one active time-record: it is automatically stopped when a new one is started
# - when hard_limit is > 1 and the user is trying to start a new entry after reaching the limit, a warning is shown
# and the user has to stop an active entry first
# active_entries:
# soft_limit: 1
# hard_limit: 3
# Rules that define timesheet validation and behaviour
# allow_future_times: whether records in the future can be created
# rules:
# allow_future_times: true
# --------------------------------------------------------------------------------
# --------------------------------------------------------------------------------
# PERMISSIONS
# Find out more about the configurable permission system at:
# https://www.kimai.org/documentation/permissions.html
# --------------------------------------------------------------------------------
permissions:
# mapping complex rule sets of single permissions to named "sets" ("set name" = [array of "permissions and sets"])
# mapping complex rule sets of single permissions to named "sets" ("set name" = [array of "permissions and @SETS"])
sets:
ACTIVITIES: ['view_activity','create_activity','edit_activity','budget_activity','delete_activity','permissions_activity']
ACTIVITIES_ALL_TEAMLEAD: ['view_teamlead_activity','edit_teamlead_activity','budget_teamlead_activity','permissions_teamlead_activity']
ACTIVITIES_ALL_TEAM: ['view_team_activity','edit_team_activity','budget_team_activity']
ACTIVITIES_TEAMLEAD: ['view_teamlead_activity','create_activity','edit_teamlead_activity','budget_teamlead_activity']
PROJECTS: ['view_project','create_project','edit_project','budget_project','delete_project','permissions_project','comments_project','comments_create_project','details_project']
PROJECTS_ALL_TEAMLEAD: ['view_teamlead_project','edit_teamlead_project','budget_teamlead_project','permissions_teamlead_project','comments_teamlead_project','comments_create_teamlead_project','details_teamlead_project']
PROJECTS_ALL_TEAM: ['view_team_project','edit_team_project','budget_team_project','comments_team_project','comments_create_team_project','details_team_project']
PROJECTS_TEAMLEAD: ['view_teamlead_project','budget_teamlead_project','comments_teamlead_project','comments_create_teamlead_project','details_teamlead_project']
CUSTOMERS: ['view_customer','create_customer','edit_customer','budget_customer','delete_customer','permissions_customer','comments_customer','comments_create_customer','details_customer']
CUSTOMERS_ALL_TEAMLEAD: ['view_teamlead_customer','edit_teamlead_customer','budget_teamlead_customer','permissions_teamlead_customer','comments_teamlead_customer','comments_create_teamlead_customer','details_teamlead_customer']
CUSTOMERS_ALL_TEAM: ['view_team_customer','edit_team_customer','budget_team_customer','comments_team_customer','comments_create_team_customer','details_team_customer']
CUSTOMERS_TEAMLEAD: ['view_teamlead_customer','budget_teamlead_customer','comments_teamlead_customer','comments_create_teamlead_customer','details_teamlead_customer']
ACTIVITIES: ['view_activity','create_activity','edit_activity','budget_activity','time_activity','delete_activity','permissions_activity']
ACTIVITIES_ALL_TEAMLEAD: ['view_teamlead_activity','edit_teamlead_activity','budget_teamlead_activity','time_teamlead_activity','permissions_teamlead_activity']
ACTIVITIES_ALL_TEAM: ['view_team_activity','edit_team_activity','budget_team_activity','time_team_activity']
ACTIVITIES_TEAMLEAD: ['view_teamlead_activity','create_activity','edit_teamlead_activity','budget_teamlead_activity','time_teamlead_activity']
PROJECTS: ['view_project','create_project','edit_project','budget_project','time_project','delete_project','permissions_project','comments_project','comments_create_project','details_project']
PROJECTS_ALL_TEAMLEAD: ['view_teamlead_project','edit_teamlead_project','budget_teamlead_project','time_teamlead_project','permissions_teamlead_project','comments_teamlead_project','comments_create_teamlead_project','details_teamlead_project']
PROJECTS_ALL_TEAM: ['view_team_project','edit_team_project','budget_team_project','time_team_project','comments_team_project','comments_create_team_project','details_team_project']
PROJECTS_TEAMLEAD: ['view_teamlead_project','budget_teamlead_project','time_teamlead_project','comments_teamlead_project','comments_create_teamlead_project','details_teamlead_project']
CUSTOMERS: ['view_customer','create_customer','edit_customer','budget_customer','time_customer','delete_customer','permissions_customer','comments_customer','comments_create_customer','details_customer']
CUSTOMERS_ALL_TEAMLEAD: ['view_teamlead_customer','edit_teamlead_customer','budget_teamlead_customer','time_teamlead_customer','permissions_teamlead_customer','comments_teamlead_customer','comments_create_teamlead_customer','details_teamlead_customer']
CUSTOMERS_ALL_TEAM: ['view_team_customer','edit_team_customer','budget_team_customer','time_team_customer','comments_team_customer','comments_create_team_customer','details_team_customer']
CUSTOMERS_TEAMLEAD: ['view_teamlead_customer','budget_teamlead_customer','time_teamlead_customer','comments_teamlead_customer','comments_create_teamlead_customer','details_teamlead_customer']
INVOICE: ['view_invoice','create_invoice']
INVOICE_ADMIN: ['manage_invoice_template','history_invoice']
TIMESHEET: ['view_own_timesheet','start_own_timesheet','stop_own_timesheet','create_own_timesheet','edit_own_timesheet','export_own_timesheet','delete_own_timesheet']
INVOICE_ADMIN: ['manage_invoice_template']
INVOICE_ALL: ['delete_invoice']
TIMESHEET: ['view_own_timesheet','start_own_timesheet','stop_own_timesheet','create_own_timesheet','edit_own_timesheet','export_own_timesheet','delete_own_timesheet','weekly_own_timesheet']
TIMESHEET_OTHER: ['view_other_timesheet','start_other_timesheet','stop_other_timesheet','create_other_timesheet','edit_other_timesheet','export_other_timesheet','delete_other_timesheet']
PROFILE: ['view_own_profile','edit_own_profile','password_own_profile','preferences_own_profile','api-token_own_profile']
PROFILE_OTHER: ['view_other_profile','edit_other_profile','password_other_profile','roles_other_profile','preferences_other_profile','api-token_other_profile','teams_other_profile']
@@ -108,19 +101,20 @@ kimai:
RATE: ['view_rate_own_timesheet','edit_rate_own_timesheet']
RATE_OTHER: ['view_rate_other_timesheet','edit_rate_other_timesheet']
EXPORT: ['create_export','edit_export_own_timesheet','edit_export_other_timesheet']
BILLABLE: ['edit_billable_own_timesheet','edit_billable_other_timesheet']
TEAMS: ['view_team','create_team','edit_team','delete_team']
LOCKDOWN: ['lockdown_grace_timesheet','lockdown_override_timesheet']
REPORTING: ['view_reporting']
REPORTING: ['view_reporting','view_other_reporting']
# some single default definitions for roles
SINGLE_USER: ['view_team_member','budget_team_project']
SINGLE_USER: ['view_team_member','time_team_project']
SINGLE_TEAMLEAD: ['view_rate_own_timesheet','view_rate_other_timesheet','hourly-rate_own_profile','view_team_member']
SINGLE_ADMIN: ['hourly-rate_own_profile','edit_exported_timesheet','teams_own_profile','view_team_member','view_all_data']
SINGLE_SUPER_ADMIN: ['hourly-rate_own_profile','hourly-rate_other_profile','roles_own_profile','system_information','system_configuration','plugins','edit_exported_timesheet','teams_own_profile','view_team_member','upload_invoice_template','view_all_data']
# link above sets to one complete set for each user role
ROLE_USER: ['@TIMESHEET','@PROFILE','@REPORTING','@SINGLE_USER']
ROLE_TEAMLEAD: ['@ACTIVITIES_TEAMLEAD','@PROJECTS_TEAMLEAD','@CUSTOMERS_TEAMLEAD','@TIMESHEET_OTHER','@INVOICE','@TIMESHEET','@PROFILE','@EXPORT','@TAGS','@REPORTING','@SINGLE_TEAMLEAD']
ROLE_ADMIN: ['@ACTIVITIES','@PROJECTS','@CUSTOMERS','@INVOICE','@INVOICE_ADMIN','@TIMESHEET','@TIMESHEET_OTHER','@PROFILE','@TEAMS','@RATE','@RATE_OTHER','@EXPORT','@TAGS','@LOCKDOWN','@REPORTING','@SINGLE_ADMIN']
ROLE_SUPER_ADMIN: ['@ACTIVITIES','@PROJECTS','@CUSTOMERS','@INVOICE','@INVOICE_ADMIN','@TIMESHEET','@TIMESHEET_OTHER','@PROFILE','@PROFILE_OTHER','@USER','@TEAMS','@RATE','@RATE_OTHER','@EXPORT','@TAGS','@LOCKDOWN','@REPORTING','@SINGLE_SUPER_ADMIN']
ROLE_TEAMLEAD: ['@ACTIVITIES_TEAMLEAD','@PROJECTS_TEAMLEAD','@CUSTOMERS_TEAMLEAD','@TIMESHEET_OTHER','@INVOICE','@TIMESHEET','@PROFILE','@EXPORT','@BILLABLE','@TAGS','@REPORTING','@SINGLE_TEAMLEAD']
ROLE_ADMIN: ['@ACTIVITIES','@PROJECTS','@CUSTOMERS','@INVOICE','@INVOICE_ADMIN','@TIMESHEET','@TIMESHEET_OTHER','@PROFILE','@TEAMS','@RATE','@RATE_OTHER','@EXPORT','@BILLABLE','@TAGS','@LOCKDOWN','@REPORTING','@SINGLE_ADMIN']
ROLE_SUPER_ADMIN: ['@ACTIVITIES','@PROJECTS','@CUSTOMERS','@INVOICE','@INVOICE_ADMIN','@TIMESHEET','@TIMESHEET_OTHER','@PROFILE','@PROFILE_OTHER','@USER','@TEAMS','@RATE','@RATE_OTHER','@EXPORT','@BILLABLE','@TAGS','@LOCKDOWN','@REPORTING','@SINGLE_SUPER_ADMIN']
# mapping "sets" or permissions to user roles ("role name" = [array of "set names"])
maps:
ROLE_USER: ['ROLE_USER']
@@ -128,7 +122,7 @@ kimai:
ROLE_ADMIN: ['ROLE_ADMIN']
ROLE_SUPER_ADMIN: ['ROLE_SUPER_ADMIN']
# only here to register the (partially) unused permissions in the UI
ROLE_FAKE: ['CUSTOMERS_ALL_TEAMLEAD','CUSTOMERS_ALL_TEAM','PROJECTS_ALL_TEAMLEAD','PROJECTS_ALL_TEAM','ACTIVITIES_ALL_TEAMLEAD','ACTIVITIES_ALL_TEAM']
ROLE_FAKE: ['CUSTOMERS_ALL_TEAMLEAD','CUSTOMERS_ALL_TEAM','PROJECTS_ALL_TEAMLEAD','PROJECTS_ALL_TEAM','ACTIVITIES_ALL_TEAMLEAD','ACTIVITIES_ALL_TEAM','INVOICE_ALL']
# add or remove single permissions
roles:
ROLE_USER: []
@@ -140,7 +134,6 @@ kimai:
# --------------------------------------------------------------------------------
# CALENDAR Configuration
# See documentation at https://www.kimai.org/documentation/calendar.html
# --------------------------------------------------------------------------------
# calendar:
# week_numbers: true
@@ -178,8 +171,6 @@ kimai:
# --------------------------------------------------------------------------------
# DASHBOARD
# Using the configurable widget sections.
# See documentation at https://www.kimai.org/documentation/dashboard.html
# --------------------------------------------------------------------------------
dashboard:
user_duration:
@@ -210,87 +201,102 @@ kimai:
rates:
title: ~
order: 50
permission: view_rate_other_timesheet
permission: view_all_data
widgets: [amountToday, amountWeek, amountMonth, amountYear]
totals:
title: ~
order: 100
permission: ROLE_USER
widgets: [TotalsUser, TotalsCustomer, TotalsProject, TotalsActivity]
# --------------------------------------------------------------------------------
# --------------------------------------------------------------------------------
# LANGUAGES
# Locale specific settings, like date formats
# --------------------------------------------------------------------------------
languages:
cs:
date_time_type: 'dd.MM.yyyy HH:mm'
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m H:i'
da:
date_time_type: 'dd.MM.yyyy HH:mm'
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
de:
date_time_type: 'dd.MM.yyyy HH:mm'
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
de_AT:
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
de_CH:
date_time_type: 'dd.MM.yyyy HH:mm'
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
el:
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
en:
date_time_type: 'yyyy-MM-dd HH:mm'
date_type: 'yyyy-MM-dd'
date: 'Y-m-d'
date_time: 'm-d H:i'
duration: '%%h:%%m h'
en_GB:
date_type: 'dd/MM/yyyy'
date: 'd/m/Y'
date_time: 'd/m H:i'
es:
date_time_type: 'dd.MM.yyyy HH:mm'
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
fi:
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
fr:
date_time_type: 'dd/MM/yyyy HH:mm'
date_type: 'dd/MM/yyyy'
date: 'd/m/Y'
date_time: 'd/m H:i'
duration: '%%h h %%m'
he:
date_time_type: 'dd/MM/yyyy HH:mm'
date_type: 'dd/MM/yyyy'
date: 'd/m/Y'
date_time: 'd/m H:i'
duration: '%%h:%%m'
hr:
date_type: 'dd. MM. yyyy.'
date: 'd. m. Y.'
date_time: 'd. m. H:i'
duration: '%%h:%%m'
hu:
date_time_type: 'yyyy.MM.dd. HH:mm'
date_type: 'yyyy.MM.dd.'
date: 'Y.m.d.'
date_time: 'm.d. H:i'
it:
date_time_type: 'dd.MM.yyyy HH:mm'
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
nl:
date_time_type: 'dd.MM.yyyy HH:mm'
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
duration: '%%hu%%m'
pt:
date_type: 'dd/MM/yyyy'
date: 'd/m/Y'
date_time: 'd-m H:i'
pt_BR:
date_time_type: 'dd-MM-yyyy HH:mm'
date_type: 'dd-MM-yyyy'
date: 'd-m-Y'
date_time: 'd-m H:i'
ru:
date_time_type: 'dd.MM.yyyy HH:mm'
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
date_time: 'd.m. H:i'
sk:
date_time_type: 'dd. MM. yyyy HH:mm'
date_type: 'dd. MM. yyyy'
date: 'd. m. Y'
date_time: 'd. m. H:i'
@@ -298,7 +304,6 @@ kimai:
duration: '%%h:%%m tim'
date_time: 'd/m H:i'
pl:
date_time_type: 'dd. MM. yyyy HH:mm'
date_type: 'dd. MM. yyyy'
date: 'd. m. Y'
date_time: 'd. m. H:i'

View File

@@ -26,30 +26,28 @@ nelmio_api_doc:
- { alias: TagEntity, type: App\Entity\Tag, groups: [Default, Entity, Tag] }
- { alias: TimesheetEditForm, type: App\Form\API\TimesheetApiEditForm, groups: [Default, Entity, Timesheet, Not_Expanded] }
- { alias: TimesheetEntity, type: App\Entity\Timesheet, groups: [Default, Entity, Timesheet, Timesheet_Entity, Not_Expanded] }
- { alias: TimesheetEntityExpanded, type: App\Entity\Timesheet, groups: [Default, Entity, Timesheet, Timesheet_Entity, Expanded] }
- { alias: TimesheetCollection, type: App\Entity\Timesheet, groups: [Default, Collection, Timesheet, Not_Expanded] }
- { alias: TimesheetCollectionExpanded, type: App\Entity\Timesheet, groups: [Default, Collection, Timesheet, Subresource, Expanded] }
- { alias: UserCreateForm, type: App\Form\API\UserApiCreateForm, groups: [Default, Entity, User, User_Entity] }
- { alias: UserEditForm, type: App\Form\API\UserApiEditForm, groups: [Default, Entity, User, User_Entity] }
- { alias: User, type: App\Entity\User, groups: [Default] }
- { alias: UserPreference, type: App\Entity\UserPreference, groups: [Default, User_Entity] }
- { alias: UserEntity, type: App\Entity\User, groups: [Default, Entity, User, User_Entity] }
- { alias: UserCollection, type: App\Entity\User, groups: [Default, Collection, User] }
- { alias: TeamEditForm, type: App\Form\API\TeamApiEditForm, groups: [Default, Entity, Team, Team_Entity] }
- { alias: TeamEntity, type: App\Entity\Team, groups: [Default, Entity, Team, Team_Entity] }
- { alias: Team, type: App\Entity\Team, groups: [Default, Entity, Team, Team_Entity] }
- { alias: TeamCollection, type: App\Entity\Team, groups: [Default, Collection, Team] }
- { alias: TeamMember, type: App\Entity\TeamMember, groups: [Team_Entity] }
- { alias: TeamMembership, type: App\Entity\TeamMember, groups: [User_Entity] }
areas:
path_patterns:
- ^/api(?!/doc)
documentation:
#host: '{{hostname}}'
host: '%router.request_context.host%'
basePath: '%router.request_context.base_url%'
schemes: ['%router.request_context.scheme%']
info:
title: Kimai 2 - API Docs
title: Kimai - API Docs
description: |
JSON API for the Kimai 2 time-tracking software. Read more about its usage in the [API documentation](https://www.kimai.org/documentation/rest-api.html) and then download a [Swagger file](doc.json) for import e.g. in Postman.
Be aware: it is not yet considered stable and BC breaks might happen, especially when using code generation.
The order of JSON attributes is not guaranteed.
JSON API for the Kimai time-tracking software: [API documentation](https://www.kimai.org/documentation/rest-api.html), [Swagger definition file](doc.json)
version: '0.6'
securityDefinitions:
apiUser:

View File

@@ -4,11 +4,10 @@ monolog:
type: fingers_crossed
action_level: error
handler: nested
excluded_404s:
# regex: exclude all 404 errors from the logs
- ^/
excluded_http_codes: [403, 404]
nested:
type: stream
level: info
path: "%kernel.logs_dir%/%kernel.environment%.log"
console:

View File

@@ -5,7 +5,7 @@ security:
providers:
chain_provider:
chain:
providers: [kimai_internal]
providers: [kimai_internal,kimai_ldap]
kimai_ldap:
id: App\Ldap\LdapUserProvider
kimai_internal:
@@ -16,7 +16,20 @@ security:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api:
request_matcher: App\Security\ApiRequestMatcher
user_checker: App\Security\UserChecker
anonymous: false
stateless: true
remember_me: false
provider: chain_provider
guard:
authenticators:
- App\Security\TokenAuthenticator
secured_area:
kimai_saml: ~
kimai_ldap: ~
pattern: ^/
user_checker: App\Security\UserChecker
anonymous: true
@@ -24,7 +37,7 @@ security:
guard:
authenticators:
- App\Security\TokenAuthenticator
- App\Security\ApiAuthenticator
remember_me:
secret: '%kernel.secret%'

View File

@@ -1,5 +1,4 @@
twig:
#paths: ['%kernel.project_dir%/templates']
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'
form_themes:
@@ -8,3 +7,4 @@ twig:
paths:
# used in templates/emails/layout.html.twig
'%kernel.project_dir%/assets/css': css
'%kernel.project_dir%/vendor/kevinpapst/adminlte-bundle/Resources/views': theme

View File

@@ -11,3 +11,17 @@ app.api:
resource: '../src/API/'
type: rest
prefix: /api
auth:
resource: '../../src/Controller/Auth/'
type: annotation
prefix: /auth
security:
resource: '../../src/Controller/Security/'
type: annotation
prefix: /{_locale}
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'

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