Compare commits

..

877 Commits
0.4 ... 1.18

Author SHA1 Message Date
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
Kevin Papst
a258516322 bump version 1.10.1 (#1927) 2020-08-27 11:48:08 +02:00
Kevin Papst
d25bcfe29c use configured language for non-twig invoice templates (#1924) 2020-08-26 23:41:47 +02:00
Kevin Papst
8464cd925e query widget data for user (#1917) 2020-08-24 18:37:42 +02:00
Kevin Papst
c2c4f087e4 cleanup for 1.10 (#1906) 2020-08-22 19:15:54 +02:00
IxFail
064d083db6 updated dutch translations (#1905) 2020-08-21 21:52:24 +02:00
Kevin Papst
ede21fe46a more extension points for plugins (#1904) 2020-08-21 19:38:17 +02:00
Kevin Papst
5c79e68c77 reporting cleanup (#1903)
- show form error when trying to load invalid user
- added non-breaking space to first table cells to allow copy&paste to excel
- added several css classes to allow customizations
- remove team assignment check for user selection
2020-08-21 11:31:42 +02:00
Kevin Papst
e6d01f2a23 allow to order tables by more fields (#1902) 2020-08-21 10:48:57 +02:00
Kevin Papst
af4101c9fe fix distinct vs group_by (#1901) 2020-08-20 22:29:28 +02:00
Kevin Papst
b9ee811cbf helper for handling billable fields (#1900) 2020-08-20 15:03:57 +02:00
Kevin Papst
7a1dada9dc stacked bars in dashboard widget (#1893)
* cleanup global context usage in widgets
* allow empty strings as time format
* fix order and update of user settings form
* added link to reporting documentation
2020-08-19 13:19:08 +02:00
Kevin Papst
1de76ba266 added link to reporting documentation 2020-08-19 10:46:08 +02:00
Kevin Papst
ec612d1046 fix duration calculation for multiple entries of same activity 2020-08-19 10:08:25 +02:00
Kevin Papst
15c3acfa0b updated test 2020-08-19 00:37:49 +02:00
Kevin Papst
6aac85bddb updated test 2020-08-19 00:03:11 +02:00
Kevin Papst
d8ae7635d1 fix order and update of user settings form 2020-08-18 23:22:16 +02:00
Kevin Papst
fbb3dd89cf removed unused dependency 2020-08-18 15:08:43 +02:00
Kevin Papst
8d1e24ae90 removed unused dependency 2020-08-18 15:06:49 +02:00
Kevin Papst
367a901207 allow empty strings as time format 2020-08-18 15:03:46 +02:00
Kevin Papst
9597015413 cleanup global context usage in widgets 2020-08-18 11:39:41 +02:00
Kevin Papst
08696651fd Merge branch 'master' into stacked-working-hours 2020-08-17 19:04:00 +02:00
Kevin Papst
661c3897b0 new form type to select a daytime in system-configuration (#1895) 2020-08-17 00:18:51 +02:00
Kevin Papst
4200208c7b Bugfix in JS for project/activity selection in timesheet edit dialog (#1894) 2020-08-16 16:20:24 +02:00
Kevin Papst
aba7e05ee2 Merge branch 'master' into stacked-working-hours 2020-08-16 12:24:18 +02:00
Kevin Papst
ed4b82f4b1 Weekly reporting view (#1892) 2020-08-16 12:23:41 +02:00
Kevin Papst
2d4cfbe821 Weekly reporting view (#1892) 2020-08-16 12:20:33 +02:00
Kevin Papst
34a1e07824 adapt test 2020-08-16 01:50:40 +02:00
Kevin Papst
bb4233ddfe use stacked bars in dashboard to show different working tasks per day 2020-08-16 01:43:38 +02:00
Kevin Papst
2449a1e8bf fix serialized dates from API (#1888) 2020-08-12 21:56:47 +02:00
synaestic
dc9bc8a8ca assign existing tag on timesheet import (#1877) (#1883) 2020-08-12 21:54:00 +02:00
Kevin Papst
0914ebf737 added team permissions for activities (#1872) 2020-08-08 18:50:04 +02:00
Kevin Papst
dc162bf385 bump serializer bundle (#1867) 2020-08-04 10:28:43 +02:00
Kevin Papst
86add9b9f7 fix batch update resets export state (#1866) 2020-08-04 10:05:05 +02:00
Kevin Papst
476e6ca150 remove usage of getenv from codebase (#1861) 2020-08-02 01:02:04 +02:00
Kevin Papst
6f8c0e3cb6 disable headings in markdown (#1843) 2020-07-26 21:06:33 +02:00
Kevin Papst
6bd2390acf fix test 2020-07-26 20:47:06 +02:00
Kevin Papst
599b18ac99 link reporting screen for users and month charts (#1842) 2020-07-26 20:28:48 +02:00
Kevin Papst
130e6ac057 handle hidden users in teams (#1841)
* allow to add disabled users to team
* allow to include disabled users in user-select
* include disabled users when editing team members ONLY if they are already part of team
2020-07-26 13:13:06 +02:00
Kevin Papst
ecea92942c prepare release 1.10 (#1837) 2020-07-21 17:07:40 +02:00
Kevin Papst
12e348544d invoice: increase number, customer specific counter (#1836) 2020-07-21 16:11:52 +02:00
Kevin Papst
4b8f743fa6 added some more tests (#1835) 2020-07-21 15:27:29 +02:00
Kevin Papst
aee063bb3c added annotation based exporter (#1831)
* added user exporter
* added project exporter
* added customer exporter
* added activity exporter
2020-07-21 03:37:51 +02:00
Kevin Papst
93a23f3fa3 fix group by with ONLY_FULL_GROUP_BY mode (#1830) 2020-07-18 10:16:15 +02:00
Kevin Papst
7907b43ef7 UI improvement (#1829)
* open "create new project/activity" form in modal
* re-use action translation for create action title
* do not pre-select first customer in list - fixes #1828
* sort user preferences in sections for better visual grouping
* show comment date only in hover of user avatar
2020-07-17 20:32:11 +02:00
Kevin Papst
c843dba29a API improvements (#1826) 2020-07-17 20:30:16 +02:00
Kevin Papst
5864c7e127 added username to export (#1827) 2020-07-17 02:32:39 +02:00
Kevin Papst
f57b314466 Preparations for coming features (#1818)
* removed unused convert_tz code
* added timestampable listener to support automatic updates of change columns
* added modified_at, billable and category timesheet fields
* new timesheet API query parameter modified_after
2020-07-13 23:35:06 +02:00
Kevin Papst
f2dd2331a5 polish detail pages (#1817) 2020-07-12 20:11:13 +02:00
Kevin Papst
164af7ae02 added reporting screen (#1805) 2020-07-12 14:05:14 +02:00
Kevin Papst
b97d9f692d added team permissions on user queries (#1815) 2020-07-12 01:18:57 +02:00
Kevin Papst
32c1e3258e invoices: unified money, number and date formats and fully respect configured language (#1814) 2020-07-10 15:09:52 +02:00
Kevin Papst
19e4ebf88c several enhancements (#1808)
* show all fields in timesheet api docs
* fix action dropdown links #1806
* apply same validation rules for passwords and for api-tokens #1753
* added "duplicate team" action #1136
2020-07-10 03:57:15 +02:00
Kevin Papst
ea39d5c74d new translations to clarify working time periods (#1802) 2020-07-04 19:44:44 +02:00
Kevin Papst
682681afa5 added domain logic for permission checks (#1803) 2020-07-04 13:29:03 +02:00
Honza Kopecký
091740f407 timesheet lockdown with grace period (#1644) 2020-07-02 18:54:17 +02:00
Kevin Papst
e22830790b new system-config to prevent overlapping records (#1720) 2020-06-28 22:09:50 +02:00
Kevin Papst
e566305426 updated composer dependencies (#1796) 2020-06-28 15:43:38 +02:00
Maarten Kooyman
8530a03449 added support for weekly invoices (#1780) 2020-06-28 15:13:35 +02:00
Oscariremma
1a24aabb6f Fixed SV locale date format (#1790) 2020-06-25 19:34:53 +02:00
Kevin Papst
381f46cdd8 Invoices: show only custom documents in upload form (#1786) 2020-06-19 18:31:08 +02:00
Kevin Papst
470a6b30e0 configuration improvements (#1784) 2020-06-16 18:35:09 +02:00
Kevin Papst
ea4e930cbb Store sessions in database (#1736) 2020-06-11 16:54:51 +02:00
Kevin Papst
a75bdc52f6 Invoice: switch from and to address (#1776) 2020-06-11 15:19:29 +02:00
Kevin Papst
21d8e8bbb8 improve configurations for usage in multi-environment setups (#1775) 2020-06-11 01:26:57 +02:00
Oscariremma
57b4473bc8 Updated swedish translations (#1774) 2020-06-09 22:54:58 +02:00
Kevin Papst
ae6beff5d8 Allow to recalculate rates via bulk edit (#1768) 2020-06-05 12:25:56 +02:00
Kevin Papst
da5563960b Added Vietnamese translations (#1758) 2020-06-04 16:21:12 +02:00
Kevin Papst
3b6df1cb84 fix by-project and by-customer queries creating empty invoices (#1756) 2020-06-02 12:56:08 +02:00
Kevin Papst
91736e89cc added hebrew translations (#1724)
first day of week in datepicker is locale specific now
2020-05-24 13:58:13 +02:00
Kevin Papst
e2a4998341 added romanian translations (#1722) 2020-05-23 12:07:57 +02:00
Kevin Papst
3c511df7f7 fix required fields in API (#1718) 2020-05-19 11:24:30 +02:00
Kevin Papst
e61ffe4db4 create timesheet for multiple users (#1716) 2020-05-18 23:35:43 +02:00
Kevin Papst
9da46bbdcd re-using menu translation for tags (#1717) 2020-05-18 16:03:45 +02:00
Kevin Papst
e3749c8e8f added pdf template and other invoice improvements (#1693) 2020-05-10 16:19:59 +02:00
Kevin Papst
4e1ffedc20 make export layout definitions changeable (#1684) 2020-05-02 12:55:30 +02:00
Kevin Papst
35f864256f include project name in invoice name (#1672) 2020-04-29 18:51:33 +02:00
Kevin Papst
ad2698dae2 fixed multilineIndent (#1669) 2020-04-28 17:13:02 +02:00
Kevin Papst
46a7b13293 display more columns in invoice template listing (#1663) 2020-04-25 16:34:15 +02:00
Kevin Papst
cbd7124cec fix removing single permissions from event (#1661) 2020-04-24 19:02:21 +02:00
Kevin Papst
0debc70ead support budget and timeBudget in API calls (#1658) 2020-04-23 18:49:48 +02:00
Kevin Papst
f8331b74c7 using font awesome icon to render color dot (#1656) 2020-04-23 16:47:50 +02:00
Kevin Papst
12c4205785 added translate filter for meta-fields in detail pages (#1655) 2020-04-23 16:45:50 +02:00
Kevin Papst
8f5c4dc4ec fix API annotation for customer collection (#1654) 2020-04-23 16:28:03 +02:00
Kevin Papst
711139ad4c delete invoices (#1652)
* include all meta fields as template variables
* support invoice preview via command
* support deletion of generated invoices
2020-04-23 12:19:07 +02:00
Kevin Papst
cfe0724620 prepare release 1.9 (#1635) 2020-04-19 19:31:43 +02:00
Kevin Papst
aeef1dae2e bump version 2020-04-19 15:39:19 +02:00
Kevin Papst
0f3fa8fdbe Code improvements (#1649)
* use global namespace for faster lookups
* phpstan level 5
2020-04-19 14:37:14 +02:00
Lukas
7b25e9acaf added events for timesheet actions (#1598) 2020-04-15 18:07:14 +02:00
Kevin Papst
be00a519b3 show expired projects in search filter (#1641) 2020-04-15 16:19:32 +02:00
Kevin Papst
4254c2590a remove roles from users when role is deleted (#1640) 2020-04-15 15:44:28 +02:00
Kevin Papst
57254bf175 fix duration calculation in admin timesheet view (#1639) 2020-04-15 11:48:18 +02:00
Kevin Papst
fe8fecafeb minimize count and visibility columns for better table alignments (#1636) 2020-04-15 11:46:54 +02:00
jojoemade
0bc9e74853 added colors to tags (#1631) 2020-04-14 14:18:11 +02:00
KuboF Hromoslav
1dfceeea99 Update Czech translation (#1630) 2020-04-12 18:36:59 +02:00
Kevin Papst
68d703d1e3 added internal rates (#1591) 2020-04-08 14:50:15 +02:00
KuboF Hromoslav
82c713031e Esperanto translations (#1607) 2020-04-07 22:19:52 +02:00
Kevin Papst
5579c3d04f allow to create default team if none with the project/customer name exists (#1624) 2020-04-07 19:07:06 +02:00
Kevin Papst
5e7b0c7826 fixed restart timesheet with tags with active record (#1622) 2020-04-07 17:30:39 +02:00
Kevin Papst
9e1e1a7a96 added event before rendering permissions (#1599) 2020-03-30 01:22:57 +02:00
Kevin Papst
7becddc3a4 allow all characters as search term in API (#1597) 2020-03-30 01:06:18 +02:00
Kevin Papst
dfe949264f update funding for sponsors information 2020-03-28 10:49:32 +01:00
Kevin Papst
163fb1be4a fix non-ascii character break invoice download (#1592) 2020-03-27 00:55:23 +01:00
Kevin Papst
33f76f426c customize html and pdf exports with twig templates (#1582) 2020-03-23 01:51:02 +01:00
Kevin Papst
1ca1b00d11 added json, xml and txt invoice renderer (#1576) 2020-03-21 01:01:47 +01:00
Kevin Papst
c89750fe94 ensure user attributes are truncated (#1580) 2020-03-21 00:21:06 +01:00
Adrian Rudnik
fb2ce0d30a xlsx improvements (#1518) 2020-03-20 18:29:26 +01:00
Kevin Papst
b8c5323ece added command to create invoices via bash (#1574) 2020-03-20 13:14:05 +01:00
Kevin Papst
7b13ea860a switch to kimai specific user-bundle fork (#1568) 2020-03-17 21:24:51 +01:00
Kevin Papst
4b1cfa5840 added multi-select for customer, project and activity (#1557) 2020-03-16 14:06:26 +01:00
Kevin Papst
6eeb01ad48 validate v1 data before import (#1552) 2020-03-15 23:34:14 +01:00
Kevin Papst
e6e6a1eeea added invoice archive & configurable invoice numbers (#1541) 2020-03-14 01:16:58 +01:00
Kevin Papst
dd64eb98f9 support more columns in listings (#1548) 2020-03-13 18:21:16 +01:00
Kevin Papst
9cd111bae5 fix timesheet permissions for non-admins (#1542) 2020-03-13 18:02:35 +01:00
Kevin Papst
137dcbf7e1 update to latest composer libs (#1545) 2020-03-12 19:33:11 +01:00
Kevin Papst
fbdc668a22 show short summary under export table (#1547) 2020-03-12 17:05:51 +01:00
Kevin Papst
7f931cbfd3 highlight overlapping times (#1534) 2020-03-12 16:35:25 +01:00
Kevin Papst
7b7a962e04 fix deprecations in migrations (#1544) 2020-03-12 00:42:47 +01:00
Sebastian Schreiber
e4610af235 migrate from zend-ldap to laminas-ldap (#1530) 2020-03-12 00:34:23 +01:00
Kevin Papst
e7458e76e1 improve kimai v1 importer for projects without customer (#1543) 2020-03-12 00:20:22 +01:00
Luca Buoncristiani
04a43378d8 Italian translations update (#1538) 2020-03-11 16:38:28 +01:00
Honza Kopecký
809acb47bf Import groups from Kimai v1 (#1532) 2020-03-08 12:34:17 +01:00
Kevin Papst
ace2788b57 fix pdf creation for very large exports (#1533) 2020-03-08 00:24:49 +01:00
Sebastian Schreiber
d60e738bd2 Escape distinguished name in ldap search (#1528) 2020-03-06 16:16:31 +01:00
Kevin Papst
a50a59bbca inline css for html invoices (#1526) 2020-03-06 03:21:39 +01:00
Adrian Rudnik
76a6ea57a1 fixed sweet alerts blocking major ui elements (#1517) 2020-03-06 03:02:30 +01:00
Kevin Papst
9907694ef6 disable title on small reponsive screens (#1527) 2020-03-06 02:20:30 +01:00
Kevin Papst
20b3c31cbd code cleanup for phpstan level 4 (#1522) 2020-03-05 02:15:16 +01:00
Kevin Papst
25a74ffeee fixing user specific rates in kimai v1 importer (#1521) 2020-03-05 00:18:31 +01:00
Kevin Papst
b8273c4441 prepare release 1.8 (#1505) 2020-03-01 14:25:59 +01:00
Kevin Papst
8d3a305ec3 handle negative duration (#1510) 2020-03-01 13:46:37 +01:00
Kevin Papst
72b73bc9a6 support multi-line values in excel invoices (#1507) 2020-02-29 20:06:45 +01:00
Kevin Papst
ec31d206e2 added UI configuration for default start-time (#1506) 2020-02-28 16:06:00 +01:00
Kevin Papst
bf11de82fc Upload invoice documents via UI (#1495) 2020-02-27 23:19:19 +01:00
Kevin Papst
34d2228d5d option to use decimal format in user timesheet export (#1489) 2020-02-24 18:03:30 +01:00
Kevin Papst
0e507804b1 human friendly name for bundles (#1491) 2020-02-22 22:56:37 +01:00
Kevin Papst
6c7477f1a9 edit single system config section in modal (#1490) 2020-02-22 18:53:03 +01:00
Kevin Papst
886fc8d74e action to duplicate timesheet record (#1478) 2020-02-18 15:32:33 +01:00
Kevin Papst
7b218c33f9 added generic rules for auth firewall (#1472) 2020-02-18 13:54:03 +01:00
Kevin Papst
c67617262f duplicate projects with all settings (#1465) 2020-02-13 16:47:20 +01:00
Kevin Papst
057c824e9f replaced mailer library, added email templates (#1462) 2020-02-12 16:05:13 +01:00
Kevin Papst
1b4f4bba22 added option to use only pre-defined tags (#1463) 2020-02-12 15:35:42 +01:00
Philipp Strobel
847798eec1 use different arrow for paginated box widget (#1431) 2020-02-10 22:16:16 +01:00
Kevin Papst
52c7437076 added user-specific rates (#1455) 2020-02-10 20:29:43 +01:00
Kevin Papst
465d7166d4 remove pagerfanta bundle (#1458) 2020-02-10 16:38:26 +01:00
MikKrz
733aa58de8 added Polish translations (#1426) 2020-02-10 00:23:37 +01:00
Kevin Papst
9620627ea6 fix dates in project API (#1451) 2020-02-10 00:16:44 +01:00
Kevin Papst
e06314e802 replace travis with github actions (#1452) 2020-02-09 23:54:04 +01:00
Kevin Papst
986d922855 invoices: choose language and duration format (#1438) 2020-02-04 20:27:36 +01:00
Kevin Papst
75dcae6fbe update to Symfony 4.4 (#1275) 2020-02-04 15:29:26 +01:00
Luca Buoncristiani
375691365e added missing italian translation files (#1437) 2020-02-04 13:31:20 +01:00
infeeeee
5c5af05408 fixed glyphs in pdf export table header (#1435) 2020-02-03 17:18:39 +01:00
Kevin Papst
69cf7015d8 optimize detail pages, add new permission for comment posting (#1432) 2020-02-02 18:16:23 +01:00
Kevin Papst
6a533579b7 added support for saml login (#1408) 2020-01-31 19:47:34 +01:00
Kevin Papst
3ff46e06c0 code improvements (#1423)
* removed unused mapping information
* added support for further field types
* fixed changing date objects for begin and end
* added more project fields as invoice variables
* theme update and asset rebuild
2020-01-31 17:07:14 +01:00
Kevin Papst
9e2fccb105 added pagination to working time widget (#1418) 2020-01-30 21:51:27 +01:00
Kevin Papst
f2c6d8aee1 better handling of custom field columns in tables (#1419) 2020-01-29 15:18:10 +01:00
Kevin Papst
836a530b86 API methods to handle teams and users (#1384) 2020-01-28 22:28:31 +01:00
Kevin Papst
a31e027c54 updated slovak translations (#1414) 2020-01-28 22:02:37 +01:00
Kevin Papst
a1b554b3ac various code improvements (#1415) 2020-01-28 21:57:34 +01:00
Kevin Papst
79c4c237fa support for auto linking urls with file protocol (#1402) 2020-01-22 17:25:11 +01:00
Kevin Papst
85a35a3063 prepare release 1.7 (#1388) 2020-01-19 21:50:29 +01:00
Kevin Papst
e0e391efbe prepare release 1.7 (#1388) 2020-01-19 21:49:41 +01:00
Kevin Papst
9eff89963c prepare release 1.7 (#1388) 2020-01-19 21:49:04 +01:00
Lukas
352fac26f3 added missing raw filter (#1393) 2020-01-19 21:47:40 +01:00
Lukas
8c16bf126a added missing raw filter (#1393) 2020-01-19 21:47:17 +01:00
Lukas
42de968f8f added missing raw filter (#1393) 2020-01-19 21:46:47 +01:00
ikusimakusi
ed8f024e42 added Basque translations (#1382) 2020-01-17 15:28:12 +01:00
Kevin Papst
e534369c5b fix widgets imports (#1387) 2020-01-17 00:02:02 +01:00
Kevin Papst
fed797df93 order user roles and permissions (#1372) 2020-01-16 16:54:42 +01:00
Kevin Papst
6a44dbfe83 detail pages for customers and projects (#1371) 2020-01-16 16:25:28 +01:00
Kevin Papst
28c5357f11 allow to hide rate or duration in html export summary (#1370) 2020-01-14 13:46:07 +01:00
Kevin Papst
a8824f92a1 added support on PHP 7.4 (#1355) 2020-01-07 21:43:33 +01:00
Kevin Papst
e57b69973f re-written exporter for simpler extendability (#1349) 2020-01-07 21:20:45 +01:00
Kevin Papst
d6798eed1e added project start and end date (#1303)
* added sortable js library
* activity in invoice is optional
* added javascript widget for paginated boxes
* fix activity dropdown for globals only
* added timesheet service to reduce code duplication
* use repository to query for teams in dropdowns
* added project validator
* validate project start and end against timesheet
* include begin and end in dynamic form requests for projects
* added timezone and language option to import flag, improve timesheet import speed
* deactivate cross-timezone filter
* add virtual fields to field order list
* composer update
* added param to ignore dates
* position loader icon fixed - fixes #1330
* permission problem when creating a new project - fixes #1340
* remove dev dependencies webserver and thanks bundle
* stop information leak (begin and end date) in duration mode - fixes #1307
* unify timesheet edit dialog for user and admins
* fix security issue, own rates exposed to unauthorized users in multi-update dialog
2020-01-05 02:49:01 +01:00
hmr-it-jr
50383673ca added api endpoint to return instance specific timesheet config (#1335) 2020-01-04 01:44:11 +01:00
Kevin Papst
022dbe32e5 allow empty date in export (#1338) 2019-12-31 20:24:47 +01:00
Kevin Papst
baac4eb698 set rates via batch update (#1326) 2019-12-29 16:52:43 +01:00
Kevin Papst
8aa8f452d5 added exported filter in timesheet view (#1327) 2019-12-29 13:55:15 +01:00
Kevin Papst
54255cf923 validate tag name (#1325) 2019-12-16 16:55:34 +01:00
Kevin Papst
bd3d82d224 fix daterange filter for multi-timezone setups (#1321) 2019-12-16 16:23:03 +01:00
Kevin Papst
b14ad9f3ab renamed translation files from .xliff to .xlf (#1314) 2019-12-09 13:25:31 +01:00
Kevin Papst
261b4646e4 added chinese translations (#1310) 2019-12-09 12:56:38 +01:00
Kevin Papst
d62e1c4468 simplify to add widgets via plugin (#1308) 2019-12-06 23:36:03 +01:00
benzel
5b0266c462 clarified translation (#1309) 2019-12-06 22:05:33 +01:00
Kevin Papst
06118dcabb loose email validation on customer (#1224) 2019-12-02 15:06:06 +01:00
Kevin Papst
984c852ab6 Release 1.6.2 (#1289)
* include user teams in user entity
* prevent unauthorized access via API
* improve teamlead permission handling in team timesheets
* add team data to user entity
* add security tests
* highlight menu for invoice template copy
* unified handling of invoice data across all templates
* access to the current users data in invoice templates
* permission improvement in invoice form
* allow to skip record rows
* allow to add new invoice locations without overwriting the global ones
* allow to order user preferences
* change permission for normal users with access to view_other_timesheets
* properly validate invoice template field length
* allow to replace multiple variables in cell values text
* upgraded office invoice template
* doctrine deprecation fix
* upgrade phpoffice/phpword
* fix future begin check for default rounding rules
* dashboard widget counter: respect visibility and teams - fixes #1161
* fix future begin check for default rounding rules
* added new events for pre and post invoice rendering
* fix permission issue for users without team seeing all records
* prevent error in spreadsheet renderer for empty invoices
2019-12-02 10:57:03 +01:00
Badgie
47414cfd0e Danish translations (#1296) 2019-12-02 00:25:28 +01:00
Kevin Papst
fdf4fdfb6a fix sqlite installer (#1283) 2019-11-26 19:32:16 +01:00
Kevin Papst
5ee0396a02 Release 1.6.1 (#1282) 2019-11-26 17:22:31 +01:00
Kevin Papst
724eb9c658 release 1.6 (#1277) 2019-11-24 15:29:01 +01:00
Kevin Papst
936ab05882 prepare release 1.6 (#1270) 2019-11-24 00:02:43 +01:00
Kevin Papst
817a43b178 added csv importer for timesheet and project data (#1216) 2019-11-23 22:02:55 +01:00
Kevin Papst
0f16f42887 Select2 search enhancement (#1276) 2019-11-23 14:26:35 +01:00
Kevin Papst
641c199c8c API: allow to set user for timesheet (#1259) 2019-11-23 14:21:46 +01:00
Aptevo
04dd6b900f added de_CH language (#1272) 2019-11-23 11:29:29 +01:00
Kevin Papst
536a05210e enable interactive features of Swagger UI (#1273) 2019-11-22 21:59:25 +01:00
Kevin Papst
60d16016e8 allow to configure calendar slot duration (#1269) 2019-11-22 01:30:25 +01:00
Kevin Papst
9222075c7a Added update command (#1268) 2019-11-21 23:15:41 +01:00
1willem
641dcdff85 Dutch translation files (#1226) 2019-11-18 21:48:16 +01:00
Kevin Papst
668649be7a use homepage link to redirect from error page (#1260) 2019-11-18 12:29:21 +01:00
Kevin Papst
0de936d474 fix the password reset page layout (#1261) 2019-11-18 12:28:59 +01:00
Kevin Papst
47bd8b0ce7 added new invoice fields, improved invoice templates (#1258) 2019-11-18 12:01:26 +01:00
Kevin Papst
2287c9951c invoice: money fields without currency, title cleanup (#1254) 2019-11-15 18:54:08 +01:00
Kevin Papst
94c28ebbc5 Update and delete multi timesheets and tags (#1240) 2019-11-15 01:25:31 +01:00
Kevin Papst
b4739f8f03 allow to include bundle configuration in system configuration screen (#1235) 2019-11-14 19:25:38 +01:00
Kevin Papst
c32cd36861 fix reset input for forms (#1251) 2019-11-14 19:09:55 +01:00
Kevin Papst
945562b34d fixes wrong foreign keys on timesheet_tags join table (#1242) 2019-11-14 01:57:58 +01:00
Kevin Papst
af0f89774e User roles and permission management via Admin UI (#1231) 2019-11-10 18:53:56 +01:00
Kevin Papst
c6c4098759 rounding rules via admin screen, round begin when starting record (#1229) 2019-11-10 13:57:05 +01:00
Kevin Papst
fa1c79e15c support different formats in user timesheet exports (#1222) 2019-11-08 16:10:38 +01:00
Kevin Papst
0705c26513 highlight menus on sub-pages (#1220) 2019-11-07 11:19:10 +01:00
Kevin Papst
140fa4b7c0 prepare release 1.5 (#1214) 2019-11-03 17:31:33 +01:00
Kevin Papst
cd88901868 re-style error pages (#1210) 2019-10-31 14:20:53 +01:00
Kevin Papst
8eec97deb5 respect users timezone in statistic widgets (#1207) 2019-10-31 00:17:31 +01:00
Kevin Papst
4331a7c9f4 fix error pages (#1209) 2019-10-31 00:16:25 +01:00
Kevin Papst
f4fcfeba9d dynamic branding options (#1205) 2019-10-30 14:22:34 +01:00
Kevin Papst
48aefb1862 fix avatar path for subdirectory installations (#1201) 2019-10-30 14:00:48 +01:00
Kevin Papst
bda9584346 reformat edit forms (#1192) 2019-10-30 13:59:53 +01:00
Kevin Papst
ed1154af67 fix absolute url (#1200) 2019-10-30 13:45:59 +01:00
Kevin Papst
c368eacd87 fixed renamed filter name, added that disabled users cannot be filtered (#1193) 2019-10-27 13:56:45 +01:00
Kevin Papst
949c59230f improve list views (#1191) 2019-10-25 16:21:30 +02:00
Kevin Papst
1114538f41 duration field in timesheet edit dialog (#1180) 2019-10-24 23:46:22 +02:00
Kevin Papst
b0f83291ee upgraded to phpunit 8 (#1155) 2019-10-24 17:35:05 +02:00
Kevin Papst
e91e4ff430 support search term in API collection requests (#1185) 2019-10-24 17:31:15 +02:00
Ahmed Şeref
4ad290d4bd added turkish translations (#1160) 2019-10-24 17:30:34 +02:00
Kevin Papst
37c6e2c0af added order-date field to project (#1186) 2019-10-24 17:04:21 +02:00
Kevin Papst
b4a45afce9 fix API login in subdirectory installations (#1181) 2019-10-24 11:06:12 +02:00
yayitazale
330ff6eb47 updated spanish translations (#1183) 2019-10-24 10:53:23 +02:00
Adrian Rudnik
c681eb1bdb docker fix to hide details for 500 errors (#1173) 2019-10-21 16:22:29 +02:00
Kevin Papst
de533e7031 Kimai 1.4.2 (#1167) 2019-10-14 12:30:11 +02:00
Kevin Papst
ae6ed3f23f Bugfixes for Kimai 1.4.1 (#1158)
* fix missing translation for preset datatable headers
* better dependency check for avatar service
* show only own teams to teamleads
2019-10-07 16:04:19 +02:00
Kevin Papst
32aa209b75 prepare release 1.4 (#1154) 2019-10-04 07:36:59 +02:00
Kevin Papst
e8c25d8ac5 added avatars, show user teams in list, new team dashboard widgets (#1150) 2019-10-03 13:44:16 +02:00
Kevin Papst
718ad4b398 fix migrations for older database versions (#1148) 2019-09-27 14:52:22 +02:00
Kevin Papst
8d81a394ee updated theme, fix deprecations in events dispatching (#1145) 2019-09-25 19:12:12 +02:00
Kevin Papst
d661c8b54e fix closing search dropdown (#1142)
* using a different library for javascript selects, fixing the closing search dropdown
* fix closing dropdown for daterangepicker
* added missing search button for mobile on customer page
* fix meta fields with same names than existing columns
2019-09-25 18:34:25 +02:00
Kevin Papst
e45e782e7d fix invoice preview (#1129) 2019-09-20 16:00:03 +02:00
Kevin Papst
5aa422dde1 Display meta-fields in datatables (#1116) 2019-09-19 20:28:31 +02:00
Kevin Papst
24cbe3d281 post 1.3 fixes (#1106) 2019-09-17 22:20:36 +02:00
Kevin Papst
13f5e76015 added czech translations (#1075) 2019-09-16 23:19:46 +02:00
Kevin Papst
35c65ba890 composer update (#1104) 2019-09-13 17:16:53 +02:00
Kevin Papst
8f2b82b832 bump version to 1.3 (#1102) 2019-09-12 00:36:48 +02:00
Kevin Papst
7f1a206a52 support installation specific translations (#1099) 2019-09-11 23:18:35 +02:00
Kevin Papst
8c503a226e fix API version string (#1096) 2019-09-11 21:44:14 +02:00
Kevin Papst
cdcf9eaf67 handles session timeouts in modals (#1092) 2019-09-10 17:07:34 +02:00
Kevin Papst
a651e55dc9 added table-column ordering (#1086) 2019-09-09 23:47:42 +02:00
Kevin Papst
d041a3f4f9 improved tag auto-completion and added tag management (#1083) 2019-09-04 23:47:33 +02:00
Kevin Papst
3ea05cb705 support multiple invoice repositories (#1084) 2019-09-04 22:50:53 +02:00
hmr-it-jr
3f27ab1e44 added mail icons (#1077) 2019-09-04 19:49:03 +02:00
Kevin Papst
e99b170d0a refactored search with free search term support (#1064) 2019-09-04 18:54:06 +02:00
Kevin Papst
49e1a1c410 use timesheet description in invoices (#1079) 2019-09-04 10:54:21 +02:00
Kevin Papst
93ab3d5666 post release 1.2 fixes (#1068)
* fix release command
* fix permission name in UPGRADING
* added missing korean calendar translations
* fixed entry.total for invoice with fixed rates
2019-09-03 11:59:34 +02:00
Kevin Papst
94f8159fdc prepare release 1.2 (#1059) 2019-08-27 18:37:42 +02:00
Kevin Papst
8fb0b1445a added korean translations (#1039) 2019-08-26 15:00:59 +02:00
Kevin Papst
15673555a2 added API functions to save meta fields (#1063) 2019-08-26 14:30:39 +02:00
Kevin Papst
ceeec7b8a6 improved invoice handling for fixed rates (#1058) 2019-08-24 00:02:16 +02:00
Kevin Papst
46e5650882 refactored invoice and export screens (#1046) 2019-08-22 18:56:21 +02:00
Kevin Papst
405ea0076b fix empty user language (#1054) 2019-08-21 11:16:44 +02:00
Kevin Papst
8cd7f7de3f do not delete team if linked entity is deleted (#1053) 2019-08-21 01:04:58 +02:00
Kevin Papst
7cd17154fc support creating new roles (#1050) 2019-08-20 14:02:15 +02:00
Kevin Papst
299fcb091a added documentation links to all screens (#1044) 2019-08-19 12:53:36 +02:00
Kevin Papst
025c6b0e7b added css class to target running records in timesheet tables (#1042) 2019-08-16 22:34:41 +02:00
Kevin Papst
388c3ec188 reduce field size to 150 chars to prevent index out of length (#1031) 2019-08-16 16:57:09 +02:00
Kevin Papst
b6d9bb0d2a fix team opens in modal (#1041) 2019-08-16 16:55:56 +02:00
Kevin Papst
561ec3b1e9 added team permissions (#996) 2019-08-16 01:22:33 +02:00
Kevin Papst
9611646bc6 added decimal format variable for invoice duration (#1037) 2019-08-15 21:31:13 +02:00
Kevin Papst
b5972bb680 added invoice variable to display month numerical (#1033) 2019-08-14 23:30:45 +02:00
Kevin Papst
455861ec69 copy timesheet meta fields on restart record (#1030) 2019-08-13 18:41:20 +02:00
trentks
5affa0de82 fix various minor english grammar translations (#1002) 2019-08-08 23:04:02 +02:00
Kevin Papst
e11a2a6089 upgraded FosUserBundle and Symfony 4.3 (#1005) 2019-08-02 16:52:30 +02:00
Kevin Papst
614a50ce0b added command to show plugin versions (#994) 2019-08-02 08:53:51 +02:00
Kevin Papst
66594b286a remove default role from user filter and role select (#993) 2019-08-02 08:31:45 +02:00
Kevin Papst
8e06f94bdd composer prod dependencies and commands (#986) 2019-08-01 23:21:43 +02:00
trentks
b0e03bb0b8 Fix english translation for 'info' (#995) 2019-08-01 23:01:02 +02:00
Kevin Papst
22e30b1871 fix activity import Kimai v1 (#1001) 2019-08-01 21:38:28 +02:00
Kevin Papst
8104a67e3e travis builds with mysql (#924) 2019-08-01 19:25:38 +02:00
Kevin Papst
654ffda454 respect users timezone when populating working-time dashboard widget (#988) 2019-07-30 23:57:20 +02:00
cdahinten
3f51437569 optimize DE translations (#950) 2019-07-29 13:31:00 +02:00
Kevin Papst
1bd784eef3 added calendar slot_duration config (#989) 2019-07-26 23:51:29 +02:00
yayitazale
0d11aded40 spanish update - more natural translations (#945) 2019-07-25 18:26:39 +02:00
Kevin Papst
00925d38aa fix migration for sqlite users (#985) 2019-07-25 18:00:53 +02:00
Kevin Papst
12803b3957 prepare release 1.1 (#983) 2019-07-24 19:38:46 +02:00
Kevin Papst
7583498735 added invoice calculator to sum by day (#982) 2019-07-24 18:36:06 +02:00
Kevin Papst
53eda31179 project grouped invoice calculator (#892) 2019-07-24 17:45:51 +02:00
Kevin Papst
56e276939b trigger template events in authentication layout as well (#981) 2019-07-24 15:32:46 +02:00
Kevin Papst
39abccb35d dashboard is missing in initial view (#974) 2019-07-24 14:47:07 +02:00
Toby Batch
dae8866053 Fixes regexp for search timesheets by tag (#978) 2019-07-22 15:34:40 +02:00
Kevin Papst
a0e8aa3a43 fixed xss in timesheet description (#962) 2019-07-14 13:58:10 +02:00
Kevin Papst
e68b7da1f8 added slovakian translations (#952) 2019-07-12 15:52:30 +02:00
Marcos Ellys Rocha Honorato
fcce7a531a updated Portuguese (Brazilian) translations (#942) 2019-07-11 00:18:42 +02:00
Kevin Papst
f23dcbec17 run migrations always in kimai:install command (#944) 2019-07-10 19:19:03 +02:00
Kevin Papst
8a1d28563d fix changing project for existing entries (#940) 2019-07-10 19:17:34 +02:00
Kevin Papst
c33a87a07c toolbar dropdown and visibility improvements (#933) 2019-07-09 16:34:11 +02:00
Toby Batch
b833e1ce27 pre-populate tags for new timesheet records via request params (#930) 2019-07-09 16:32:40 +02:00
Kevin Papst
6de1a55d73 updated swedish translations (#934) 2019-07-09 14:02:11 +02:00
Kevin Papst
cbf9086e10 performance improvements (#927) 2019-07-09 03:40:48 +02:00
Kevin Papst
eb4aa23577 allow non-interactive installation (#932) 2019-07-09 03:03:27 +02:00
Kevin Papst
bf9ae44775 fix LDAP edge-case initialization error (#931) 2019-07-08 20:35:41 +02:00
Kevin Papst
f0822fa2b1 prepare release 1.0.1 (#922) 2019-07-05 19:25:06 +02:00
Kevin Papst
f966d34929 updated all composer packages (#920) 2019-07-05 15:07:03 +02:00
Kevin Papst
d51136f8f4 cleanup prod log config (#921) 2019-07-05 13:48:24 +02:00
Kevin Papst
19843760e5 allow to configure default values for users (#919) 2019-07-05 02:42:50 +02:00
Kevin Papst
3457f93ed0 fix 500 happening in error pages (#914) 2019-07-04 17:00:55 +02:00
Kevin Papst
625ac2f1d7 fix default calendar config (#918) 2019-07-04 16:59:57 +02:00
Kevin Papst
061581c4ff use pre-defined icons in menu as well (#913) 2019-07-04 14:59:03 +02:00
Kevin Papst
a0116422c6 remove scrutinizer (#915) 2019-07-04 14:57:07 +02:00
yayitazale
94e49ea86f updated Spanish translations (#906) 2019-07-02 12:10:38 +02:00
heddi.nabbisen
040409eac7 Update japanese translation (#905) 2019-07-02 12:07:01 +02:00
Kevin Papst
baa2fca7ca Release 1.0 (#885) 2019-07-02 02:36:46 +02:00
infeeeee
1fd8139214 Update Hungarian translation (#902) 2019-07-02 00:14:31 +02:00
Kevin Papst
db5f9f639e fix selectbox is not resettable (#901) 2019-07-02 00:14:06 +02:00
Kevin Papst
90980f40f5 allow to disable user preferences by permission (#895) 2019-07-01 19:37:20 +02:00
Kevin Papst
94d68c8b64 fixed short invoice (#891) 2019-06-30 18:38:02 +02:00
Kevin Papst
834a0a873f fix migration for sqlite (#881) 2019-06-30 15:16:44 +02:00
Kevin Papst
d8621f0b7a support custom fields for timesheets, customers, projects and activities (#871) 2019-06-26 00:39:05 +02:00
Kevin Papst
994c671fd8 order users by username (#880) 2019-06-26 00:35:54 +02:00
Kevin Papst
7b95750dcf added LDAP config to set filter for finding user attributes (#877) 2019-06-23 12:38:11 +02:00
Kevin Papst
9fbbaf9b88 performance tuning on timesheets (#874) 2019-06-20 16:05:31 +02:00
Jacob Blanco
bb8572a364 fix LDAP hydration with multi-value email field (#862) 2019-06-20 15:35:22 +02:00
Kevin Papst
bdd05a275d use default_begin in duration only mode (#873) 2019-06-20 01:38:28 +02:00
Toby Batch
dcdbf23b6d load plugins in test env (#864) 2019-06-19 23:10:06 +02:00
Kevin Papst
ce6ad0bbb8 export tags in spreadsheets (#860) 2019-06-16 15:35:22 +02:00
Kevin Papst
59d2946b91 add "duration + fixed start time" tracking mode (#859) 2019-06-15 23:04:53 +02:00
Kevin Papst
92f3f4ee57 added config to brand Kimai with logo and company name (#856) 2019-06-13 19:06:02 +02:00
Kevin Papst
3311f17bbb users weekly stats as bar-chart in dashboard (#847) 2019-06-13 18:38:49 +02:00
yayitazale
e1f862507e Spanish translate updated (#852) 2019-06-13 13:41:26 +02:00
Thierry Pasquier
7e040ac216 Update of the French translation (#850) 2019-06-13 13:02:12 +02:00
Kevin Papst
515c19422d improved fixture data for demo (#848) 2019-06-11 14:55:25 +02:00
Kevin Papst
5702d7afa8 added hourly and money budgets to activity, project and customer (#843) 2019-06-11 13:18:57 +02:00
Kevin Papst
833968a87d fix LDAP install for systems without ldap extension (#846) 2019-06-11 01:25:49 +02:00
Kevin Papst
0c0e9c2f71 LDAP authentication support (#815) 2019-06-07 22:48:39 +02:00
Kevin Papst
bcf1ebd778 fixed pdf temp directory (#845) 2019-06-07 18:17:45 +02:00
heddi.nabbisen
4c82f9767f updated japanese translations (#837) 2019-06-05 13:57:08 +02:00
Kevin Papst
ab405f671e updated dockerfile (#840) 2019-06-05 13:56:31 +02:00
Kevin Papst
325d204332 added installation command (#838) 2019-06-04 23:51:37 +02:00
Kevin Papst
97feed0be6 updated frontend stack to latest versions (#729) 2019-06-03 01:43:49 +02:00
Kevin Papst
19636582ab use codecov for code coverage (#833) 2019-06-01 11:53:27 +02:00
Kevin Papst
393abe9e62 phpstan level 3, fixed deprecations, code cleanup (#811) 2019-05-28 12:24:21 +02:00
Kevin Papst
d9dca96a32 added punch-in punch-out / time-clock mode (#812) 2019-05-27 01:36:43 +02:00
Kevin Papst
ebff4a765a refactored permissions for simpler customizations (#808) 2019-05-25 17:23:15 +02:00
Kevin Papst
d18019159b fix tag query to show all tags of an item, even if not included in query (#810) 2019-05-25 16:27:01 +02:00
Kevin Papst
46905e9504 allow markdown for customer, project and activity comments (#807) 2019-05-25 00:29:23 +02:00
Kevin Papst
8b1c15ccb6 added github funding config (#804) 2019-05-24 13:16:25 +02:00
Kevin Papst
8873947a1b added phpstan for code analyzes (#806) 2019-05-24 01:11:03 +02:00
Kevin Papst
cdef22b4d1 added SECUTRITY.md for reporting vulnerabilities (#805) 2019-05-23 21:42:52 +02:00
Kevin Papst
29209105d3 improved html export (#802) 2019-05-23 18:19:56 +02:00
Kevin Papst
fea3495098 lock exported timesheets (#798) 2019-05-22 22:28:29 +02:00
Kevin Papst
871b2e52c7 use dropdown for entity actions on detail pages (#801) 2019-05-21 23:21:26 +02:00
Kevin Papst
ec174a38a9 timesheet controller refactoring (#796) 2019-05-19 23:52:43 +02:00
Kevin Papst
46ff78a4c4 fix phpunit annotations (#794) 2019-05-19 17:05:07 +02:00
Kevin Papst
d2ad87d09c improved calendar (#784) 2019-05-19 16:16:20 +02:00
Kevin Papst
1903d6fb77 fix column and max key length (#789) 2019-05-14 23:09:33 +02:00
Kevin Papst
bbe1f9beda restart via API allows to copy description (#782) 2019-05-13 17:32:01 +02:00
heddi.nabbisen
1f5710eaba updated japanese translations (#779) 2019-05-13 13:16:27 +02:00
Kevin Papst
392f8239f5 bugfix for API selects (#780) 2019-05-12 17:22:24 +02:00
Kevin Papst
5c227888f2 delete timesheets via api (#776) 2019-05-12 03:26:31 +02:00
Mathias
e29e183e84 added tags for timesheets (#604) 2019-05-12 01:40:04 +02:00
Kevin Papst
f31118292c translate date picker and charts (#775) 2019-05-12 00:56:00 +02:00
heddi.nabbisen
5f4a5364b0 add japanese translation (#774) 2019-05-11 22:37:36 +02:00
Kevin Papst
09da7cd242 javascript and api to stop and display active records (#772) 2019-05-10 13:45:09 +02:00
Björn Weinbrenner
e619b5fd31 added more entity actions (#757) 2019-05-10 02:10:37 +02:00
Kevin Papst
b1855447b8 recent activities via API (#761) 2019-05-07 22:24:28 +02:00
Kevin Papst
98f386dad6 refactored javascript to ES6 classes (#759) 2019-05-06 15:22:52 +02:00
Kevin Papst
80af3fb010 fix toolbar requests for empty choice (#758) 2019-05-05 08:31:13 +02:00
Kevin Papst
6e224c63ef improve cross database engine compatibility (#756) 2019-05-05 03:09:02 +02:00
Kevin Papst
aa113cc300 dynamically update title and visible durations for running records (#752) 2019-05-05 03:01:25 +02:00
Kevin Papst
65df1ff909 colors for visual grouping of customer, projects and activities (#751) 2019-05-04 01:45:52 +02:00
Kevin Papst
e92c2d168e entity action buttons re-designed (#746) 2019-05-03 21:10:16 +02:00
Kevin Papst
455d772095 moved shared entity fields and functions to trait (#750) 2019-05-02 18:03:40 +02:00
Kevin Papst
e80973c4d2 refactored column visibility modal to ES6 (#733) 2019-05-01 22:18:57 +02:00
Kevin Papst
721ecdbf3d prevent jumping icons in navbar between collapsed and open state (#739) 2019-04-30 18:50:31 +02:00
Kevin Papst
e6b3d4349e navbar block cleanup (#742) 2019-04-30 18:10:25 +02:00
Kevin Papst
b865add1b3 translate time-tracking in login screen and browser title (#738) 2019-04-30 17:52:19 +02:00
Kevin Papst
b35022d161 use bootstrap tooltips instead of own solution (#741) 2019-04-30 17:00:10 +02:00
Kevin Papst
62b091c77b always query timesheets by begin date (#740) 2019-04-30 14:31:10 +02:00
Kevin Papst
cdb112df05 theme update for swedish auth screens (#737) 2019-04-30 14:29:52 +02:00
Kevin Papst
6dc4fa0811 fix tests that failed around midnight (#735) 2019-04-29 02:29:40 +02:00
Kevin Papst
fb17af1afd prepare release 0.9 (#730) 2019-04-29 01:48:27 +02:00
Kevin Papst
b8811924c3 reduce config complexity by converting php format to js format (#734) 2019-04-29 00:24:23 +02:00
Kevin Papst
1b0b45649d added swedish (#732) 2019-04-28 23:55:27 +02:00
Kevin Papst
e49bd05ae6 updated authorization screen styles (#727) 2019-04-27 19:58:32 +02:00
Kevin Papst
32f0d80729 configs: overwrite via prepend, mode instead of duration_only (#715) 2019-04-26 16:14:28 +02:00
Simone Gasparini
f0f757cf75 allow dynamic export types (#703) 2019-04-25 19:33:06 +02:00
Kevin Papst
ccf4e32523 added delete timesheet API endpoint (#726) 2019-04-25 18:27:58 +02:00
Kevin Papst
56fe14c451 UI updates - new user menu, updated about and profile screen and more (#723) 2019-04-25 17:50:28 +02:00
Kevin Papst
28801bf1ea remove invalid cache header (#722) 2019-04-24 18:14:08 +02:00
Kevin Papst
460391136f API: changed date-format, camelCase instead of snake_case, null values, update and create for customer and project (#718) 2019-04-24 18:13:33 +02:00
Kevin Papst
215d4fc8bf apply users timezone to toolbar queries (#716) 2019-04-22 16:21:22 +02:00
horlabs
46cb021260 API: added activities create and update (#717) 2019-04-22 16:16:06 +02:00
Kevin Papst
f9c8028ea1 updated to Symfony 4.2 (#710) 2019-04-21 01:41:08 +02:00
Kevin Papst
32b36f42f0 remove unused role ROLE_CUSTOMER (#712) 2019-04-19 18:42:25 +02:00
Kevin Papst
48f3ad842d fix validation for create user command (#709) 2019-04-17 00:20:38 +02:00
Simone Gasparini
3251b26d9e added floor and ceil rounding modes (#695) 2019-04-16 17:36:47 +02:00
Simone Gasparini
136df3724f removed active flag in user preferences form for own profile (#696) 2019-04-16 17:30:51 +02:00
Kevin Papst
0d6b8486c4 remove the total counter from all admin pages (#708) 2019-04-16 17:20:53 +02:00
Kevin Papst
3a4aa5a001 added plugin screen (#671) 2019-04-08 18:38:56 +02:00
Kevin Papst
5bea9915f5 improved activity-project assignment in importer (#679) 2019-04-05 23:29:16 +02:00
hmr-it-jr
26de367bc5 added content-type to allowed cors header for api (#672) 2019-04-01 21:51:46 +02:00
infeeeee
3c361c9414 Updated hungarian translation (#661) 2019-03-26 15:37:28 +01:00
Kevin Papst
0d4fdc38e4 remove mailer url from about debug info (#657) 2019-03-23 13:31:52 +01:00
Kevin Papst
6f7035e4cf fixing default env var for cors header (#656) 2019-03-23 13:24:15 +01:00
Kevin Papst
38ae013e03 added cors bundle to allow external api access (#655) 2019-03-23 11:04:55 +01:00
Kevin Papst
13d9f8f3f7 added database driven system configurations with admin screen (#647) 2019-03-22 20:58:38 +01:00
Kevin Papst
e990ae4800 fix modal autofocus problem, datepicker not shown on begin date (#653) 2019-03-22 15:00:59 +01:00
Kevin Papst
6a68dc6e4f added route to redirect locale to configured homepage (#654) 2019-03-22 14:37:54 +01:00
Kevin Papst
cfc19dca25 fix pdf export cache directory (#650) 2019-03-22 14:37:25 +01:00
Kevin Papst
50318a8fc5 added command to create release packages (for FTP user) (#642) 2019-03-18 11:57:26 +01:00
Kevin Papst
bde791fa55 added begin, end and export filter for API timesheets (#639) 2019-03-14 03:34:54 +01:00
Kevin Papst
2e6f3ed864 delete directory with invalid case (#643) 2019-03-13 18:50:34 +01:00
Kevin Papst
fb6bf4319f removed dynamic database prefix (#641) 2019-03-13 15:17:18 +01:00
Kevin Papst
19bfff9899 set autofocus attribute on form fields for better keyboard support (#640) 2019-03-13 00:09:02 +01:00
Kevin Papst
f4d53e9006 replaced delete confirm dialog with modal (#638) 2019-03-12 23:24:22 +01:00
Kevin Papst
46655ad462 support subdirectories and subdomains for assets (#636) 2019-03-12 01:02:42 +01:00
blueowl04
1b6b957b23 allow non-interactive timezone conversion (#637) 2019-03-11 18:44:54 +01:00
Kevin Papst
0f6334314e removed inline documentation (#624) 2019-03-11 15:10:51 +01:00
Kevin Papst
3ac72a5c89 enhanced plugin support (#634)
- refactored admin controller and templates
- plugin support for entity actions
- changed column mail to email in customer table
- refactored theme events
2019-03-11 14:46:30 +01:00
Kevin Papst
519be2d5a2 remove invisible entities from toolbars (#628) 2019-03-08 20:22:58 +01:00
Kevin Papst
e8bc45f7dd fix random order in recent activities (#631) 2019-03-08 16:09:37 +01:00
Kevin Papst
76c3c5f2f6 fix for firefox datepicker focus problem in modals (#630) 2019-03-08 01:16:10 +01:00
Kevin Papst
54cd30c564 added support for Ante meridiem and Post meridiem format (#615) 2019-03-06 10:59:31 +01:00
Kevin Papst
e260dd84ad Improve create and start permission handling (#613) 2019-03-06 10:24:27 +01:00
Kevin Papst
bce85b04d6 added filter for global activities (#614) 2019-03-05 01:42:06 +01:00
Kevin Papst
642db480ce added new rounding mode: closest (#611) 2019-03-03 20:33:35 +01:00
Kevin Papst
bea4be881b Edit and create timesheet records in modal (#603)
- added loading indicator for datatables
- fix multiple reloads of datatable content
2019-03-03 19:43:12 +01:00
Kevin Papst
86832fb703 code cleanup (#602) 2019-02-26 02:26:37 +01:00
Kevin Papst
03aa4c9ddc Plugins support (#592) 2019-02-24 15:54:38 +01:00
Kevin Papst
36a158a805 simplified theme settings and standard layout (#586) 2019-02-23 13:51:44 +01:00
Kevin Papst
32fbebd469 order datatable items by name (#594) 2019-02-23 02:27:56 +01:00
Kevin Papst
3d4b0c3fd6 UI improvements for datatables (#593) 2019-02-22 21:25:43 +01:00
Kevin Papst
1f7ec6769a release 0.8.1 (#595) 2019-02-22 18:05:45 +01:00
Kevin Papst
239be527b8 post release fixes (#584) 2019-02-22 17:20:41 +01:00
Kevin Papst
fd4a87e3a6 Support foreign keys with SQLite (#590) 2019-02-20 20:06:19 +01:00
Kevin Papst
3f535cc506 stop navbar from breaking on mobile views (#583) 2019-02-20 00:35:04 +01:00
Kevin Papst
0b57bd51ca fix sql for only_full_group_by (#581) 2019-02-19 13:39:08 +01:00
Kevin Papst
49c78ddd9d updated CHANGELOG (#580) 2019-02-19 12:49:02 +01:00
Kevin Papst
47b7046743 release 0.8 (#567) 2019-02-19 11:03:11 +01:00
Kevin Papst
b4f1cae323 fix pagination in combination with daterange picker (#568) 2019-02-14 01:09:23 +01:00
Kevin Papst
17856e0b96 handle deleted user during import from v1 (#569) 2019-02-14 00:26:54 +01:00
Kevin Papst
8005679e60 allow to query other users timesheets via api (#563) 2019-02-14 00:04:27 +01:00
Kevin Papst
ef33233624 fix timezone problems in timesheet forms (#555) 2019-02-13 21:37:54 +01:00
Kevin Papst
2c6f57c7ce daily stats in timesheet (#552) 2019-02-13 15:36:59 +01:00
Kevin Papst
fd60d5bb17 Updated HTML invoice templates (#560) 2019-02-12 15:35:33 +01:00
Kevin Papst
742e6eb3a3 updated composer packages (#559) 2019-02-11 20:38:40 +01:00
infeeeee
331ea586f1 updated php requirements in dev-documentation (#551) 2019-02-11 16:28:27 +01:00
infeeeee
afb0eabaa4 styles: year selector width, recent activities menu width (#549) 2019-02-09 23:13:47 +01:00
Kevin Papst
afa0aa5b3a improve recent activities (#550) 2019-02-09 23:01:35 +01:00
Kevin Papst
1f99f69ecd fix daterange-picker for fr, hu and ar (#547) 2019-02-08 20:02:23 +01:00
Kevin Papst
d00596d297 convert timesheets to UTC with support for user timezone (#372) 2019-02-08 18:24:33 +01:00
Kevin Papst
8dcc18dde3 improved installation docs (#548) 2019-02-08 18:16:53 +01:00
Sanjit Patel
616d514d5a Use Symfony formatter for currency symbol placement (#542) 2019-02-08 16:56:47 +01:00
Kevin Papst
b2587c71b8 do not limit timesheet-export page size (#545) 2019-02-07 23:43:20 +01:00
Kevin Papst
816866549c added export module (#538) 2019-02-05 21:37:33 +01:00
Kevin Papst
062735c9e3 added daterange-picker and localized date-inputs (#540) 2019-02-03 21:24:30 +01:00
Kevin Papst
aae9183de6 highlight current day in date-picker (#527) 2019-02-02 15:27:02 +01:00
Kevin Papst
7f3e2d453f updated documentation (#536) 2019-02-01 16:33:55 +01:00
Kevin Papst
1b42aed34c support remote data in beta-test selectpicker (#529) 2019-01-31 12:59:25 +01:00
Kevin Papst
974806d145 Improve allowed running records (#528) 2019-01-29 20:45:04 +01:00
Kevin Papst
fe4c3c10d6 added configurable view after login (#523) 2019-01-29 02:15:12 +01:00
Kevin Papst
67dab35b57 prepare release 0.7 (#514) 2019-01-28 01:40:42 +01:00
Kevin Papst
55d8bc9ba5 pagination without reload while keeping filters applied (#521) 2019-01-23 18:48:17 +01:00
Kevin Papst
572f01ed74 go back to calendar after editing and creation of time-records (#519) 2019-01-23 17:30:45 +01:00
Kevin Papst
ee32d6f926 fix wrong include filename in user registration (#520) 2019-01-23 14:16:37 +01:00
Kevin Papst
89abaa9dda fetch toolbar results without page reload (#518) 2019-01-23 02:45:33 +01:00
Kevin Papst
a9ece209ae Form and theme improvements (#513) 2019-01-21 13:10:53 +01:00
Lukas
47ac50b4d0 Only one running timesheet: automatically stop others (#386) 2019-01-21 12:49:22 +01:00
Kevin Papst
5539f68a54 validation for future and negative times (#512) 2019-01-21 01:51:57 +01:00
Kevin Papst
5b1ec1eb8f alphabetical order for selectboxes (#510) 2019-01-19 19:24:29 +01:00
Kevin Papst
a609cbf84a export team timesheets (#508) 2019-01-19 00:25:00 +01:00
Kevin Papst
1ad440f488 support template variable entry.row for docx if description is not used (#504) 2019-01-18 16:19:02 +01:00
Kevin Papst
64330e6cc4 display invoice entries in ascending order (#505) 2019-01-18 14:32:08 +01:00
Kevin Papst
03421c099a fix broken sql in activity admin (#506)
* fix broken sql in activity admin
* pre-select customer for existing activities
2019-01-18 14:30:20 +01:00
Lukas
b5c4084452 support anchor links for inline documentation (#482) 2019-01-17 23:30:02 +01:00
Kevin Papst
5d5b971f57 do not display admin menu if it has no children (#500) 2019-01-17 01:25:00 +01:00
Lukas
825d31af20 improve login screen and simplify customizations (#493) 2019-01-17 01:01:30 +01:00
Toby Batch
7880f980a8 Better composer install in docker (#481) 2018-12-21 14:32:04 +01:00
Steve Colson
137fd69f47 Update dockerfile for https in composer installer (#478) 2018-12-20 13:01:09 +01:00
Kevin Papst
ed8efcf139 support line breaks in docx (#466) 2018-12-07 11:24:39 +01:00
Kevin Papst
7fa3b67cc4 updated README and installation docu (#465) 2018-12-05 23:47:59 +01:00
Kevin Papst
93c500fbf2 fix segmentation fault - rollback composer dependencies (#463) 2018-12-05 00:01:48 +01:00
Kevin Papst
c58c12ea3d fixed null project for advanced invoice calculator (#462) 2018-12-03 22:36:38 +01:00
Kevin Papst
35305ad107 updated all composer packages (#459) 2018-12-03 20:24:22 +01:00
Kevin Papst
589d750e59 allow decimals in users hourly rate (#460) 2018-12-03 20:23:52 +01:00
Kevin Papst
43b488f21f moved some packages to dev requirements (#456) 2018-12-01 19:53:44 +01:00
Matheus
54d06462fc added portuguese translations (#446) 2018-11-28 18:22:05 +01:00
Kevin Papst
2d6109d587 simplify timesheet edit form if only one customer is existing (#443) 2018-11-28 15:05:12 +01:00
Kevin Papst
8fddf627bf added configurable permission system (#424) 2018-11-26 13:20:32 +01:00
Kevin Papst
0334f6ce86 added project variables for invoice templates (#439) 2018-11-23 15:56:06 +01:00
Kevin Papst
025558e58e fix restart timesheet button (#436) 2018-11-22 21:48:05 +01:00
Kevin Papst
f74547008d prepare release 0.6.1 (#433) 2018-11-19 16:17:28 +01:00
Kevin Papst
67dc1c7640 fix migration for MySQL (#430) 2018-11-19 15:24:00 +01:00
Kevin Papst
40322c6de4 fix importer for MySQL #428 (#429) 2018-11-19 00:32:12 +01:00
Kevin Papst
417675b3df prepare release 0.6 (#412) 2018-11-18 20:45:00 +01:00
Lukas
321ac74b6a added parsedown extension for header ids (#388) (#399) 2018-11-18 20:31:37 +01:00
Kevin Papst
b1c06eed7b API endpoint for Timesheet entries (#332) 2018-11-18 19:43:58 +01:00
Kevin Papst
8cb52e22b1 fix column visibility if unconfigured / no cookie existing (#423) 2018-11-18 02:13:44 +01:00
Kevin Papst
a073064900 redirect to user language after profile update (#421) 2018-11-15 12:06:57 +01:00
Kevin Papst
07cceca67e fix duration and rate for html invoices (#414) 2018-11-12 23:32:05 +01:00
Kevin Papst
540318fcd0 toolbar - always allow to choose global activities (#410) 2018-11-12 15:00:25 +01:00
Kevin Papst
e9cbb872d0 added further timesheet related invoice fields (#411) 2018-11-12 12:19:57 +01:00
Kevin Papst
f9dc42d1f9 option to move entries from one entity to another upon deletion (#409) 2018-11-12 00:01:49 +01:00
Kevin Papst
1dabeedaa0 show toolbar filter after submission (#407) 2018-11-11 15:32:41 +01:00
Kevin Papst
dc70ff128c full configurable data columns in all screen sizes (#404) 2018-11-10 22:22:08 +01:00
Kevin Papst
b012b7170b added global activity support in importer (#402) 2018-11-10 03:05:33 +01:00
Toby Batch
0a1c2d8440 updated docker documentation #397 (#398) 2018-11-09 14:07:49 +01:00
Toby Batch
d72596f000 added links to docker hub and production docker repo (#396) 2018-11-08 23:07:33 +01:00
Lukas
33029b2a11 fixed docu: issues- & milestone links (#395) 2018-11-07 00:45:58 +01:00
Kevin Papst
bae24dd0ec beta test: added quick search box for customers, projects and activities (#392) 2018-11-06 23:35:09 +01:00
Kevin Papst
db7de3aac1 added global activities (#259) 2018-11-06 23:10:34 +01:00
Kevin Papst
c66dfbc653 added links to further docker images by the community (#394) 2018-11-06 22:30:44 +01:00
Kevin Papst
51c207e025 fixed broken toolbar form with empty date (#391) 2018-11-05 22:26:57 +01:00
Lukas
e44e2442af updated invoice documentation (#387) 2018-11-04 15:55:34 +01:00
infeeeee
86f40083ef Added Hungarian translation (#385) 2018-11-02 23:38:12 +01:00
Kevin Papst
f45fbbce60 improved docs and cross-linked docker (#383) 2018-11-02 16:11:40 +01:00
srdco
c648866cb4 Update installation instructions for non-server (#382) 2018-11-01 12:28:39 +01:00
Kevin Papst
f8adafdabe invoice calculator to group entries by activity (#380) 2018-10-31 15:10:06 +01:00
Toby Batch
ab4a1a0a1d added dockerfile for development (#377) 2018-10-31 13:19:48 +01:00
Kevin Papst
34a3f4e275 about screen with debug information for super-admin (#378) 2018-10-29 15:28:52 +01:00
Kevin Papst
55aedcd4a8 bump version number for development (#375) 2018-10-25 22:27:43 +02:00
Kevin Papst
6633c550f5 user-profile - sidebar links and language settings (#369) 2018-10-23 23:59:38 +02:00
Kevin Papst
0165658659 added config for initial calendar view (#363) 2018-10-21 15:43:16 +02:00
Toby Batch
3075276a52 added default settings for new customer form (#358) 2018-10-21 15:27:43 +02:00
Kevin Papst
b46e752d0a decrease minimum username length to 3 character (#362) 2018-10-19 16:50:03 +02:00
Kevin Papst
ad171e7706 removed deprecated symfony/lts and updated all other packages (#354) 2018-10-12 17:51:38 +02:00
Kevin Papst
92c665436a updated admin lte theme bundle (#350) 2018-10-08 20:58:21 +02:00
Kevin Papst
2dbf433474 fixed redirect route after password reset (#345) 2018-10-07 19:12:59 +02:00
Kevin Papst
56ac642446 arabic translations and locale support in datepicker (#337) 2018-10-07 18:29:12 +02:00
Kevin Papst
2f6c0d2208 updated timesheet and email documentation (#349) 2018-10-07 16:50:20 +02:00
Kevin Papst
a32614fff8 updated required dependencies (#346) 2018-10-07 16:43:54 +02:00
Kevin Papst
53053c127e prepare release 0.5 (#326) 2018-09-27 13:35:03 +02:00
Kevin Papst
a89ef41e81 added copy invoice template action (#331) 2018-09-26 17:50:46 +02:00
Kevin Papst
eee7cb9bf4 fix spreadsheet renderer for invoices with one entry (#328) 2018-09-25 21:16:41 +02:00
Kevin Papst
98dc38ed99 timesheet export (#317)
* remove autocomplete for begin and end
* fix minute display in timesheet-edit form
* toolbar form label in separate row
* added export action
2018-09-24 16:46:10 +02:00
Kevin Papst
7bcd6a6382 added version command and api endpoint (#321) 2018-09-24 15:56:29 +02:00
Kevin Papst
73e0a75585 invoice VAT as float and database key length (#323) 2018-09-24 15:03:51 +02:00
Kevin Papst
71aa899f77 added invoice voter (#316) 2018-09-22 22:38:51 +02:00
Kevin Papst
53f82a808b improved invoices with new renderer (#306)
* added docx renderer and demo template
* added csv renderer and demo template
* added xlsx renderer and demo template
* added ods renderer and demo template
* added user calculator
* added invoice documentation
2018-09-21 01:27:56 +02:00
Kevin Papst
b035fc9ebd add stable controller tests (#305) 2018-09-07 00:44:57 +02:00
Kevin Papst
8cae5e8b3f added fixed-rate and hourly-rate for customer, project and activity (#304) 2018-09-06 23:37:25 +02:00
Kevin Papst
6163f33abf add hourly_rate and fixed_rate to timesheet entries (#302) 2018-09-05 15:27:39 +02:00
Kevin Papst
a636faa4ab added freelancer invoice template (#254) 2018-09-02 21:29:49 +02:00
Kevin Papst
ee4df36735 allow to switch language on any page (#299) 2018-09-02 20:58:19 +02:00
Thierry Pasquier
4ede5463f9 Fix duration_short format for french (#297) 2018-09-02 17:03:38 +02:00
Kevin Papst
4c277fe1b5 allow markdown in timesheet descriptions (#296) 2018-09-02 12:10:49 +02:00
Kevin Papst
9f6079ad8a added option to delete invoice template (#294) 2018-09-02 11:36:04 +02:00
2454 changed files with 236191 additions and 33694 deletions

30
.codecov.yml Normal file
View File

@@ -0,0 +1,30 @@
codecov:
notify:
require_ci_to_pass: yes
coverage:
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
comment:
layout: "diff, flags, files"
behavior: default
require_changes: yes
require_base: no
require_head: yes
branches: null

View File

@@ -3,8 +3,17 @@ root = true
; Unix-style newlines
[*]
end_of_line = LF
end_of_line = lf
charset = utf-8
[*.php]
indent_style = space
indent_size = 4
indent_size = 4
[*.yaml]
indent_style = space
indent_size = 4
[*.yml]
indent_style = space
indent_size = 4

View File

@@ -1,29 +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
# KIMAI DEFAULT ENV VARS
DATABASE_PREFIX=kimai2_
# 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
###> symfony/framework-bundle ###
# 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
#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 ###
###> symfony/swiftmailer-bundle ###
# For Gmail as a transport, use: "gmail://username:password@localhost"
# For a generic SMTP server, use: "smtp://localhost:25?encryption=&auth_mode="
# Delivery is disabled by default via "null://localhost"
MAILER_URL=null://localhost
###< symfony/swiftmailer-bundle ###
# 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

2
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
github: [kevinpapst]
custom: ["https://www.kimai.org/donate/", "https://www.paypal.me/kevinpapst"]

View File

@@ -1,22 +0,0 @@
## Description
## Expected Behavior
## Actual Behavior
## Possible Fix
## Steps to Reproduce
1.
2.
3.
4.
## Your Environment
* Version:
* Browser Name and version:
* Operating System and version (desktop or mobile):

View File

@@ -1,6 +1,9 @@
---
name: Bug report
about: Create a report to help us improve
about: Found a problem? Create a report to help us improve Kimai
title: ''
labels: bug
assignees: ''
---
@@ -8,28 +11,17 @@ about: Create a report to help us improve
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
3. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Logfile**
```
Add the last lines from your logfile at "var/log/prod.log" or "Doctor > Logs", around the time when the problem happened.
```
**Additional context**
Add any other context about the problem here.
- Kimai version: ?.?
- PHP version: ?.?
- Device: [Ubuntu Laptop 16 inch, Windows Desktop 27 inch, iPhone 6s]
- Browser [e.g. Firefox 81, Chrome 85, Safari 14]

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

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: "Support / Questions / Discussions"
url: https://github.com/kevinpapst/kimai2/discussions
about: "This forum is for support questions: eg. if you need help with your Kimai installation, want to know how to use a Kimai feature or wonder where to start creating a new Kimai plugin."

View File

@@ -1,6 +1,9 @@
---
name: Feature request
about: Suggest an idea for this project
about: Suggest an idea to make Kimai better
title: ''
labels: feature request
assignees: ''
---
@@ -13,5 +16,5 @@ 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.
**Screenshot**
Add a mockup / screenshot of your idea here.

View File

@@ -1,5 +1,5 @@
## Description
A clear and concise description of what this pull request adds or changes.
## Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
@@ -7,8 +7,6 @@
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
## Checklist
- [ ] My code follows the code style
- [ ] All files have a license header
- [ ] All methods have a doc header with type declarations
- [ ] I have updated the documentation accordingly
- [ ] I have added tests to cover my changes
- [ ] I verified that my code applies to the guidelines (`composer code-check`)
- [ ] I updated the documentation (see [here](https://github.com/kimai/www.kimai.org/tree/master/_documentation))
- [ ] I agree that this code is used in Kimai and will be published under the [MIT license](https://github.com/kevinpapst/kimai2/blob/master/LICENSE)

22
.github/lock.yaml vendored
View File

@@ -1,22 +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.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: false
# Limit to only `issues` or `pulls`
# only: pulls

69
.github/workflows/coverage.yaml vendored Normal file
View File

@@ -0,0 +1,69 @@
name: Coverage
on:
pull_request: null
push:
branches:
- master
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: ['8.0']
name: Coverage (${{ matrix.php }})
steps:
- 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, 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@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
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

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

98
.github/workflows/testing.yaml vendored Normal file
View File

@@ -0,0 +1,98 @@
name: Tests
on:
pull_request: null
push:
branches:
- master
jobs:
integration:
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.4', '8.0', '8.1']
name: Integration (${{ matrix.php }})
steps:
- 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, mysql, zip, gd, ldap
tools: cs2pr:1.1.0
- 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: 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?serverVersion=5.7
APP_ENV: dev
MAILER_URL: null://localhost

View File

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

45
.gitignore vendored
View File

@@ -1,17 +1,40 @@
# ========== KIMAI ==========
# IDE
# some hosters require a htaccess to change the PHP version
.htaccess
.env-*
.idea/
.DS_Store
# for symfony local webserver
php.ini
/bin/*
!bin/console
/config/packages/local.yaml
/config/packages/*-local.yaml
/config/packages/*/local.yaml
/config/packages/*/*-local.yaml
/config/bundles-local.php
/var/data/kimai.sqlite
public/avatars/*.png
templates/invoice/renderer/.~lock*
translations/branding.*.xlf
/var/data/*
!/var/data/.gitkeep
/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
@@ -25,10 +48,6 @@
/vendor/
###< symfony/framework-bundle ###
###> symfony/web-server-bundle ###
.web-server-pid
###< symfony/web-server-bundle ###
###> phpunit/phpunit ###
/phpunit.xml
/.phpunit.result.cache
@@ -37,13 +56,17 @@
###> friendsofphp/php-cs-fixer ###
.php_cs
.php_cs.cache
.php-cs-fixer.cache
###< friendsofphp/php-cs-fixer ###
###> symfony/webpack-encore-pack ###
/node_modules/
###< symfony/webpack-encore-pack ###
###> symfony/phpunit-bridge ###
.phpunit
/phpunit.xml
###< symfony/phpunit-bridge ###
###> symfony/webpack-encore-bundle ###
/node_modules/
npm-debug.log
yarn-error.log
###< symfony/webpack-encore-bundle ###
/nbproject/*

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,10 +101,10 @@ 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' => true,
'phpdoc_no_empty_return' => false,
'phpdoc_no_package' => true,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_return_self_reference' => true,
@@ -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,
@@ -141,6 +142,18 @@ return PhpCsFixer\Config::create()
'method',
'property',
]],
'native_function_invocation' => [
'include' => [
'@compiler_optimized'
],
'scope' => 'namespaced'
],
'native_function_type_declaration_casing' => true,
'no_alias_functions' => [
'sets' => [
'@internal'
]
],
])
->setFinder(
PhpCsFixer\Finder::create()
@@ -151,3 +164,5 @@ return PhpCsFixer\Config::create()
)
->setFormat('checkstyle')
;
return $fixer;

View File

@@ -1,35 +0,0 @@
build:
environment:
node: v8.11.2
nodes:
analysis:
tests:
override:
- js-scrutinizer-run
- php-scrutinizer-run
tests:
tests:
override:
-
command: 'vendor/bin/phpunit --coverage-clover=clover.xml tests/'
coverage:
file: 'clover.xml'
format: 'clover'
-
command: 'bin/console kimai:phpcs --checkstyle=checkstyle'
analysis:
file: 'checkstyle'
format: 'php-cs-checkstyle'
filter:
excluded_paths:
- '.github/'
- 'bin/'
- 'config/'
- 'public/'
- 'templates/'
- 'translations/'
- 'var/'
dependency_paths:
- 'node_modules/'
- 'vendor/'

View File

@@ -1,34 +0,0 @@
language: php
sudo: false
cache:
directories:
- $HOME/.composer/cache/files
addons:
mariadb: '10.2'
services:
- mysql
matrix:
fast_finish: true
include:
- php: 7.1
- php: 7.2
before_install:
- if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then phpenv config-rm xdebug.ini; fi
- composer self-update
install:
- composer install
script:
- vendor/bin/phpunit tests/
- cp tests/.env.dist.sqlite .env
- bin/console doctrine:database:create -n
- bin/console doctrine:migrations:migrate -n
- cp tests/.env.dist.mysql .env
- bin/console doctrine:database:create -n
- bin/console doctrine:migrations:migrate -n

View File

@@ -1,274 +1,3 @@
# Change Log
# Changelog
## [0.4](https://github.com/kevinpapst/kimai2/tree/0.4) (2018-09-01)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.3...0.4)
**Fixed bugs:**
- Don't allow to stop an already stopped entry [\#282](https://github.com/kevinpapst/kimai2/issues/282)
- installed it, and then what??? [\#255](https://github.com/kevinpapst/kimai2/issues/255)
- fixed calendar for empty timesheet descriptions [\#265](https://github.com/kevinpapst/kimai2/pull/265) ([kevinpapst](https://github.com/kevinpapst))
- fixed .htaccess for apache users [\#260](https://github.com/kevinpapst/kimai2/pull/260) ([kevinpapst](https://github.com/kevinpapst))
**Closed issues:**
- Improve dashboard display [\#280](https://github.com/kevinpapst/kimai2/issues/280)
- CSV export [\#263](https://github.com/kevinpapst/kimai2/issues/263)
- Spanish Translation Contrib [\#248](https://github.com/kevinpapst/kimai2/issues/248)
- Administration of projects throws error if locale is "de" [\#247](https://github.com/kevinpapst/kimai2/issues/247)
- Web Installer Package for near-automated installs from browser [\#235](https://github.com/kevinpapst/kimai2/issues/235)
- Delete user [\#225](https://github.com/kevinpapst/kimai2/issues/225)
- Feature request - Monthly overview / report [\#207](https://github.com/kevinpapst/kimai2/issues/207)
**Merged pull requests:**
- fixed money display in dashboard widgets [\#291](https://github.com/kevinpapst/kimai2/pull/291) ([kevinpapst](https://github.com/kevinpapst))
- Symfony update 4.1.4 [\#290](https://github.com/kevinpapst/kimai2/pull/290) ([kevinpapst](https://github.com/kevinpapst))
- do not allow to stop already stopped timesheets [\#289](https://github.com/kevinpapst/kimai2/pull/289) ([kevinpapst](https://github.com/kevinpapst))
- added configurable formats for duration [\#287](https://github.com/kevinpapst/kimai2/pull/287) ([kevinpapst](https://github.com/kevinpapst))
- Updated russian translations [\#286](https://github.com/kevinpapst/kimai2/pull/286) ([kevinpapst](https://github.com/kevinpapst))
- Update french translation [\#279](https://github.com/kevinpapst/kimai2/pull/279) ([jeau](https://github.com/jeau))
- Fix standard date format in french [\#278](https://github.com/kevinpapst/kimai2/pull/278) ([jeau](https://github.com/jeau))
- new translations: spanish, french and italian [\#276](https://github.com/kevinpapst/kimai2/pull/276) ([kevinpapst](https://github.com/kevinpapst))
- French translation for Kimai [\#275](https://github.com/kevinpapst/kimai2/pull/275) ([jeau](https://github.com/jeau))
- updated to AdminLTE 2.4.8 [\#274](https://github.com/kevinpapst/kimai2/pull/274) ([kevinpapst](https://github.com/kevinpapst))
- fixing migration\_v1.md url [\#270](https://github.com/kevinpapst/kimai2/pull/270) ([ltsavar](https://github.com/ltsavar))
- dashboard widgets are configurable via config [\#269](https://github.com/kevinpapst/kimai2/pull/269) ([kevinpapst](https://github.com/kevinpapst))
- Spanish translation for Kimai [\#266](https://github.com/kevinpapst/kimai2/pull/266) ([cobaltos](https://github.com/cobaltos))
- moved theme settings to dynamic compiler pass [\#264](https://github.com/kevinpapst/kimai2/pull/264) ([kevinpapst](https://github.com/kevinpapst))
- Added config setting to disable password-reset and user-registration [\#261](https://github.com/kevinpapst/kimai2/pull/261) ([kevinpapst](https://github.com/kevinpapst))
- Added basic API endpoints [\#258](https://github.com/kevinpapst/kimai2/pull/258) ([kevinpapst](https://github.com/kevinpapst))
- Hotfix for Symfony Flex incompatibility with latest composer changes [\#257](https://github.com/kevinpapst/kimai2/pull/257) ([kevinpapst](https://github.com/kevinpapst))
- added italian translation [\#253](https://github.com/kevinpapst/kimai2/pull/253) ([kevinpapst](https://github.com/kevinpapst))
- Delete user [\#249](https://github.com/kevinpapst/kimai2/pull/249) ([kevinpapst](https://github.com/kevinpapst))
- dashboard widgets from event [\#246](https://github.com/kevinpapst/kimai2/pull/246) ([kevinpapst](https://github.com/kevinpapst))
- Added timesheet-calendar view [\#236](https://github.com/kevinpapst/kimai2/pull/236) ([kevinpapst](https://github.com/kevinpapst))
- Improved data fixtures [\#234](https://github.com/kevinpapst/kimai2/pull/234) ([kevinpapst](https://github.com/kevinpapst))
## [0.3](https://github.com/kevinpapst/kimai2/tree/0.3) (2018-07-22)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.2...0.3)
**Fixed bugs:**
- Missing assets in fresh installation [\#213](https://github.com/kevinpapst/kimai2/issues/213)
- Cannot remove payment terms from invoice template [\#188](https://github.com/kevinpapst/kimai2/issues/188)
- Set PHP locale for date format and month names [\#110](https://github.com/kevinpapst/kimai2/issues/110)
- Show revenue only for Admin \(wrong currency shown\) [\#19](https://github.com/kevinpapst/kimai2/issues/19)
**Closed issues:**
- Installation Issue of version1.3.1 [\#208](https://github.com/kevinpapst/kimai2/issues/208)
- Error on bin/console doctrine:schema:create [\#191](https://github.com/kevinpapst/kimai2/issues/191)
- Verifying email configuration [\#226](https://github.com/kevinpapst/kimai2/issues/226)
- Add favicon [\#205](https://github.com/kevinpapst/kimai2/issues/205)
- Install Kimai as WebApp [\#203](https://github.com/kevinpapst/kimai2/issues/203)
- Replace AvanzuAdminTheme with AdminLTE bundle [\#201](https://github.com/kevinpapst/kimai2/issues/201)
- Document DB requirements in install docu [\#196](https://github.com/kevinpapst/kimai2/issues/196)
- easier creation of tasks [\#195](https://github.com/kevinpapst/kimai2/issues/195)
- Integrate lock bot [\#183](https://github.com/kevinpapst/kimai2/issues/183)
- Upgrade to FontAwesome 5 [\#179](https://github.com/kevinpapst/kimai2/issues/179)
- Add dynamic column filter [\#174](https://github.com/kevinpapst/kimai2/issues/174)
- Add register user function [\#164](https://github.com/kevinpapst/kimai2/issues/164)
- Add forgot password function - login screen [\#163](https://github.com/kevinpapst/kimai2/issues/163)
- Integrate FOSUserBundle \(for registration, password-reset, etc.\) [\#144](https://github.com/kevinpapst/kimai2/issues/144)
**Merged pull requests:**
- prepare release 0.3 [\#231](https://github.com/kevinpapst/kimai2/pull/231) ([kevinpapst](https://github.com/kevinpapst))
- Easier creation of Tasks/Projects/User [\#230](https://github.com/kevinpapst/kimai2/pull/230) ([kevinpapst](https://github.com/kevinpapst))
- Added email configuration docs [\#228](https://github.com/kevinpapst/kimai2/pull/228) ([kevinpapst](https://github.com/kevinpapst))
- Show revenue only for ROLE\_ADMIN [\#227](https://github.com/kevinpapst/kimai2/pull/227) ([kevinpapst](https://github.com/kevinpapst))
- hotfix responsiveness [\#220](https://github.com/kevinpapst/kimai2/pull/220) ([kevinpapst](https://github.com/kevinpapst))
- Integrated FOSUserBundle [\#216](https://github.com/kevinpapst/kimai2/pull/216) ([kevinpapst](https://github.com/kevinpapst))
- added auto-script to install assets [\#214](https://github.com/kevinpapst/kimai2/pull/214) ([kevinpapst](https://github.com/kevinpapst))
- added yunohost installation link [\#212](https://github.com/kevinpapst/kimai2/pull/212) ([kevinpapst](https://github.com/kevinpapst))
- added favicons and web app metadata [\#211](https://github.com/kevinpapst/kimai2/pull/211) ([kevinpapst](https://github.com/kevinpapst))
- added FAQ and database requirement docu \#196 [\#210](https://github.com/kevinpapst/kimai2/pull/210) ([kevinpapst](https://github.com/kevinpapst))
- Updated to AdminLTEBundle 1.0 [\#206](https://github.com/kevinpapst/kimai2/pull/206) ([kevinpapst](https://github.com/kevinpapst))
- replaced AvanzuAdminTheme with AdminLTE bundle [\#202](https://github.com/kevinpapst/kimai2/pull/202) ([kevinpapst](https://github.com/kevinpapst))
- allow empty invoice template terms \#188 [\#189](https://github.com/kevinpapst/kimai2/pull/189) ([kevinpapst](https://github.com/kevinpapst))
- improved install docs and composer [\#187](https://github.com/kevinpapst/kimai2/pull/187) ([kevinpapst](https://github.com/kevinpapst))
- added lock-bot config \#183 [\#186](https://github.com/kevinpapst/kimai2/pull/186) ([kevinpapst](https://github.com/kevinpapst))
- Composer package name [\#185](https://github.com/kevinpapst/kimai2/pull/185) ([kevinpapst](https://github.com/kevinpapst))
- added dynamic column filter \#174 [\#184](https://github.com/kevinpapst/kimai2/pull/184) ([kevinpapst](https://github.com/kevinpapst))
- updated to font-awesome 5 \#179 [\#181](https://github.com/kevinpapst/kimai2/pull/181) ([kevinpapst](https://github.com/kevinpapst))
- language specific money and date display [\#180](https://github.com/kevinpapst/kimai2/pull/180) ([kevinpapst](https://github.com/kevinpapst))
## [0.2](https://github.com/kevinpapst/kimai2/tree/0.2) (2018-06-23)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.1...0.2)
**Fixed bugs:**
- Change to users language after login [\#7](https://github.com/kevinpapst/kimai2/issues/7)
- Prevent end time before start time [\#152](https://github.com/kevinpapst/kimai2/issues/152)
- Importing old data fails [\#145](https://github.com/kevinpapst/kimai2/issues/145)
- Translate LanguageType choices [\#83](https://github.com/kevinpapst/kimai2/issues/83)
- Mobile alignments and toolbar \#151 [\#157](https://github.com/kevinpapst/kimai2/pull/157) ([kevinpapst](https://github.com/kevinpapst))
- Improved mobile view \#151 [\#150](https://github.com/kevinpapst/kimai2/pull/150) ([kevinpapst](https://github.com/kevinpapst))
**Closed issues:**
- Add english translation [\#8](https://github.com/kevinpapst/kimai2/issues/8)
- Add configurable system configuration [\#6](https://github.com/kevinpapst/kimai2/issues/6)
- Add CHANGELOG.md [\#177](https://github.com/kevinpapst/kimai2/issues/177)
- Hide notifications after some seconds [\#169](https://github.com/kevinpapst/kimai2/issues/169)
- Add preview blog message and info text on old website [\#162](https://github.com/kevinpapst/kimai2/issues/162)
- Setup Scrutinizer to run code sniffer [\#158](https://github.com/kevinpapst/kimai2/issues/158)
- Local config to overwrite settings [\#153](https://github.com/kevinpapst/kimai2/issues/153)
- Improve mobile view [\#151](https://github.com/kevinpapst/kimai2/issues/151)
- Upgrade to Symfony 4.1 [\#149](https://github.com/kevinpapst/kimai2/issues/149)
- Replace has\_role\(\) with is\_granted\(\) [\#148](https://github.com/kevinpapst/kimai2/issues/148)
- Add help text to form elements [\#138](https://github.com/kevinpapst/kimai2/issues/138)
- Duration mode: creating new timesheet records prefills duration with some seconds [\#137](https://github.com/kevinpapst/kimai2/issues/137)
- Add duration-only mode [\#131](https://github.com/kevinpapst/kimai2/issues/131)
- Add help controller [\#129](https://github.com/kevinpapst/kimai2/issues/129)
- \[RFC\] Encore: configureFilenames with hash after filename instead of in the filename [\#125](https://github.com/kevinpapst/kimai2/issues/125)
- \[RFC\] Kimai license header [\#124](https://github.com/kevinpapst/kimai2/issues/124)
- Secure create-user command [\#123](https://github.com/kevinpapst/kimai2/issues/123)
- Setup travis to run phpunit tests [\#120](https://github.com/kevinpapst/kimai2/issues/120)
- Add command for building a production release [\#115](https://github.com/kevinpapst/kimai2/issues/115)
- Add webpack and webpack-encore for frontend assets [\#113](https://github.com/kevinpapst/kimai2/issues/113)
- Add time rounding option [\#112](https://github.com/kevinpapst/kimai2/issues/112)
- Add field order number in Projects [\#107](https://github.com/kevinpapst/kimai2/issues/107)
- Create docu for invoice templates [\#106](https://github.com/kevinpapst/kimai2/issues/106)
- Add invoice template: timesheet [\#104](https://github.com/kevinpapst/kimai2/issues/104)
- Add importer from Kimai v1 [\#102](https://github.com/kevinpapst/kimai2/issues/102)
- Setup error pages [\#100](https://github.com/kevinpapst/kimai2/issues/100)
- Add basic HTML invoice rendering [\#97](https://github.com/kevinpapst/kimai2/issues/97)
- Add russian translation [\#95](https://github.com/kevinpapst/kimai2/issues/95)
- Filter user in timesheet admin [\#93](https://github.com/kevinpapst/kimai2/issues/93)
- Support to switch theme settings [\#89](https://github.com/kevinpapst/kimai2/issues/89)
- Roles should become a real table [\#86](https://github.com/kevinpapst/kimai2/issues/86)
- Fix Doctrine extensions config loader [\#84](https://github.com/kevinpapst/kimai2/issues/84)
- Upgrade to Symfony 4 and Flex [\#74](https://github.com/kevinpapst/kimai2/issues/74)
- Add remember me login [\#53](https://github.com/kevinpapst/kimai2/issues/53)
- Add preferences sidebar [\#10](https://github.com/kevinpapst/kimai2/issues/10)
- Add user settings [\#9](https://github.com/kevinpapst/kimai2/issues/9)
**Merged pull requests:**
- \[WIP\] Translations [\#173](https://github.com/kevinpapst/kimai2/pull/173) ([simonschaufi](https://github.com/simonschaufi))
- prepare v0.2 release \#177 [\#178](https://github.com/kevinpapst/kimai2/pull/178) ([kevinpapst](https://github.com/kevinpapst))
- various documentation updates [\#176](https://github.com/kevinpapst/kimai2/pull/176) ([kevinpapst](https://github.com/kevinpapst))
- code styles: header\_comment and ordered\_imports [\#175](https://github.com/kevinpapst/kimai2/pull/175) ([kevinpapst](https://github.com/kevinpapst))
- Code sniffer rules \#158 [\#172](https://github.com/kevinpapst/kimai2/pull/172) ([kevinpapst](https://github.com/kevinpapst))
- Set default locale for unit-tests [\#171](https://github.com/kevinpapst/kimai2/pull/171) ([kevinpapst](https://github.com/kevinpapst))
- Hide success notification after 5 seconds [\#170](https://github.com/kevinpapst/kimai2/pull/170) ([kevinpapst](https://github.com/kevinpapst))
- Added validation for end date before start date [\#167](https://github.com/kevinpapst/kimai2/pull/167) ([kevinpapst](https://github.com/kevinpapst))
- Security expression \#148 [\#166](https://github.com/kevinpapst/kimai2/pull/166) ([kevinpapst](https://github.com/kevinpapst))
- Composer install [\#165](https://github.com/kevinpapst/kimai2/pull/165) ([kevinpapst](https://github.com/kevinpapst))
- added scrutinizer config \#158 [\#161](https://github.com/kevinpapst/kimai2/pull/161) ([kevinpapst](https://github.com/kevinpapst))
- Update to Symfony 4.1 \#149 [\#160](https://github.com/kevinpapst/kimai2/pull/160) ([kevinpapst](https://github.com/kevinpapst))
- Updated README [\#159](https://github.com/kevinpapst/kimai2/pull/159) ([kevinpapst](https://github.com/kevinpapst))
- Local config \#153 [\#156](https://github.com/kevinpapst/kimai2/pull/156) ([kevinpapst](https://github.com/kevinpapst))
- Filter in hidden toolbar - improved mobile \#151 [\#155](https://github.com/kevinpapst/kimai2/pull/155) ([kevinpapst](https://github.com/kevinpapst))
- added russian translation \#95 [\#147](https://github.com/kevinpapst/kimai2/pull/147) ([kevinpapst](https://github.com/kevinpapst))
- Bugfix importer \(\#145\) [\#146](https://github.com/kevinpapst/kimai2/pull/146) ([kevinpapst](https://github.com/kevinpapst))
- help text and link for form labels \#138 [\#143](https://github.com/kevinpapst/kimai2/pull/143) ([kevinpapst](https://github.com/kevinpapst))
- bugfix for duration\_only mode \#137 [\#142](https://github.com/kevinpapst/kimai2/pull/142) ([kevinpapst](https://github.com/kevinpapst))
- Make the back link appear like a normal link instead of a button [\#139](https://github.com/kevinpapst/kimai2/pull/139) ([simonschaufi](https://github.com/simonschaufi))
- Use short array syntax [\#135](https://github.com/kevinpapst/kimai2/pull/135) ([simonschaufi](https://github.com/simonschaufi))
- Duration only mode \#131 [\#134](https://github.com/kevinpapst/kimai2/pull/134) ([kevinpapst](https://github.com/kevinpapst))
- added controller to render markdown documentation \#129 [\#132](https://github.com/kevinpapst/kimai2/pull/132) ([kevinpapst](https://github.com/kevinpapst))
- Rounding rules [\#128](https://github.com/kevinpapst/kimai2/pull/128) ([kevinpapst](https://github.com/kevinpapst))
- Secure create-user command [\#127](https://github.com/kevinpapst/kimai2/pull/127) ([simonschaufi](https://github.com/simonschaufi))
- ConfigureFilenames with hash after filename [\#126](https://github.com/kevinpapst/kimai2/pull/126) ([simonschaufi](https://github.com/simonschaufi))
- added webpack-encore for managing frontend assets \#113 [\#122](https://github.com/kevinpapst/kimai2/pull/122) ([kevinpapst](https://github.com/kevinpapst))
- Remove personal mentions in license header [\#119](https://github.com/kevinpapst/kimai2/pull/119) ([simonschaufi](https://github.com/simonschaufi))
- Add github issue and pull request template [\#118](https://github.com/kevinpapst/kimai2/pull/118) ([simonschaufi](https://github.com/simonschaufi))
- Improvements [\#114](https://github.com/kevinpapst/kimai2/pull/114) ([kevinpapst](https://github.com/kevinpapst))
- added first docu on extending kimai with bundles \#106 [\#109](https://github.com/kevinpapst/kimai2/pull/109) ([kevinpapst](https://github.com/kevinpapst))
- added order number to projects \#107 [\#108](https://github.com/kevinpapst/kimai2/pull/108) ([kevinpapst](https://github.com/kevinpapst))
- added short invoice calculator and timesheet invoice template \#104 [\#105](https://github.com/kevinpapst/kimai2/pull/105) ([kevinpapst](https://github.com/kevinpapst))
- added command to import data from kimai v1 \#102 [\#103](https://github.com/kevinpapst/kimai2/pull/103) ([kevinpapst](https://github.com/kevinpapst))
- Error pages \#100 [\#101](https://github.com/kevinpapst/kimai2/pull/101) ([kevinpapst](https://github.com/kevinpapst))
- added basic invoice rendering \#97 [\#99](https://github.com/kevinpapst/kimai2/pull/99) ([kevinpapst](https://github.com/kevinpapst))
- added remember me feature \#53 [\#98](https://github.com/kevinpapst/kimai2/pull/98) ([kevinpapst](https://github.com/kevinpapst))
- code-cleanup: removed unused classes, added role constants, phpcs fixes [\#96](https://github.com/kevinpapst/kimai2/pull/96) ([kevinpapst](https://github.com/kevinpapst))
- load doctrine extensions during kernel bootstrap \#84 [\#92](https://github.com/kevinpapst/kimai2/pull/92) ([kevinpapst](https://github.com/kevinpapst))
- support theme options via user preferences \#89 [\#91](https://github.com/kevinpapst/kimai2/pull/91) ([kevinpapst](https://github.com/kevinpapst))
- added dynamic user preferences \#7 \#9 [\#90](https://github.com/kevinpapst/kimai2/pull/90) ([kevinpapst](https://github.com/kevinpapst))
- added control sidebar \#10 [\#87](https://github.com/kevinpapst/kimai2/pull/87) ([kevinpapst](https://github.com/kevinpapst))
- added english translation \#8 [\#82](https://github.com/kevinpapst/kimai2/pull/82) ([kevinpapst](https://github.com/kevinpapst))
- upgraded to symfony 4 \#74 [\#81](https://github.com/kevinpapst/kimai2/pull/81) ([kevinpapst](https://github.com/kevinpapst))
## [0.1](https://github.com/kevinpapst/kimai2/tree/0.1) (2018-01-10)
**Closed issues:**
- Hide inactive delete user button [\#78](https://github.com/kevinpapst/kimai2/issues/78)
- Delete activity [\#71](https://github.com/kevinpapst/kimai2/issues/71)
- Delete other users timesheet entries [\#70](https://github.com/kevinpapst/kimai2/issues/70)
- Delete Project [\#69](https://github.com/kevinpapst/kimai2/issues/69)
- Delete Customer [\#68](https://github.com/kevinpapst/kimai2/issues/68)
- Delete timesheet entries [\#67](https://github.com/kevinpapst/kimai2/issues/67)
- Add installation docu [\#64](https://github.com/kevinpapst/kimai2/issues/64)
- Disallow login for inactive user [\#57](https://github.com/kevinpapst/kimai2/issues/57)
- Add toolbar to filter user screen [\#56](https://github.com/kevinpapst/kimai2/issues/56)
- Upgrade to latest Avanzu version [\#55](https://github.com/kevinpapst/kimai2/issues/55)
- AdminLTE login screen [\#52](https://github.com/kevinpapst/kimai2/issues/52)
- Add edit Timesheet entry for Teamleads [\#45](https://github.com/kevinpapst/kimai2/issues/45)
- Add Timesheet Voter [\#44](https://github.com/kevinpapst/kimai2/issues/44)
- Developer improvements [\#42](https://github.com/kevinpapst/kimai2/issues/42)
- Base class for repository and query objects [\#40](https://github.com/kevinpapst/kimai2/issues/40)
- Add console command to create user [\#36](https://github.com/kevinpapst/kimai2/issues/36)
- Add basic security Voter [\#34](https://github.com/kevinpapst/kimai2/issues/34)
- Do not show hidden Activities [\#33](https://github.com/kevinpapst/kimai2/issues/33)
- Do not show hidden Projects [\#32](https://github.com/kevinpapst/kimai2/issues/32)
- Add "create timesheet record" form [\#31](https://github.com/kevinpapst/kimai2/issues/31)
- Add filter to Customer admin [\#28](https://github.com/kevinpapst/kimai2/issues/28)
- Do not show hidden Customer [\#27](https://github.com/kevinpapst/kimai2/issues/27)
- Rename Timesheet query class [\#25](https://github.com/kevinpapst/kimai2/issues/25)
- Add "create activity" functionality [\#24](https://github.com/kevinpapst/kimai2/issues/24)
- Add "create project" functionality [\#23](https://github.com/kevinpapst/kimai2/issues/23)
- Add "create customer" functionality [\#22](https://github.com/kevinpapst/kimai2/issues/22)
- Translate dashboard widgets [\#20](https://github.com/kevinpapst/kimai2/issues/20)
- Display user avatar in navbar [\#16](https://github.com/kevinpapst/kimai2/issues/16)
- Add role SUPER\_ADMIN [\#15](https://github.com/kevinpapst/kimai2/issues/15)
- Teamlead can see all user times [\#13](https://github.com/kevinpapst/kimai2/issues/13)
- Add filter to Timesheet \(user\) [\#11](https://github.com/kevinpapst/kimai2/issues/11)
- Add "create user" functionality [\#5](https://github.com/kevinpapst/kimai2/issues/5)
- Edit users role [\#4](https://github.com/kevinpapst/kimai2/issues/4)
- Add filter to Timesheet admin [\#3](https://github.com/kevinpapst/kimai2/issues/3)
- Add filter to Activity admin [\#2](https://github.com/kevinpapst/kimai2/issues/2)
- Add filter to Project admin [\#1](https://github.com/kevinpapst/kimai2/issues/1)
**Merged pull requests:**
- hide inactive delete user button \#78 [\#79](https://github.com/kevinpapst/kimai2/pull/79) ([kevinpapst](https://github.com/kevinpapst))
- added delete customer action \#68 [\#77](https://github.com/kevinpapst/kimai2/pull/77) ([kevinpapst](https://github.com/kevinpapst))
- added delete action for projects \#69 [\#76](https://github.com/kevinpapst/kimai2/pull/76) ([kevinpapst](https://github.com/kevinpapst))
- Delete actions \#71 [\#75](https://github.com/kevinpapst/kimai2/pull/75) ([kevinpapst](https://github.com/kevinpapst))
- added delete timesheet record for admins \#70 [\#73](https://github.com/kevinpapst/kimai2/pull/73) ([kevinpapst](https://github.com/kevinpapst))
- added delete timesheet records action for users \#67 [\#72](https://github.com/kevinpapst/kimai2/pull/72) ([kevinpapst](https://github.com/kevinpapst))
- added toolbar to user screen \#56 [\#66](https://github.com/kevinpapst/kimai2/pull/66) ([kevinpapst](https://github.com/kevinpapst))
- document installation options \#64 [\#65](https://github.com/kevinpapst/kimai2/pull/65) ([kevinpapst](https://github.com/kevinpapst))
- update avanzu admin bundle \#55 [\#63](https://github.com/kevinpapst/kimai2/pull/63) ([kevinpapst](https://github.com/kevinpapst))
- prevent inactive user from login \#57 [\#61](https://github.com/kevinpapst/kimai2/pull/61) ([kevinpapst](https://github.com/kevinpapst))
- handle hidden customer \#27 [\#60](https://github.com/kevinpapst/kimai2/pull/60) ([kevinpapst](https://github.com/kevinpapst))
- handle hidden projects \#32 [\#59](https://github.com/kevinpapst/kimai2/pull/59) ([kevinpapst](https://github.com/kevinpapst))
- Handle hidden activities \#33 [\#58](https://github.com/kevinpapst/kimai2/pull/58) ([kevinpapst](https://github.com/kevinpapst))
- using the AdminLTE login screen \#52 [\#54](https://github.com/kevinpapst/kimai2/pull/54) ([kevinpapst](https://github.com/kevinpapst))
- added toolbar for activity screen \#2 [\#51](https://github.com/kevinpapst/kimai2/pull/51) ([kevinpapst](https://github.com/kevinpapst))
- Added toolbar to project screen \#1 [\#50](https://github.com/kevinpapst/kimai2/pull/50) ([kevinpapst](https://github.com/kevinpapst))
- added toolbar to customer screen \#28 [\#49](https://github.com/kevinpapst/kimai2/pull/49) ([kevinpapst](https://github.com/kevinpapst))
- added form to edit timesheet entries for all user \#45 [\#48](https://github.com/kevinpapst/kimai2/pull/48) ([kevinpapst](https://github.com/kevinpapst))
- Create timesheet for User \#31 [\#47](https://github.com/kevinpapst/kimai2/pull/47) ([kevinpapst](https://github.com/kevinpapst))
- added timesheet voter \#44 [\#46](https://github.com/kevinpapst/kimai2/pull/46) ([kevinpapst](https://github.com/kevinpapst))
- Developer cleanup \#42 [\#43](https://github.com/kevinpapst/kimai2/pull/43) ([kevinpapst](https://github.com/kevinpapst))
- Repository cleanup [\#41](https://github.com/kevinpapst/kimai2/pull/41) ([kevinpapst](https://github.com/kevinpapst))
- Added voter for customer, project and activity [\#39](https://github.com/kevinpapst/kimai2/pull/39) ([kevinpapst](https://github.com/kevinpapst))
- added create user console command [\#38](https://github.com/kevinpapst/kimai2/pull/38) ([kevinpapst](https://github.com/kevinpapst))
- added "create user" functionality [\#37](https://github.com/kevinpapst/kimai2/pull/37) ([kevinpapst](https://github.com/kevinpapst))
- Added "create activity" form [\#35](https://github.com/kevinpapst/kimai2/pull/35) ([kevinpapst](https://github.com/kevinpapst))
- Added create project functionality [\#30](https://github.com/kevinpapst/kimai2/pull/30) ([kevinpapst](https://github.com/kevinpapst))
- Rename TimesheetQuery class [\#29](https://github.com/kevinpapst/kimai2/pull/29) ([kevinpapst](https://github.com/kevinpapst))
- Add customer functionality [\#26](https://github.com/kevinpapst/kimai2/pull/26) ([kevinpapst](https://github.com/kevinpapst))
- Dashboard widgets [\#21](https://github.com/kevinpapst/kimai2/pull/21) ([kevinpapst](https://github.com/kevinpapst))
- Added form to edit user roles [\#18](https://github.com/kevinpapst/kimai2/pull/18) ([kevinpapst](https://github.com/kevinpapst))
- added role ROLE\_SUPER\_ADMIN [\#17](https://github.com/kevinpapst/kimai2/pull/17) ([kevinpapst](https://github.com/kevinpapst))
- allow TEAMLEAD to see user times [\#14](https://github.com/kevinpapst/kimai2/pull/14) ([kevinpapst](https://github.com/kevinpapst))
- Timesheet toolbar [\#12](https://github.com/kevinpapst/kimai2/pull/12) ([kevinpapst](https://github.com/kevinpapst))
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
See [GitHub release page](https://github.com/kevinpapst/kimai2/releases).

View File

@@ -1,17 +1,18 @@
# Contributing
Kimai is an open source project, contributions made by the community are welcome.
Send us your ideas, code reviews, pull requests and feature requests to help us improve this project.
Send your ideas, code reviews, pull requests and feature requests to help improving this project.
## Pull request rules
- We use PSR-2 with some additional code-style checks (see our [php-cs-fixer config](.php_cs.dist)). You can run `bin/console kimai:phpcs` to check and `bin/console kimai:phpcs --fix` to fix violations.
- Add PHPUnit tests for your changes, verify everything still works and execute our test-suites `bin/console kimai:test-unit` and `bin/console kimai:test-integration`.
- If you contribute new files, please add them with the file-header template from below (our chode-style fixer can do that for you).
- With sending in a PR, you accept that your contributions/code will be published under MIT license (see the [LICENSE](LICENSE) file as well).
- If one of the PR checks fails, please fix them before asking us for a review.
- Use the [pre-configured codesniffer](.php_cs.dist)) to check for `composer kimai:codestyle` and fix `composer kimai:codestyle-fix` violations
- Add PHPUnit tests for your changes!
- Verify everything still works with `composer kimai:tests-unit` and `composer kimai:tests-integration`
- If you contribute new files, add them with the file-header template from below (the code-style fixer can do that for you)
- When sending in a PR, you must accept that your contributions/code will be published under MIT license (see the [LICENSE](LICENSE) file as well), otherwise your PR will be closed
- If one of the PR checks/builds fails, fix it before asking for a review
Further documentation can be found in the [developer documentation](var/docs/developers.md).
Further documentation can be found in the [developer documentation](https://www.kimai.org/documentation/developers.html).
### File-header template
```

12
LICENSE
View File

@@ -1,11 +1,13 @@
Copyright (c) 2017-2018 Kevin Papst
MIT License
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
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
@@ -15,5 +17,5 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

199
README.md
View File

@@ -1,165 +1,88 @@
# Kimai v2 - Time Tracking
<p align="center">
<img src="https://raw.githubusercontent.com/kimai/images/master/repository-header.png" alt="Kimai logo">
</p>
Kimai v2 - the open source time-tracking application with a mobile-first approach, read more at the [official website](http://v2.kimai.org).
<p align="center">
<a href="https://github.com/kevinpapst/kimai2/actions"><img alt="CI Status" src="https://github.com/kevinpapst/kimai2/workflows/CI/badge.svg"></a>
<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://twitter.com/kimai_org"><img alt="Twitter" src="https://img.shields.io/badge/follow-%40kimai__org-00acee"></a>
</p>
[![Latest Stable Version](https://poser.pugx.org/kevinpapst/kimai2/v/stable)](https://packagist.org/packages/kevinpapst/kimai2)
[![License](https://poser.pugx.org/kevinpapst/kimai2/license)](https://packagist.org/packages/kevinpapst/kimai2)
[![Travis Status](https://travis-ci.org/kevinpapst/kimai2.svg?branch=master)](https://travis-ci.org/kevinpapst/kimai2)
[![Code Quality](https://scrutinizer-ci.com/g/kevinpapst/kimai2/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/kevinpapst/kimai2/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/kevinpapst/kimai2/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/kevinpapst/kimai2/?branch=master)
[![Scrutinizer Status](https://scrutinizer-ci.com/g/kevinpapst/kimai2/badges/build.png?b=master)](https://scrutinizer-ci.com/g/kevinpapst/kimai2/build-status/master)
<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](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
This is the reloaded version of the open source timetracker Kimai.
The new version has not much in common with its predecessor [Kimai v1](http://www.kimai.org) besides the basic ideas of time-tracking and the current development team.
Right now its in an early development phase, its usable but some advanced features from Kimai v1 are missing by now (like export and ODT invoices).
But we already support to [import your timesheets](migration_v1.md) from Kimai v1.
It is developed with modern frameworks like [Symfony v4](https://github.com/symfony/symfony), [Doctrine](https://github.com/doctrine/),
[AdminLTE](https://github.com/kevinpapst/AdminLTEBundle/) and [many](composer.json) [more](package.json).
Kimai is a multi-language application and already translated to English. German, Italian, Frensh, Spanish and Russian.
If you want to support us in translating Kimai, please [read this documentation](var/docs/translations.md).
- [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.1.3 or higher
- One PHP extension of [PDO-SQLite](https://php.net/manual/en/ref.pdo-sqlite.php) or [PDO-MySQL](https://php.net/manual/en/ref.pdo-mysql.php) enabled (it might work with PostgreSQL and Oracle as well, but that wasn't tested and is not officially supported)
- The PHP extension [intl](https://php.net/manual/en/book.intl.php)
- The [usual Symfony application requirements](http://symfony.com/doc/current/reference/requirements.html)
- If you use MariaDB, make sure its at least v10.7.2 (see [FAQ](var/docs/faq.md))
- Kimai needs to be installed in the root directory of a domain or you need to [recompile the frontend assets](var/docs/developers.md)
- A modern browser, Kimai v2 might be broken on old browsers like IE 10
- PHP 7.3 or higher (PHP 8 supported)
- MariaDB or MySQL
- A webserver and subdomain
- PHP extensions: `gd`, `intl`, `json`, `mbstring`, `pdo`, `xsl`, `zip`
## Documentation & Roadmap
### About
Looking for more information about using Kimai? Check out our more detailed [documentation](var/docs/).
This is the new version of the open source time tracker Kimai. It is stable and production ready, ships
with many advanced features, including but not limited to:
You can see our development roadmap for the future in the [Milestones](milestones/) sections.
Our roadmap is open for changes and input from the community, please [sent us](issues/) your ideas and questions.
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 and team permissions, responsive and ready for your mobile device,
user specific rates, advanced search & filtering, money and time budgets, reporting, support for plugins and many more.
## Installation
There are [further infos about installation](var/docs/installation.md) if you have to use FTP or want to develop with Kimai.
- [Recommended setup](https://www.kimai.org/documentation/installation.html#recommended-setup) - with Git and Composer
- [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
If you want to install Kimai 2 in your production environment, then SSH into your server and change to your webserver root.
You need to install Git and [Composer](https://getcomposer.org/doc/00-intro.md) if you haven't already.
### Updating Kimai
First clone this repo:
- [Update Kimai](https://www.kimai.org/documentation/updates.html) - get the latest version
- [UPGRADING guide](UPGRADING.md) - version specific steps
```bash
git clone https://github.com/kevinpapst/kimai2.git
cd kimai2/
```
### Plugins
Make sure the [file permissions are correct](https://symfony.com/doc/current/setup/file_permissions.html):
```bash
chown -R www-data var/
chmod -R 777 var/
```
- [Plugin marketplace](https://www.kimai.org/store/) - find existing plugins here
- [Developer documentation](https://www.kimai.org/documentation/developers.html) - how to create a plugin
It's up to you which database server you want to use, Kimai v2 supports MySQL/MariaDB and SQLite.
Configure the database connection string in your the `.env` file:
```
# adjust all settings in .env to your needs
APP_ENV=prod
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
```
## Roadmap and releases
Now install all dependencies for Kimai 2:
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.
```bash
sudo -u www-data composer install --no-dev --optimize-autoloader
```
> 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.
Optionally create the database:
```bash
bin/console doctrine:database:create
```
Release versions will be created on a regular base (approx. one release every 2 months).
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 backporting changes.
Create all schema tables:
```bash
bin/console doctrine:schema:create
```
## Contributing
Make sure that upcoming updates can be correctly applied by setting the initial database version:
```bash
bin/console doctrine:migrations:version --add --all
```
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.
Warm up the cache (as webserver user):
```bash
sudo -u www-data bin/console cache:warmup --env=prod
```
In case you want to contribute, but you wouldn't know how, here are some suggestions:
Create your first user with the following command. You will be asked to enter a password afterwards:
```bash
bin/console kimai:create-user username admin@example.com ROLE_SUPER_ADMIN
```
_Tip: You can skip the "create user" step, if you are going to [import data from Kimai v1](var/docs/migration_v1.md)._
- 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 lie 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 little 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
- Contribute: You don't have to be programmer to help. The documentation and translation could use some love as well.
- Sponsor the project
For available roles, please refer to the [user documentation](var/docs/users.md).
> **NOTE**
>
> If you want to use a fully-featured web server (like Nginx or Apache) to run
> Kimai, configure it to point at the `public/` directory of the project.
> For more details, see:
> http://symfony.com/doc/current/cookbook/configuration/web_server_configuration.html
Installation complete: enjoy time-tracking :-)
## Updating Kimai
**STOP**
1. It's important that you don't execute the Installation steps before or after your upgrade
2. Make sure that you have a working database backup before you start the update
3. Read the [UPGRADING](UPGRADING.md) guide and [release information](https://github.com/kevinpapst/kimai2/releases) to check if there a further steps required
Get the latest code and install dependencies:
```bash
cd kimai2/
git pull origin master
sudo -u www-data composer install --no-dev --optimize-autoloader
```
Refresh your cache:
```bash
sudo -u www-data bin/console cache:clear --env=prod
sudo -u www-data bin/console cache:warmup --env=prod
```
And upgrade your database:
```bash
bin/console doctrine:migrations:migrate
```
Done! You can use the latest version of Kimai 2.
## Rolling releases & Git
Please note: Kimai 2 uses a rolling release concept for delivering updates.
Release versions will be created on a regular base and you can use these tags if you are familiar with Git, but we
will not provide support for any specific version (whether its bugs or installation/update docu).
Every code change, whether it's a new features or bug fixes, will be targeted against the master branch and
intensively tested before merging. We have to go this way, as we develop Kimai in our free time and want to put our
effort into the software instead of installation scripts and complicated upgrade processes.
## Extensions for Kimai 2
As Kimai 2 was built on top of Symfony, it can be extended like every other Symfony application.
We call these extensions bundles, but you might also know them as add-ons, extensions or plugins.
All available Kimai 2 bundles can be found at the [Kimai recipes](https://github.com/kimai/recipes) repository.
## Developer
If you want to develop with and for Kimai 2 please read the following documentation:
- an example on how to extend Kimai 2 can be found in this [GitHub repository](https://github.com/kevinpapst/kimai2-invoice)
- the [developer documentation](var/docs/developers.md) is available both on GitHub and your local installation
There is one simple rule in our "Code of conduct": Don't be an ass!

24
SECURITY.md Normal file
View File

@@ -0,0 +1,24 @@
# Security Policy
## Supported Versions
As announced in the [README](README.md) I only support the latest available release and master.
| Version | Supported |
|---------| ------------------ |
| master | :white_check_mark: |
| 1.17 | :white_check_mark: |
| < 1.17 | :x: |
## Reporting a Vulnerability
Please read the [Bughunter](https://www.kimai.org/documentation/bughunter.html) documentation before posting,
and then you 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.
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!

View File

@@ -1,25 +1,337 @@
# Upgrading Kimai 2
Database upgrades are currently ONLY provided for MySQL/MariaDB and SQLite.
_Make sure to create a backup before you start!_
If you plan on using e.g. PostgreSQL, please read more about the `bin/console doctrine:migrations:diff` and
`bin/console doctrine:migrations:migrate` commands and contact us, so we can integrate them into the official releases.
Read the [updates documentation](https://www.kimai.org/documentation/updates.html) to find out how
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.
A normal upgrade can be executed with these commands:
## [1.16](https://github.com/kevinpapst/kimai2/releases/tag/1.16)
```bash
git pull origin master
sudo -u www-data composer install --no-dev --optimize-autoloader
sudo -u www-data bin/console cache:clear --env=prod
sudo -u www-data bin/console cache:warmup --env=prod
bin/console doctrine:migrations:migrate
**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).**
- Invoice renderer `CSV` was removed
- 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 anymore, text like `# foo` is not converted to `<h1 id="foo">foo</h1>` anymore
### Developer
- **BC break**: removed registration of `.env` with `putenv()` - do not rely on `getenv()` as it is not thread-safe
- **BC break**: interface method signature `HtmlToPdfConverter::convertToPdf()` changed
- **BC break**: the macros `badge` and `label` do not apply the `|trans` filter any more
- **BC Break**: removed `getVisible()` (deprecated since 1.4) method on Customer, Project and Activity (use `isVisible()` instead, templates are still working)
- **BC Break**: API changes
- some representation names changed (eg. from `ActivityMetaField` to `ActivityMeta`, `TimesheetSubCollection` vs `TimesheetCollectionExpanded`), you could use `class_alias()` if you use auto-generated code from Swagger-Gen or alike
- new result types were introduced
- result data changed in some areas to smooth out inconsistencies (eg. TeamEntity fields changed in nested results)
## [1.9](https://github.com/kevinpapst/kimai2/releases/tag/1.9)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- The directory `var/data/invoices/` will be used to store archived invoice files (check file permissions)
- The default invoice number format changed. If you want to use the old one: configure `{date}` as format - see [invoice documentation](https://www.kimai.org/documentation/invoices.html)
- HTML invoice templates are now treated like other files and offered as download. If you are using relative URLs for including assets (CSS, images) you need to either inline them (see the default templates) or use absolute URLs
- Invoice templates that use the templates variables `${activity.X}` or `${project.X}` should be checked and possibly adapted, as multi-select is now possible for filtering
- Invoice templates have access to all meta-fields as variables, not only the ones marked as visible
- Rates configuration/structure changed for customer, project and activity
- **Invoice templates**: rates variables were removed
Permission changes:
- `history_invoice` - NEW: grants all features for the new invoice archive (by default for all admins)
### Developer
- **BC break**: `InvoiceItemInterface` has new methods `getType()` and `getCategory()`
- **BC break**: API fields changed - see new `/rates` endpoints
## [1.8](https://github.com/kevinpapst/kimai2/releases/tag/1.8)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- New PHP requirement: `ext-xsl` - which should be pre-installed in most environments when `ext-xml` is loaded
- New mailer library: check if emails are still working (eg. by using the "password forgotten" function) or if you need to adjust your configuration, [see docs at symfony.com](https://symfony.com/doc/current/components/mailer.html#transport)
- Support for line breaks in multiline invoice fields for spreadsheets (check your invoice templates after the update)
Permission changes:
- `comments_create_customer` - NEW: permission that allows to add new comments for customers
- `comments_create_team_customer` - NEW: permission that allows to add new comments for team members of the current customer
- `comments_create_teamlead_customer` - NEW: permission that allows to add new comments for a teamlead of the current customer
- `comments_create_project` - NEW: permission that allows to add new comments for project
- `comments_create_team_project` - NEW: permission that allows to add new comments for team members of the current project
- `comments_create_teamlead_project` - NEW: permission that allows to add new comments for a teamlead of the current project
- `edit_teamlead_project` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
- `edit_teamlead_customer` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
- `upload_invoice_template` - NEW: permission that allows to upload invoice documents from the UI
## [1.7](https://github.com/kevinpapst/kimai2/releases/tag/1.7)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
New permissions:
- `comments_customer` - show comment list on customer detail page (new feature)
- `details_customer` - show detail information for customers (customer number, vat, rates, meta-fields, assigned teams ...)
- `comments_project` - show comment list on project detail page (new feature)
- `details_project` - show detail information for projects (rates, meta-fields, assigned teams ...)
If you are using teams, please read on: The following list of permissions are now also available in the UI and they (can) replace the `X_project` and `X_customer` permissions.
They are more strict, as they allow only access to team specific items, the older permissions without `_teamlead_`/`_team_` work on a global level instead.
- `view_teamlead_customer`, `edit_teamlead_customer`, `budget_teamlead_customer`, `permissions_teamlead_customer`, `comments_teamlead_customer`, `details_teamlead_customer` - allows access to customer data when user is teamlead of a team assigned to the customer (replaces more global permission like `view_customer` for teamleads)
- `view_team_customer`, `edit_team_customer`, `budget_team_customer`, `comments_team_customer`, `details_team_customer` - allows access to customer data when user is member of a team assigned to the customer (replaces more global permission like `view_customer` for users)
- `view_teamlead_project`, `edit_teamlead_project`, `budget_teamlead_project`, `permissions_teamlead_project`, `comments_teamlead_project`, `details_teamlead_project` - allows access to customer data when user is teamlead of a team assigned to the project (replaces more global permission like `view_project` for teamleads)
- `view_team_project`, `edit_team_project`, `budget_team_project`, `comments_team_project`, `details_team_project` - allows access to customer data when user is member of a team assigned to the project (replaces more global permission like `view_project` for users)
### ExpenseBundle
**ATTENTION** due to incompatibilities in the underlying frameworks users of the ExpenseBundle need to do one more step:
You need to delete the bundle before updating: `rm -r var/plugins/ExpenseBundle`, otherwise you will run into errors during the update.
After the Kimai update was successful, you have to re-install the latest bundle version, which is compatible with Kimai 1.7 only.
### Developer
- Projects now have a start and end date and the API will only return those, which are either unconfigured or currently active, you might want to reload the list of projects once the user entered begin and end datetime OR use the new `ignoreDates` parameter.
- Doctrine bundle was updated to v2, check your code for [the usage of RegistryInterface and ObjectManager](https://github.com/doctrine/DoctrineBundle/blob/master/UPGRADE-2.0.md)
- Removed the webserver bundle and the command `server:run` - see [docs](https://www.kimai.org/documentation/developers.html)
## [1.6](https://github.com/kevinpapst/kimai2/releases/tag/1.6), [1.6.1](https://github.com/kevinpapst/kimai2/releases/tag/1.6.1), [1.6.2](https://github.com/kevinpapst/kimai2/releases/tag/1.6.2)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- Invoice changes:
- Moved CSV, ODS and XSLX invoice templates to [another repository](https://github.com/Keleo/kimai2-invoice-templates). Using them? Install them manually (see [invoice documentation](https://www.kimai.org/documentation/invoices.html)).
- Added new invoice fields (VAT, contact, payment details) and customer field (VAT). Used the twig settings before? Move them to the respective invoice template settings.
- Permissions can be managed via Admin UI. Please move your permission settings from [local.yaml to your database](https://www.kimai.org/documentation/permissions.html).
- Important permission change: regular users with the `view_other_timesheet` permission could see all timesheets. This was a legacy from the time before team permissions were introduced. If you rely on this behavior, you need to create a team with all users and the teamlead being the user who needs access to all timesheets.
### Developer
Please add default permissions to your [plugin](https://www.kimai.org/documentation/plugins.html).
## [1.5](https://github.com/kevinpapst/kimai2/releases/tag/1.5)
[Update as usual](https://www.kimai.org/documentation/updates.html)
## [1.4](https://github.com/kevinpapst/kimai2/releases/tag/1.4)
**There is a new directory, which needs to be writable by the webserver: `public/avatars/`.**
New permission (used in new dashboard widget):
- `view_team_member` - display team assignments (names, teamleads and members) for the current user
Activated Javascript select component by default (check mobile devices).
### Developer: BC breaks
- Dashboard widgets and rows need to define their `type` by FQCN
- Switched to Symfony 4.3 event types, this could fail in plugins, but only if they didn't use the official constants for event names
## [1.3](https://github.com/kevinpapst/kimai2/releases/tag/1.3)
Added `manage_tag` permission for new tag features
### Developer: BC breaks
- Refactored toolbars and search, plugins needs to be checked
- Invoices now supports multiple repositories, some method signatures had to be changed (eg. `calculateSumIdentifier()`)
## [1.2](https://github.com/kevinpapst/kimai2/releases/tag/1.2)
**If you are still using 0.7 or below, you need to upgrade to 1.1 before upgrading to this version.**
- Deleted timezone conversion command.
- Minimum password length raised from 5 to 8 character (applies only for password changes and new users)
- Maximum customer name length lowered to 150 character
- Maximum project name length lowered to 150 character
- Maximum activity name length lowered to 150 character
- Added new permission: `manage_invoice_template`
- Removed permissions: `view_invoice_template`, `create_invoice_template`, `edit_invoice_template`, `delete_invoice_template`
- Removed permission: `view_export` (using `create_export` only)
### Developer: BC breaks
- Custom export renderer need to check for usage of `Timesheet::getEnd()` as running entries can now be exported as well
## [1.1](https://github.com/kevinpapst/kimai2/releases/tag/1.1)
[Update as usual](https://www.kimai.org/documentation/updates.html), nothing special for this release if you upgrade from 1.0 / 1.0.1.
## [1.0](https://github.com/kevinpapst/kimai2/releases/tag/1.0)
This release contains several changes, as I still have the goal to stabilize the code base to prevent
such "challenges" after 1.0 for a while.
### Changes for your local.yaml
New permissions are available. You have to add them to your `local.yaml` ONLY if you use a custom permission structure,
otherwise you can't use the new features:
- `view_tag` - view all tags
- `delete_tag` - delete tags
- `edit_exported_timesheet` - allows to edit records which were exported
- `role_permissions` - view calculated permissions for user roles
- `budget_activity` - view and edit budgets for activities
- `budget_project` - view and edit budgets for projects
- `budget_customer` - view and edit budgets for customers
Removed permission:
- `system_actions` - removed experimental feature to flush app cache from the about screen
### BC BREAKS
- API: Format for queries including a datetime object fixed to use HTML5 format (previously `2019-03-02 14:23` - now `2019-03-02T14:23:00`)
- **Permission config**: the `permissions` definition in your `local.yaml` needs to be verified/changed, as the internal structure was highly optimized to simplify the definition.
Thanks to the new structure, you should be able to remove almost everything from your `local.yaml` (tip: start over from scratch!). Please read [the updated permission docu](https://www.kimai.org/documentation/permissions.html).
- default widgets were removed from `kimai.yaml`, that shouldn't cause any issues ... but if something is odd: [look here for help](https://www.kimai.org/documentation/dashboard.html)
## [0.9](https://github.com/kevinpapst/kimai2/releases/tag/0.9)
Remember to execute the necessary timezone conversion script, if you haven't updated to 0.8 before (see below)!
### BC BREAKS
This release contains some BC breaks which were necessary before 1.0 will be released (_now or never_), to prevent those BC breaks after 1.0.
- **Kimai requires PHP 7.2 now => [PHP 7.1 expired 4 month ago](https://www.php.net/supported-versions.php)**
- The `.env` variable `DATABASE_PREFIX` was removed and the table prefix is now hardcoded to `kimai2_`. If you used another prefix,
you have to rename your tables manually before starting the update process. You can delete the row `DATABASE_PREFIX` from your `.env` file.
- API: Format for DateTime objects changed, now including timezone identifier (previously `2019-03-02 14:23` - now `2019-03-02T14:23:00+00:00`), see [#718](https://github.com/kevinpapst/kimai2/pull/718)
- API: changed from snake_case to camelCase (affected fields: hourlyRate vs hourly_rate / fixedRate vs fixed_rate / orderNumber vs order_number / i18n config object)
- Plugin mechanism changed: existing Plugins have to be deleted or updated
### Apply necessary changes to your `local.yaml`:
New permissions are available:
- `system_configuration` - for accessing the new system configuration screen
- `system_actions` - for the experimental feature to flush your cache from the about screen
- `plugins` - for accessing the new plugins screen
The setting `kimai.timesheet.mode` replaces the setting `kimai.timesheet.duration_only`. If you used the duration_only mode, you need to change your config:
```yaml
# Before
kimai:
timesheet:
duration_only: true
# After
kimai:
timesheet:
mode: duration_only
```
Or switch the mode directly in the new System configuration screen within Kimai.
There might be version specific tasks that need to be executed before or after these steps, please see below
if your updated version is mentioned below.
## [0.8.1](https://github.com/kevinpapst/kimai2/releases/tag/0.8.1)
## [0.4](https://github.com/kevinpapst/kimai2/releases/tag/0.4) (2018-09-01)
A bug fixing release. Remember to execute the necessary timezone conversion script, if you haven't updated to 0.8 before (see below)!
## [0.8](https://github.com/kevinpapst/kimai2/releases/tag/0.8)
After you followed the normal update and database migration process (see above), you need to execute a bash command to convert your timesheet data for timezone support:
- Read this [pull request](https://github.com/kevinpapst/kimai2/pull/372) BEFORE you follow the instructions to convert the
timezones in your existing time records with `bin/console kimai:convert-timezone`. Without that, you will end up with wrong times in your database.
### Apply necessary changes to your `local.yaml`:
- A new boolean setting `kimai.timesheet.rules.allow_future_times` was introduced
- New permissions are available:
- `view_export` - for the new export feature
- `create_export` - for the new export feature
- `edit_export_own_timesheet` - for the new export feature
- `edit_export_other_timesheet` - for the new export feature
- `system_information` - to see the new about screen
## [0.7](https://github.com/kevinpapst/kimai2/releases/tag/0.7)
The configuration `kimai.theme.active_warning` was deprecated and should be replaced in your local.yaml,
[read config docs for more information](https://www.kimai.org/documentation/timesheet.html#limit-active-entries).
## [0.6.1](https://github.com/kevinpapst/kimai2/releases/tag/0.6.1)
A bugfix release to address database compatibility issues with older MySQL/MariaDB versions.
## [0.6](https://github.com/kevinpapst/kimai2/releases/tag/0.6)
The API has some minor BC breaks: some fields were renamed and entities have a larger attribute set than collections.
Be aware that the API is still is development mode and shouldn't be considered stable for now.
## [0.5](https://github.com/kevinpapst/kimai2/releases/tag/0.5)
Some configuration nodes were removed, if you have one of them in your `local.yaml` you need to delete them before you start the update:
- `kimai.invoice.calculator`
- `kimai.invoice.renderer`
- `kimai.invoice.number_generator`
The new config `kimai.invoice.documents` was introduced, holding a list of directories ([read more](https://www.kimai.org/documentation/invoices.html)).
**BC break:** InvoiceTemplate name was changed from 255 characters to 60. If you used longer invoice-template names, they will be truncated when upgrading the database.
Please make sure that they are unique in the first 60 character before you upgrade your database with `doctrine:migrations:migrate`.
## [0.4](https://github.com/kevinpapst/kimai2/releases/tag/0.4)
In the time between 0.3 and 0.4 there was a release of composer that introduced a BC break,
which leads to problems between Composer and Symfony Flex, resulting in an error like this when running it:
@@ -32,24 +344,12 @@ which leads to problems between Composer and Symfony Flex, resulting in an error
This can be fixed by updating Composer and Flex before executing the Kimai update:
```
sudo composer self-update
sudo -u www-data composer update symfony/flex --no-plugins
sudo -u www-data composer update symfony/flex --no-plugins --no-scripts
```
Then the full update can be executed as usual:
## [0.3](https://github.com/kevinpapst/kimai2/releases/tag/0.3)
```bash
git pull origin master
sudo -u www-data composer install --no-dev --optimize-autoloader
sudo -u www-data bin/console cache:clear --env=prod
sudo -u www-data bin/console cache:warmup --env=prod
bin/console doctrine:migrations:migrate
```
## [0.3](https://github.com/kevinpapst/kimai2/releases/tag/0.3) (2018-07-22)
**Update from 0.2:**
You need to adjust your `.env` file and add your `from` address for [all emails](https://github.com/kevinpapst/kimai2/blob/master/var/docs/emails.md) generated by Kimai 2:
You need to adjust your `.env` file and add your `from` address for [all emails](https://www.kimai.org/documentation/emails.html) generated by Kimai 2:
```
MAILER_FROM=kimai@example.com
```

99
assets/app.js Normal file
View File

@@ -0,0 +1,99 @@
// ------------------- INLINED ADMIN-LTE DEFINITIONS -------------------
// require('../vendor/kevinpapst/adminlte-bundle/Resources/assets/admin-lte');
// this was replaced to save around 300kb by:
// - removing moment locales which are not used
// - removing fullcalendar locales which are not used
// - removing icheck which is not used
// - removing jquery-ui which is not used
const $ = require('jquery');
global.$ = global.jQuery = $;
require('bootstrap-sass');
require('jquery-slimscroll');
require('select2');
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/fi');
require('select2/dist/js/i18n/fr');
require('select2/dist/js/i18n/he');
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/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');
require('select2/dist/js/i18n/sk');
require('select2/dist/js/i18n/sv');
require('select2/dist/js/i18n/tr');
require('select2/dist/js/i18n/vi');
require('select2/dist/js/i18n/zh-CN');
const Moment = require('moment');
global.moment = Moment;
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/fi');
require('moment/locale/fo');
require('moment/locale/fr');
require('moment/locale/he');
require('moment/locale/hu');
require('moment/locale/it');
require('moment/locale/ja');
require('moment/locale/ko');
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');
require('moment/locale/sk');
require('moment/locale/sv');
require('moment/locale/tr');
require('moment/locale/vi');
require('moment/locale/zh-cn');
require('daterangepicker');
// ------ AdminLTE framework ------
require('./sass/bootstrap.scss');
require('./sass/fontawesome.scss');
require('admin-lte/dist/css/AdminLTE.min.css');
require('admin-lte/dist/css/skins/_all-skins.css');
require('../vendor/kevinpapst/adminlte-bundle/Resources/assets/admin-lte-extensions.scss');
global.$.AdminLTE = {};
global.$.AdminLTE.options = {};
require('admin-lte/dist/js/adminlte.min');
// ------------------- INLINED ADMIN-LTE DEFINITIONS -------------------
// ---------------------------------------------------------------------
require('./sass/app.scss');
// ------ Kimai itself ------
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');

37
assets/calendar.js Normal file
View File

@@ -0,0 +1,37 @@
// 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');
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/fi');
require('fullcalendar/dist/locale/fr');
require('fullcalendar/dist/locale/he');
require('fullcalendar/dist/locale/hu');
require('fullcalendar/dist/locale/it');
require('fullcalendar/dist/locale/ja');
require('fullcalendar/dist/locale/ko');
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');
require('fullcalendar/dist/locale/sk');
require('fullcalendar/dist/locale/sv');
require('fullcalendar/dist/locale/tr');
require('fullcalendar/dist/locale/zh-cn');
require('fullcalendar/dist/locale/vi');
require('fullcalendar/dist/locale/en-gb'); // the last imported file is used as fallback for locales that do not exist (like EO)
require('fullcalendar/dist/fullcalendar.min.css');

2
assets/chart.js Normal file
View File

@@ -0,0 +1,2 @@
require('chart.js/dist/Chart.min');

View File

@@ -1,39 +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.
*/
@import "~bootstrap-sass/assets/stylesheets/bootstrap/variables";
.error-page {
margin-bottom: 50px;
}
@media print{
.sf-toolbar, .control-sidebar {display: none !important;}
}
@import 'content';
@import 'toolbar';
/* ================================ SIDEBAR ================================ */
/* Used for the Sidebar UserPanel (which is deactivated right now) */
.user-panel>.info {
left: 80px;
}
/* ================================ FOOTER ================================ */
footer.main-footer {
padding: 5px;
font-size: 80%;
}
@import 'invoice';
@import 'datatable';
@import 'calendar';
@import 'dashboard';
@import 'navbar';

View File

@@ -1,7 +0,0 @@
.popover-content {
.calendar-entry {
ul {
padding: 0 0 0 10px;
}
}
}

View File

@@ -1,30 +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.
*/
.content {
padding: 15px 0;
}
.content-header {
h1 {
small {
display: none;
}
}
}
@media (min-width: $screen-sm-min) {
.content-header {
h1 {
small {
display: inline-block;
}
}
}
.content {
padding: 15px;
}
}

1348
assets/css/emails.css Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +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.
*/
.invoice {
margin: 0;
}
@media (min-width: $screen-sm-min) {
.invoice {
margin: 10px 25px;
}
}
.page-header-small{
font-size: 14px;
}
div.invoice-address {
margin-top: 30px;
margin-bottom: 30px;
}
table.invoice-records {}
table.invoice-meta th {
padding-right: 40px;
}
table.invoice-sum th {
width: 70%;
}
table.invoice-sum th, table.invoice-sum td {
text-align: right;
}

View File

@@ -1,46 +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.
*/
.navbar-nav > li > a.ddt-large {
padding-top: 12px;
padding-bottom: 9px;
}
li.messages-menu ul.menu li .pull-left i {
color: #dd4b39;
}
.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>p {
overflow: hidden;
text-overflow: ellipsis;
}
.navbar-nav .start_record {
text-align: center;
}
/*
.ticktac:hover i.running{
color: #4ff131;
}
li.open .ticktac i.running{
color: #4ff131;
}
.ticktac i.stopped{
color: #fff;
}
.ticktac:hover i.stopped{
color: #4ff131;
}
.user-panel>.info {
left: 40px;
padding-top: 0px;
}
*/

View File

@@ -1,29 +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.
*/
/* Page based action buttons in the upper right corner of the content area */
.content-header > .breadcrumb {
position: absolute;
float: right;
background: transparent;
}
/* 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;
}
}
}
/* The filter form available on most pages above the datatable */
.toolbar form {
font-size: $font-size-base;
}

BIN
assets/images/signature.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

2
assets/invoice-pdf.js Normal file
View File

@@ -0,0 +1,2 @@
require('./sass/invoice-pdf.scss');

2
assets/invoice.js Normal file
View File

@@ -0,0 +1,2 @@
require('./sass/invoice.scss');

View File

@@ -0,0 +1,26 @@
/*
* 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] KimaiConfiguration: handling all configuration and runtime settings
*/
export default class KimaiConfiguration {
constructor(configurations) {
this._configurations = configurations;
}
get(name) {
return this._configurations[name];
}
has(name) {
return name in this._configurations;
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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] KimaiContainer
*
* ServiceContainer for Kimai
*/
import KimaiConfiguration from './KimaiConfiguration';
import KimaiTranslation from './KimaiTranslation';
import KimaiPlugin from './KimaiPlugin';
export default class KimaiContainer {
/**
* Create a new Container with the given configurations and translations.
*
* @param {Object} configuration
* @param {Object} translation
*/
constructor(configuration, translation) {
if (!(configuration instanceof KimaiConfiguration)) {
throw new Error('Configuration needs to a KimaiConfiguration instance');
}
this._configuration = configuration;
if (!(translation instanceof KimaiTranslation)) {
throw new Error('Configuration needs to a KimaiTranslation instance');
}
this._translation = translation;
this._plugins = [];
}
/**
* Register a new Plugin.
*
* @param {KimaiPlugin} plugin
* @returns {KimaiPlugin}
*/
registerPlugin(plugin) {
if (!(plugin instanceof KimaiPlugin)) {
throw new Error('Invalid plugin given, needs to be a KimaiPlugin instance');
}
plugin.setContainer(this);
this._plugins.push(plugin);
return plugin;
}
/**
* @param {string} name
* @returns {KimaiPlugin}
*/
getPlugin(name) {
for (let plugin of this._plugins) {
if (plugin.getId() !== null && plugin.getId() === name) {
return plugin;
}
}
throw new Error('Unknown plugin: ' + name);
}
/**
* @returns {Array<KimaiPlugin>}
*/
getPlugins() {
return this._plugins;
}
/**
* @returns {KimaiTranslation}
*/
getTranslation() {
return this._translation;
}
/**
* @returns {KimaiConfiguration}
*/
getConfiguration() {
return this._configuration;
}
}

94
assets/js/KimaiLoader.js Normal file
View File

@@ -0,0 +1,94 @@
/*
* 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] KimaiLoader: bootstrap the application and all plugins
*/
import moment from 'moment';
import KimaiTranslation from "./KimaiTranslation";
import KimaiConfiguration from "./KimaiConfiguration";
import KimaiContainer from "./KimaiContainer";
import KimaiActiveRecordsDuration from './plugins/KimaiActiveRecordsDuration.js';
import KimaiDatatableColumnView from './plugins/KimaiDatatableColumnView.js';
import KimaiThemeInitializer from "./plugins/KimaiThemeInitializer";
import KimaiDateRangePicker from "./plugins/KimaiDateRangePicker";
import KimaiDatatable from "./plugins/KimaiDatatable";
import KimaiToolbar from "./plugins/KimaiToolbar";
import KimaiAPI from "./plugins/KimaiAPI";
import KimaiSelectDataAPI from "./plugins/KimaiSelectDataAPI";
import KimaiDateTimePicker from "./plugins/KimaiDateTimePicker";
import KimaiAlternativeLinks from "./plugins/KimaiAlternativeLinks";
import KimaiAjaxModalForm from "./plugins/KimaiAjaxModalForm";
import KimaiActiveRecords from "./plugins/KimaiActiveRecords";
import KimaiRecentActivities from "./plugins/KimaiRecentActivities";
import KimaiEvent from "./plugins/KimaiEvent";
import KimaiAPILink from "./plugins/KimaiAPILink";
import KimaiAlert from "./plugins/KimaiAlert";
import KimaiAutocomplete from "./plugins/KimaiAutocomplete";
import KimaiFormSelect from "./plugins/KimaiFormSelect";
import KimaiForm from "./plugins/KimaiForm";
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 {
constructor(configurations, translations) {
// set the current locale for all javascript components
moment.locale(configurations['locale'].replace('_', '-').toLowerCase());
const kimai = new KimaiContainer(
new KimaiConfiguration(configurations),
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());
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.searchform', 'toolbar-action'));
kimai.registerPlugin(new KimaiSelectDataAPI('select[data-related-select]'));
kimai.registerPlugin(new KimaiAlternativeLinks('.alternative-link'));
kimai.registerPlugin(new KimaiAjaxModalForm('.modal-ajax-form'));
kimai.registerPlugin(new KimaiRecentActivities('li.notifications-menu'));
kimai.registerPlugin(new KimaiActiveRecords('li.messages-menu', 'li.messages-menu-empty'));
kimai.registerPlugin(new KimaiAPILink('api-link'));
kimai.registerPlugin(new KimaiAutocomplete('.js-autocomplete'));
kimai.registerPlugin(new KimaiForm());
kimai.registerPlugin(new KimaiThemeInitializer());
kimai.registerPlugin(new KimaiMultiUpdateTable());
//kimai.registerPlugin(new KimaiPauseRecord('li.messages-menu ul.menu li'));
// notify all listeners that Kimai plugins can now be registered
kimai.getPlugin('event').trigger('kimai.pluginRegister', {'kimai': kimai});
// initialize all plugins
kimai.getPlugins().map(plugin => { plugin.init(); });
// notify all listeners that Kimai is now ready to be used
kimai.getPlugin('event').trigger('kimai.initialized', {'kimai': kimai});
this.kimai = kimai;
}
getKimai() {
return this.kimai;
}
}

76
assets/js/KimaiPlugin.js Normal file
View File

@@ -0,0 +1,76 @@
/*
* 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] KimaiPlugin: base class for all plugins
*/
import KimaiContainer from "./KimaiContainer";
export default class KimaiPlugin {
/**
* Overwrite this method to initialize your plugin.
*
* It is called AFTER setContainer() and AFTER DOMContentLoaded was fired.
* You don't have access to the container before this method!
*/
init() {
}
/**
* If you return an ID, you indicate that your plugin can be used by other plugins.
*
* @returns {string|null}
*/
getId() {
return null;
}
/**
* @param {KimaiContainer} core
*/
setContainer(core) {
if (!(core instanceof KimaiContainer)) {
throw new Error('Plugin was given an invalid KimaiContainer');
}
this._core = core;
}
/**
* This function returns null, if you call it BEFORE init().
*
* @returns {KimaiContainer}
*/
getContainer() {
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

@@ -0,0 +1,37 @@
/*
* 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] KimaiTranslation: handling translation strings
*/
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

@@ -0,0 +1,33 @@
/*
* This file is part of the Kimai time-tracking app.
*
* Main JS application file for Kimai 2. This file should be included in all pages.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/*!
* [KIMAI] Wrapper class for loading Kimai app in browser script scope
*/
import KimaiLoader from "./KimaiLoader";
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], function () {
return (root.KimaiWebLoader = factory());
});
} else if (typeof module === 'object' && module.exports) {
module.exports = factory();
} else {
root.KimaiWebLoader = factory();
}
}(typeof self !== 'undefined' ? self : this, function () {
class KimaiWebLoader extends KimaiLoader {
}
return KimaiWebLoader;
}));

View File

@@ -1,19 +0,0 @@
require('../../vendor/kevinpapst/adminlte-bundle/Resources/assets/admin-lte');
require('../css/app.scss');
require('../css/datatable.scss');
require('../css/calendar.scss');
require('fullcalendar');
require('fullcalendar/dist/gcal.min');
require('fullcalendar/dist/locale-all');
require('fullcalendar/dist/fullcalendar.min.css');
// ------ for charts ------
require('chart.js/dist/Chart.min');
// ------ Kimai itself ------
require('./kimai.js');
require('./datatable.js');
require('./toolbar.js');
require('../images/default_avatar.png');

View File

@@ -1,66 +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.
*/
/** global: Cookies */
global.Cookies = require('js-cookie');
if (typeof jQuery === 'undefined') {
throw new Error('Kimai requires jQuery');
}
/* datatable
*
* @type Object
* @description $.datatable is the main object for views with data-tables.
* It's used for implementing functions and options related
* to the datatables.
*/
$.datatable = {};
$(function() {
"use strict";
$.datatable = {
saveVisibility: function (modalSelector) {
var settings = {};
var cookieName = $(modalSelector).find('form').attr('name');
$(modalSelector).find('form').find('input:checkbox:not(:checked)').each(
function () {
settings[$(this).attr('name')] = $(this).is(':checked');
}
);
if (jQuery.isEmptyObject(settings)) {
Cookies.remove(cookieName);
} else {
Cookies.set(cookieName, JSON.stringify(settings), {expires: 365});
}
$(modalSelector).modal('toggle');
location.reload();
},
changeVisibility: function (column) {
var tbl = $('table.dataTable');
var amount = tbl.find('th').length -1;
if (column < 0 || column >= amount) {
return;
}
var header = $(tbl.find('th').get(column));
if (header.css("display") === "none") {
header.show();
tbl.find('tr').each(function(){
$($(this).find('td').get(column)).show('ease');
});
} else {
header.hide();
tbl.find('tr').each(function(){
$($(this).find('td').get(column)).hide('ease');
});
}
}
};
});

View File

@@ -1,110 +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.
*/
if (typeof jQuery === 'undefined') {
throw new Error('Kimai requires jQuery');
}
/* kimai
*
* @type Object
* @description $.kimai is the main object for the template's app.
* It's used for implementing functions and options related
* to the template. Keeping everything wrapped in an object
* prevents conflict with other plugins and is a better
* way to organize our code.
*/
$.kimai = {};
$(function() {
"use strict";
$.kimai = {
init: function(options) {
if (typeof options !== 'undefined') {
$.kimai.settings = $.extend({}, $.kimai.defaults, options);
}
// ask before a delete call is executed
$('a.btn-trash').click(function (event) {
return confirm($.kimai.settings['confirmDelete']);
});
// activate the dropdown functionality
$('.dropdown-toggle').dropdown();
// auto hide success message after x seconds, as they are just meant as quick feedback and
// not as a permanent source of information
if ($.kimai.settings['alertSuccessAutoHide'] > 0) {
setTimeout(
function() {
$('div.alert-success').alert('close');
},
$.kimai.settings['alertSuccessAutoHide']
);
}
$('input[data-datepicker="on"]').daterangepicker({
singleDatePicker: true,
showDropdowns: true,
locale: {
format: "YYYY-MM-DD",
firstDay: 1
}
});
$('input[data-datetimepicker="on"]').daterangepicker({
singleDatePicker: true,
timePicker: true,
timePicker24Hour: true,
showDropdowns: true,
autoUpdateInput: false,
locale: {
cancelLabel: 'Clear',
format: "YYYY-MM-DD HH:mm",
firstDay: 1
}
});
$('input[data-datetimepicker="on"]').on('apply.daterangepicker', function(ev, picker) {
$(this).val(picker.startDate.format('YYYY-MM-DD HH:mm'));
});
/*
$('input').iCheck({
checkboxClass: 'icheckbox_square-blue',
radioClass: 'iradio_square-blue',
increaseArea: '20%' // optional
});
*/
// $.AdminLTE.pushMenu.expandOnHover();
},
pauseRecord: function(selector) {
$(selector + ' .pull-left i').hover(function () {
var link = $(this).parents('a');
link.attr('href', link.attr('href').replace('/stop', '/pause'));
$(this).removeClass('fa-stop-circle').addClass('fa-pause-circle').addClass('text-orange');
},function () {
var link = $(this).parents('a');
link.attr('href', link.attr('href').replace('/pause', '/stop'));
$(this).removeClass('fa-pause-circle').removeClass('text-orange').addClass('fa-stop-circle');
});
}
};
// default values
$.kimai.defaults = {
baseUrl: '/',
imagePath: '/images',
confirmDelete: 'Really delete?',
alertSuccessAutoHide: 5000
};
// once initialized, here are all values
$.kimai.settings = {};
});

View File

@@ -0,0 +1,152 @@
/*
* 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] KimaiAPI: easy access to API methods
*/
import jQuery from 'jquery';
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiAPI extends KimaiPlugin {
getId() {
return 'api';
}
get(url, data, callbackSuccess, callbackError) {
jQuery.ajax({
url: url,
headers: {
'X-AUTH-SESSION': true,
'Content-Type':'application/json'
},
method: 'GET',
data: data,
dataType: 'json',
success: callbackSuccess,
error: callbackError
});
}
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: {
'X-AUTH-SESSION': true,
'Content-Type':'application/json'
},
method: 'PATCH',
data: data,
dataType: 'json',
success: callbackSuccess,
error: callbackError
});
}
delete(url, callbackSuccess, callbackError) {
if (callbackError === null || callbackError === undefined) {
callbackError = this.getDeleteErrorHandler();
}
jQuery.ajax({
url: url,
headers: {
'X-AUTH-SESSION': true,
'Content-Type':'application/json'
},
method: 'DELETE',
dataType: 'json',
success: callbackSuccess,
error: callbackError
});
}
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

@@ -0,0 +1,98 @@
/*
* 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.
*/
import KimaiPlugin from "../KimaiPlugin";
/**
* Needs to be initialized with a class name.
*
* A link like <a href=# class=remoteLink> can be activated with:
* new KimaiAPILink('remoteLink')
*
* Allows to assign the given selector to any element, which then is used as click-handler
* calling an API method and trigger the event from data-event attribute afterwards.
*
* @param selector
*/
export default class KimaiAPILink extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
init() {
const self = this;
document.addEventListener('click', function(event) {
let target = event.target;
while (target !== null && !target.matches('body')) {
if (target.classList.contains(self.selector)) {
const attributes = target.dataset;
let url = attributes['href'];
if (!url) {
url = target.getAttribute('href');
}
if (attributes.question !== undefined) {
self.getContainer().getPlugin('alert').question(attributes.question, function(value) {
if (value) {
self._callApi(url, attributes);
}
});
} else {
self._callApi(url, attributes);
}
event.preventDefault();
event.stopPropagation();
}
target = target.parentNode;
}
});
}
_callApi(url, attributes)
{
const method = attributes['method'];
const eventName = attributes['event'];
const API = this.getContainer().getPlugin('api');
const eventing = this.getContainer().getPlugin('event');
const alert = this.getContainer().getPlugin('alert');
const successHandle = function(result) {
eventing.trigger(eventName);
if (attributes.msgSuccess) {
alert.success(attributes.msgSuccess);
}
};
const errorHandle = function(xhr, err) {
let message = 'action.update.error';
if (attributes.msgError) {
message = attributes.msgError;
}
API.handleError(message, xhr, err);
};
if (method === 'PATCH') {
let data = {};
if (attributes.payload) {
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

@@ -0,0 +1,125 @@
/*
* 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] KimaiActiveRecords: responsible to display the users active records
*/
import KimaiPlugin from '../KimaiPlugin';
export default class KimaiActiveRecords extends KimaiPlugin {
constructor(selector, selectorEmpty) {
super();
this.selector = selector;
this.selectorEmpty = selectorEmpty;
}
getId() {
return 'active-records';
}
init() {
this.menu = document.querySelector(this.selector);
// the menu can be hidden if user has no permissions to see it
if (this.menu === null) {
return;
}
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);
document.addEventListener('kimai.customerDelete', handle);
}
_toggleMenu(hasEntries) {
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'] = '';
}
}
const menuEmpty = document.querySelector(this.selectorEmpty);
if (menuEmpty !== null) {
menuEmpty.style.display = !hasEntries ? 'inline-block' : 'none';
}
}
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) {
return;
}
if (template === null) {
this._replaceInNode(this.menu, entries[0]);
} else {
const container = template.parentElement;
container.innerHTML = '';
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() {
const self = this;
const API= this.getContainer().getPlugin('api');
API.get(this.attributes['api'], {}, function(result) {
self.setEntries(result);
});
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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] KimaiActiveRecordsDuration: activate the updates for all active timesheet records on this page
*/
import KimaiPlugin from '../KimaiPlugin';
export default class KimaiActiveRecordsDuration extends KimaiPlugin {
getId() {
return 'timesheet-duration';
}
init() {
this.updateBrowserTitle = !!this.getConfiguration('updateBrowserTitle');
this.updateRecords();
const self = this;
const handle = function() { self.updateRecords(); };
this._updatesHandler = setInterval(handle, 10000);
// this will probably not work as expected, as other event-handler might need longer to update the DOM
document.addEventListener('kimai.timesheetUpdate', handle);
}
unregisterUpdates() {
clearInterval(this._updatesHandler);
}
updateRecords() {
let durations = [];
const activeRecords = document.querySelectorAll('[data-since]:not([data-since=""])');
if (activeRecords.length === 0) {
if (this.updateBrowserTitle) {
if (document.body.dataset['title'] === undefined) {
this.updateBrowserTitle = false;
} else {
document.title = document.body.dataset['title'];
}
}
return;
}
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;
}
if (durations.length === 0) {
return;
}
if (!this.updateBrowserTitle) {
return;
}
let title = durations.shift();
let prefix = ' | ';
for (let duration of durations.slice(0, 2)) {
title += prefix + duration;
}
document.title = title;
}
}

View File

@@ -0,0 +1,241 @@
/*
* 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] KimaiAjaxModalForm
*
* allows to assign the given selector to any element, which then is used as click-handler:
* opening a modal with the content from the URL given in the elements 'data-href' or 'href' attribute
*/
import jQuery from 'jquery';
import KimaiReducedClickHandler from "./KimaiReducedClickHandler";
export default class KimaiAjaxModalForm extends KimaiReducedClickHandler {
constructor(selector) {
super();
this.selector = selector;
}
getId() {
return 'modal';
}
init() {
const self = this;
this.isDirty = false;
this.modal = jQuery('#remote_form_modal');
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);
});
}
openUrlInModal(url, errorHandler) {
const self = this;
if (errorHandler === undefined) {
errorHandler = function(xhr, err) {
if (xhr.status === undefined || xhr.status !== 403) {
window.location = url;
}
};
}
jQuery.ajax({
url: url,
success: function(html) {
self._openFormInModal(html);
},
error: errorHandler
});
}
/**
* Returns the CSS selector for the modal form.
*
* @returns {string}
* @private
*/
_getFormIdentifier() {
return '#remote_form_modal .modal-content form';
}
_openFormInModal(html) {
const self = this;
let formIdentifier = this._getFormIdentifier();
// if any of these is found in a response, the form will be re-displayed
let flashErrorIdentifier = 'div.alert-error';
// messages to show above the form
let flashMessageIdentifier = 'div.alert';
let form = jQuery(formIdentifier);
let remoteModal = this.modal;
// will be (re-)activated later
form.off('submit');
// load new form from given content
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');
}
});
if (jQuery(html).find('#form_modal').hasClass('modal-danger')) {
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);
}
// show error flash messages
let flashMessages = jQuery(html).find(flashMessageIdentifier);
if (flashMessages.length > 0) {
jQuery('#remote_form_modal .modal-body').prepend(flashMessages);
}
// -----------------------------------------------------------------------
// a fix for firefox focus problems with datepicker in modal
// see https://github.com/kevinpapst/kimai2/issues/618
let enforceModalFocusFn = jQuery.fn.modal.Constructor.prototype.enforceFocus;
jQuery.fn.modal.Constructor.prototype.enforceFocus = function() {};
remoteModal.on('hidden.bs.modal', function () {
jQuery.fn.modal.Constructor.prototype.enforceFocus = enforceModalFocusFn;
});
// -----------------------------------------------------------------------
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) {
// 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');
const alert = self.getContainer().getPlugin('alert');
event.preventDefault();
event.stopPropagation();
jQuery.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize(),
success: function(html) {
btn.button('reset');
let hasFieldError = jQuery(html).find('#form_modal .modal-content .has-error').length > 0;
let hasFormError = jQuery(html).find('#form_modal .modal-content ul.list-unstyled li.text-danger').length > 0;
let hasFlashError = jQuery(html).find(flashErrorIdentifier).length > 0;
if (hasFieldError || hasFormError || hasFlashError) {
self._openFormInModal(html);
} else {
events.trigger(eventName);
// try to find form defined messages first ...
let msg = form.attr('data-msg-success');
if (msg === null || msg === undefined) {
// ... but if none was available, check the response to find server rendered flash-message
let flashMessage = jQuery(html).find('section.content div.row div.alert.alert-success');
if (flashMessage.length > 0) {
let flashContent = flashMessage.contents();
if (flashContent.length === 3) {
msg = flashContent[2].textContent;
}
}
}
// ... and if even that is not available, we use a generic fallback message
if (msg === null || msg === undefined) {
msg = 'action.update.success';
}
self.isDirty = false;
remoteModal.modal('hide');
alert.success(msg);
}
return false;
},
error: function(xhr, err) {
let message = form.attr('data-msg-error');
if (message === null || message === undefined) {
message = 'action.update.error';
}
if (xhr.responseJSON && xhr.responseJSON.message) {
err = xhr.responseJSON.message;
} else if (xhr.status && xhr.statusText) {
err = '[' + xhr.status +'] ' + xhr.statusText;
}
alert.error(message, err);
// this is useful for changing form fields and retrying to save (and in development to test form changes)
setTimeout(function() {
btn.button('reset');
}, 1500);
}
});
});
}
}

View File

@@ -0,0 +1,116 @@
/*
* 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] KimaiAlert: notifications for Kimai
*/
import Swal from 'sweetalert2'
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiAlert extends KimaiPlugin {
getId() {
return 'alert';
}
/**
* @param {string} title
* @param {string|array} message
*/
error(title, message) {
const translation = this.getContainer().getTranslation();
if (translation.has(title)) {
title = translation.get(title);
}
if (translation.has(message)) {
message = translation.get(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)) {
message = translation.get(message);
}
Swal.fire({
timer: 2000,
timerProgressBar: true,
toast: true,
position: 'top',
showConfirmButton: false,
icon: type,
title: message,
});
}
/**
* Callback receives a value and needs to decide what should happen with it
*
* @param message
* @param callback
*/
question(message, callback) {
const translation = this.getContainer().getTranslation();
if (translation.has(message)) {
message = translation.get(message);
}
Swal.fire({
title: message,
icon: 'question',
showCancelButton: true,
confirmButtonText: translation.get('confirm'),
cancelButtonText: translation.get('cancel')
}).then((result) => {
callback(result.value);
});
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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] KimaiAlternativeLinks
*
* allows to assign the given selector to any element, which then is used as click-handler
* redirecting to the URL given in the elements 'data-href' or 'href' attribute
*/
import jQuery from 'jquery';
import KimaiReducedClickHandler from "./KimaiReducedClickHandler";
export default class KimaiAlternativeLinks extends KimaiReducedClickHandler {
constructor(selector) {
super();
this.selector = selector;
}
init() {
this._addClickHandler(this.selector, function(href) {
window.location = href;
});
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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.
*/
import jQuery from 'jquery';
import KimaiPlugin from "../KimaiPlugin";
/**
* Supporting auto-complete fields via API.
* Currently used for timesheet tagging in toolbar and edit dialogs.
*/
export default class KimaiAutocomplete extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
init() {
this.minChars = this.getConfiguration('autoComplete');
}
getId() {
return 'autocomplete';
}
splitTagList(val) {
return val.split(/,\s*/);
}
extractLastTag(term) {
return this.splitTagList(term).pop();
}
activateAutocomplete(selector) {
const self = this;
jQuery(selector + ' ' + this.selector).each(function(index) {
const currentField = jQuery(this);
const apiUrl = currentField.attr('data-autocomplete-url');
const API = self.getContainer().getPlugin('api');
currentField
// don't navigate away from the field on tab when selecting an item
.on("keydown", function (event) {
if (event.keyCode === jQuery.ui.keyCode.TAB &&
jQuery(this).autocomplete("instance").menu.active) {
event.preventDefault();
}
})
.autocomplete({
source: function (request, response) {
const lastEntry = self.extractLastTag(request.term);
API.get(apiUrl, {'name': lastEntry}, function(data){
response(data);
});
},
search: function () {
// custom minLength
var term = self.extractLastTag(this.value);
if (term.length < self.minChars) {
return false;
}
},
focus: function () {
// prevent value inserted on focus
return false;
},
select: function (event, ui) {
var terms = self.splitTagList(this.value);
// remove the current input
terms.pop();
// check if selected tag is already in list
if (!terms.includes(ui.item.value)) {
// add the selected item
terms.push(ui.item.value);
}
// add placeholder to get the comma-and-space at the end
terms.push("");
this.value = terms.join(", ");
$(this).trigger('change');
return false;
}
}
)
;
});
}
destroyAutocomplete(selector) {
jQuery(selector + ' ' + this.selector).each(function(index) {
const currentField = jQuery(this);
currentField.autocomplete("destroy");
currentField.removeData('autocomplete');
});
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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.
*/
import KimaiPlugin from "../KimaiPlugin";
/**
* Needs to be initialized with a class name.
*
* Allows to assign the given selector to any element, which then is used as click-handler
* calling an API method and trigger the event from data-event attribute afterwards.
*
* @param selector
*/
export default class KimaiConfirmationLink extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
init() {
const self = this;
document.addEventListener('click', function(event) {
let target = event.target;
while (target !== null && !target.matches('body')) {
if (target.classList.contains(self.selector)) {
const attributes = target.dataset;
// is this a link?
let url = attributes['href'];
// or another HTML element with a custom href
if (!url) {
url = target.getAttribute('href');
}
// or is this a button?
let form = null;
if (target.type === 'submit' && target.form !== undefined) {
form = target.form;
}
if (attributes.question !== undefined) {
self.getContainer().getPlugin('alert').question(attributes.question, function(value) {
if (value) {
if (form === null) {
document.location = url;
} else {
if (url !== null) {
form.action = url;
}
form.submit();
}
}
});
}
event.preventDefault();
event.stopPropagation();
}
target = target.parentNode;
}
});
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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] KimaiDatatable: handles functionality for the datatable
*/
import jQuery from 'jquery';
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiDatatable extends KimaiPlugin {
constructor(contentAreaSelector, tableSelector) {
super();
this.contentArea = contentAreaSelector;
this.selector = tableSelector;
}
getId() {
return 'datatable';
}
init() {
const dataTable = document.querySelector(this.selector);
// not every page contains a dataTable
if (dataTable === null) {
return;
}
const attributes = dataTable.dataset;
const events = attributes['reloadEvent'];
this.fixDropdowns();
if (events === undefined) {
return;
}
const self = this;
const handle = function() { self.reloadDatatable(); };
for (let eventName of events.split(' ')) {
document.addEventListener(eventName, 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();
const form = jQuery(toolbarSelector);
let loading = '<div class="overlay"><i class="fas fa-sync fa-spin"></i></div>';
jQuery(contentArea).append(loading);
// remove the empty fields to prevent errors
let formData = jQuery(toolbarSelector + ' :input')
.filter(function(index, element) {
return jQuery(element).val() !== '';
})
.serialize();
jQuery.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: formData,
success: function(html) {
jQuery(contentArea).replaceWith(
jQuery(html).find(contentArea)
);
durations.updateRecords();
self.fixDropdowns();
},
error: function(xhr, err) {
form.submit();
}
});
}
/**
* 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

@@ -0,0 +1,110 @@
/*
* 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] KimaiDatatableColumnView: manages the visibility of data-table columns in cookies
*/
import Cookies from 'js-cookie';
import jQuery from 'jquery';
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiDatatableColumnView extends KimaiPlugin {
constructor(dataAttribute) {
super();
this.dataAttribute = dataAttribute;
}
getId() {
return 'datatable-column-visibility';
}
init() {
let dataTable = document.querySelector('[' + this.dataAttribute + ']');
if (dataTable === null) {
return;
}
this.id = dataTable.getAttribute(this.dataAttribute);
this.modal = document.getElementById('modal_' + this.id);
this.bindButtons();
}
bindButtons() {
let self = this;
this.modal.querySelector('button[data-type=save]').addEventListener('click', function() {
self.saveVisibility();
});
this.modal.querySelector('button[data-type=reset]').addEventListener('click', function() {
self.resetVisibility();
});
for (let checkbox of this.modal.querySelectorAll('form input[type=checkbox]')) {
checkbox.addEventListener('click', function () {
self.changeVisibility(checkbox.getAttribute('name'), checkbox.checked);
});
}
}
saveVisibility() {
const form = this.modal.getElementsByTagName('form')[0];
let settings = {};
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, SameSite: 'Strict'});
jQuery(this.modal).modal('toggle');
}
resetVisibility() {
const form = this.modal.getElementsByTagName('form')[0];
Cookies.remove(form.getAttribute('name'));
for (let checkbox of form.querySelectorAll('input[type=checkbox]')) {
if (!checkbox.checked) {
checkbox.click();
}
}
jQuery(this.modal).modal('toggle');
}
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++;
}
if (!foundColumn) {
return;
}
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

@@ -0,0 +1,73 @@
/*
* 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] KimaiDatePicker: single date selects (currently unused)
*/
import jQuery from 'jquery';
import KimaiPlugin from '../KimaiPlugin';
export default class KimaiDatePicker extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
getId() {
return 'date-picker';
}
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');
jQuery(this).daterangepicker({
singleDatePicker: true,
showDropdowns: true,
autoUpdateInput: false,
drops: 'down',
locale: {
format: localeFormat,
firstDay: firstDow,
applyLabel: TRANSLATE.get('confirm'),
cancelLabel: TRANSLATE.get('cancel'),
customRangeLabel: TRANSLATE.get('customRange'),
daysOfWeek: DATE_UTILS.getWeekDaysShort(),
monthNames: DATE_UTILS.getMonthNames(),
}
});
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");
});
});
}
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

@@ -0,0 +1,96 @@
/*
* 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] KimaiDateRangePicker: activate the (daterange picker) compound field in toolbar
*/
import jQuery from 'jquery';
import KimaiPlugin from '../KimaiPlugin';
import moment from 'moment';
export default class KimaiDateRangePicker extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
getId() {
return 'date-range-picker';
}
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');
let separator = jQuery(this).data('separator');
let rangesList = {};
rangesList[TRANSLATE.get('today')] = [moment(), moment()];
rangesList[TRANSLATE.get('yesterday')] = [moment().subtract(1, 'days'), moment().subtract(1, 'days')];
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')];
rangesList[TRANSLATE.get('lastYear')] = [moment().subtract(1, 'year').startOf('year'), moment().subtract(1, 'year').endOf('year')];
jQuery(this).daterangepicker({
showDropdowns: true,
autoUpdateInput: false,
autoApply: false,
linkedCalendars: true,
drops: 'down',
locale: {
separator: separator,
format: localeFormat,
firstDay: firstDow,
applyLabel: TRANSLATE.get('confirm'),
cancelLabel: TRANSLATE.get('cancel'),
customRangeLabel: TRANSLATE.get('customRange'),
daysOfWeek: DATE_UTILS.getWeekDaysShort(),
monthNames: DATE_UTILS.getMonthNames(),
},
ranges: rangesList,
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));
jQuery(this).data('end', picker.endDate.format(localeFormat));
jQuery(this).trigger("change");
});
});
}
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

@@ -0,0 +1,76 @@
/*
* 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] KimaiDateTimePicker: activate the (datetime picker) field in timesheet edit dialog
*/
import jQuery from 'jquery';
import KimaiPlugin from '../KimaiPlugin';
export default class KimaiDateTimePicker extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
getId() {
return 'date-time-picker';
}
activateDateTimePicker(selector) {
const TRANSLATE = this.getContainer().getTranslation();
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: is24hours,
showDropdowns: true,
autoUpdateInput: false,
drops: 'down',
locale: {
format: localeFormat,
firstDay: firstDow,
applyLabel: TRANSLATE.get('confirm'),
cancelLabel: TRANSLATE.get('cancel'),
customRangeLabel: TRANSLATE.get('customRange'),
daysOfWeek: DATE_UTILS.getWeekDaysShort(),
monthNames: DATE_UTILS.getMonthNames(),
}
});
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");
});
});
}
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

@@ -0,0 +1,110 @@
/*
* 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] KimaiDateUtils: responsible for handling date specific tasks
*/
import KimaiPlugin from '../KimaiPlugin';
import moment from 'moment';
export default class KimaiDateUtils extends KimaiPlugin {
getId() {
return 'date';
}
/**
* @param {string} dateTime
* @returns {string}
*/
getFormattedDate(dateTime) {
return moment(dateTime).format(this.getConfiguration('formatDate'));
}
getWeekDaysShort() {
return moment.localeData().weekdaysShort();
}
getMonthNames() {
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()).toString();
const minutes = duration.minutes();
const seconds = duration.seconds();
return this.formatTime(hours, minutes, seconds);
}
formatTime(hours, minutes, 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;
}
const format = this.getConfiguration('formatDuration');
return format.replace('%h', hours).replace('%m', ('0' + minutes).substr(-2)).replace('%s', ('0' + seconds).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

@@ -0,0 +1,33 @@
/*
* 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] KimaiEvent: helper to trigger events
*/
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiEvent extends KimaiPlugin {
getId() {
return 'event';
}
trigger(name, details) {
if (name === null || name === undefined) {
return;
}
for(let event of name.split(' ')) {
let triggerEvent = new Event(event);
if (details !== undefined) {
triggerEvent = new CustomEvent(event, {detail: details});
}
document.dispatchEvent(triggerEvent);
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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] KimaiForm: basic functions for all forms
*/
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiForm extends KimaiPlugin {
getId() {
return 'form';
}
activateForm(formSelector, container) {
this.getContainer().getPlugin('date-range-picker').activateDateRangePicker(formSelector);
this.getContainer().getPlugin('date-time-picker').activateDateTimePicker(formSelector);
this.getContainer().getPlugin('date-picker').activateDatePicker(formSelector);
this.getContainer().getPlugin('autocomplete').activateAutocomplete(formSelector);
this.getContainer().getPlugin('form-select').activateSelectPicker(formSelector, container);
}
destroyForm(formSelector) {
this.getContainer().getPlugin('form-select').destroySelectPicker(formSelector);
this.getContainer().getPlugin('autocomplete').destroyAutocomplete(formSelector);
this.getContainer().getPlugin('date-picker').destroyDatePicker(formSelector);
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

@@ -0,0 +1,265 @@
/*
* 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] KimaiFormSelect: enhanced functionality for HTML select's
*/
import KimaiPlugin from "../KimaiPlugin";
import jQuery from "jquery";
export default class KimaiFormSelect extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
getId() {
return 'form-select';
}
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
this.matcher = function (params, data) {
// Always return the object if there is nothing to compare
if (jQuery.trim(params.term) === '') {
return data;
}
// Check whether options has children
let hasChildren = data.children && data.children.length > 0;
// Split search param by space to search for all terms and convert all to uppercase
let terms = params.term.toUpperCase().split(' ');
let original = data.text.toUpperCase();
// Always return the parent option including its children, when the name matches one of the params
// Check if the text contains all or at least one of the terms
let foundAll = true;
let foundOne = false;
let missingTerms = [];
terms.forEach(function(item, index) {
if (original.indexOf(item) > -1) {
foundOne = true;
} else {
foundAll = false;
missingTerms.push(item);
}
});
// If the option element contains all terms, return it
if (foundAll) {
return data;
}
// Do a recursive check for options with children
if (hasChildren) {
// If the parent already contains one or more search terms, proceed only with the missing ones
// First: Clone the original params object...
let newParams = jQuery.extend(true, {}, params);
if (foundOne) {
newParams.term = missingTerms.join(' ');
} else {
newParams.term = params.term;
}
// Clone the data object if there are children
// This is required as we modify the object to remove any non-matches
let match = jQuery.extend(true, {}, data);
// Check each child of the option
for (let c = data.children.length - 1; c >= 0; c--) {
let child = data.children[c];
let matches = self.matcher(newParams, child);
// If there wasn't a match, remove the object in the array
if (matches === null) {
match.children.splice(c, 1);
}
}
// If any children matched, return the new object
if (match.children.length > 0) {
return match;
}
}
// 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.getConfiguration('locale').replace('_', '-'),
theme: "bootstrap",
matcher: this.matcher
}};
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
}};
jQuery(node).select2(colorOptions);
} else {
jQuery(node).select2(options);
}
}
activateSelectPicker(selector, container) {
const self = this;
jQuery(selector + ' ' + this.selector).each(function(i, el) {
self.activateSelectPickerByElement(el, container);
});
}
destroySelectPicker(selector) {
jQuery(selector + ' ' + this.selector).select2('destroy');
}
updateOptions(selectIdentifier, data) {
let select = jQuery(selectIdentifier);
let emptyOption = jQuery(selectIdentifier + ' option[value=""]');
const selectedValue = select.val();
select.find('option').remove().end().find('optgroup').remove().end();
if (emptyOption.length !== 0) {
select.append(this._createOption(emptyOption.text(), ''));
}
let emptyOpts = [];
let options = [];
let titlePattern = null;
if (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) {
emptyOpts.push(this._createOption(this._getTitleFromPattern(titlePattern, entity), entity.id));
}
continue;
}
let optGroup = this._createOptgroup(key);
for (const entity of value) {
optGroup.appendChild(this._createOption(this._getTitleFromPattern(titlePattern, entity), entity.id));
}
options.push(optGroup);
}
select.append(options);
select.append(emptyOpts);
// if available, re-select the previous selected option (mostly usable for global activities)
select.val(selectedValue);
// if we don't trigger the change, the other selects won't reset
select.trigger('change');
// if select2 is active, this will tell the select to refresh
if (select.hasClass('selectpicker')) {
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(/- \?-\?/, '');
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

@@ -0,0 +1,73 @@
/*
* 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] KimaiMultiUpdateForm: handle the multi update checkbox list and form
*/
import KimaiPlugin from '../KimaiPlugin';
import jQuery from "jquery";
export default class KimaiMultiUpdateTable extends KimaiPlugin {
init() {
const self = this;
jQuery('body').
on('change', '#multi_update_all', function(event) {
jQuery('.multi_update_single').prop('checked', jQuery(event.target).prop('checked'));
self.toggleForm();
})
.on('change', '.multi_update_single', function(event) {
self.toggleForm();
})
.on('change', '#multi_update_table_action', function(event) {
const selectedItem = jQuery('#multi_update_table_action option:selected');
const selectedVal = selectedItem.val();
if (selectedVal === '') {
return;
}
const form = jQuery('#multi_update_form form');
const selectedText = selectedItem.text();
const ids = self.getSelectedIds();
const question = form.attr('data-question').replace(/%action%/, selectedText).replace(/%count%/, ids.length);
self.getContainer().getPlugin('alert').question(question, function(value) {
if (value) {
form.attr('action', selectedVal).submit();
} else {
jQuery('#multi_update_table_action').val('').trigger('change');
}
});
});
}
getSelectedIds()
{
let ids = [];
jQuery('.multi_update_single:checked').each(function(i){
ids[i] = $(this).val();
});
return ids;
}
toggleForm()
{
const ids = this.getSelectedIds();
jQuery('#multi_update_table_entities').val(ids.join(','));
if (ids.length > 0) {
jQuery('#multi_update_form').show();
} else {
jQuery('#multi_update_form').hide();
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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] KimaiPauseRecord
*
* allows to pause records
* THIS IS JUST A DRAFT FOR THE DOM, IT IS NOT SUPPORTED IN KIMAI ITSELF!
*/
import jQuery from 'jquery';
import KimaiPlugin from '../KimaiPlugin';
export default class KimaiPauseRecord extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
init() {
this.activate(this.selector);
}
activate(selector) {
jQuery(selector + ' .pull-left i').hover(function () {
let link = jQuery(this).parents('a');
link.attr('href', link.attr('href').replace('/stop', '/pause'));
jQuery(this).removeClass('fa-stop-circle').addClass('fa-pause-circle').addClass('text-orange');
},function () {
let link = jQuery(this).parents('a');
link.attr('href', link.attr('href').replace('/pause', '/stop'));
jQuery(this).removeClass('fa-pause-circle').removeClass('text-orange').addClass('fa-stop-circle');
});
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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] KimaiRecentActivities: responsible to reload the users recent activities
*/
import KimaiPlugin from '../KimaiPlugin';
export default class KimaiRecentActivities extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
getId() {
return 'recent-activities';
}
init() {
const menu = document.querySelector(this.selector);
// the menu can be hidden if user has no permissions to see it
if (menu === null) {
return;
}
const dropdown = menu.querySelector('ul.dropdown-menu');
this.attributes = dropdown.dataset;
this.itemList = dropdown.querySelector('li > ul.menu');
const self = this;
const handle = function() { self.reloadRecentActivities(); };
// don't block initial browser rendering
setTimeout(handle, 500);
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() {
this.itemList.innerHTML = '';
}
setEntries(entries) {
if (entries.length === 0) {
this.emptyList();
return;
}
let htmlToInsert = '';
for (let timesheet of entries) {
let label = this.attributes['template']
.replace('%customer%', this.escape(timesheet.project.customer.name))
.replace('%project%', this.escape(timesheet.project.name))
.replace('%activity%', this.escape(timesheet.activity.name))
;
htmlToInsert +=
`<li>` +
`<a href="${ this.attributes['href'].replace('000', timesheet.id) }" data-event="kimai.timesheetStart kimai.timesheetUpdate" class="api-link" data-method="PATCH" data-msg-error="timesheet.start.error" data-msg-success="timesheet.start.success">` +
`<i class="${ this.attributes['icon'] }"></i> ${ label }` +
`</a>` +
`</li>`;
}
this.itemList.innerHTML = htmlToInsert;
}
reloadRecentActivities() {
const self = this;
const API = this.getContainer().getPlugin('api');
API.get(this.attributes['api'], {}, function(result) {
self.setEntries(result);
});
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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] KimaiReducedClickHandler: abstract class
*/
import jQuery from 'jquery';
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiReducedClickHandler extends KimaiPlugin {
_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) {
return;
}
// handles the "click" on table rows or list elements
let target = event.target;
if (event.currentTarget.matches('tr') || event.currentTarget.matches('li')) {
while (target !== null && !target.matches('body')) {
// when an element within the row is clicked, that can trigger stuff itself, we don't want the event to be processed
// don't act if a link, button or form element was clicked
if (target.matches('a') || target.matches ('button') || target.matches ('input')) {
return;
}
target = target.parentNode;
}
}
event.preventDefault();
event.stopPropagation();
let href = jQuery(this).attr('data-href');
if (!href) {
href = jQuery(this).attr('href');
}
if (href === undefined || href === null || href === '') {
return;
}
callback(href);
});
}
}

View File

@@ -0,0 +1,150 @@
/*
* 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] KimaiSelectDataAPI: <select> boxes with dynamic data from API
*/
import jQuery from 'jquery';
import KimaiPlugin from "../KimaiPlugin";
import moment from 'moment';
export default class KimaiSelectDataAPI extends KimaiPlugin {
constructor(selector) {
super();
this.selector = selector;
}
getId() {
return 'select-data-api';
}
init() {
this.activateApiSelects(this.selector);
}
activateApiSelects(selector) {
const self = this;
const API = this.getContainer().getPlugin('api');
jQuery('body').on('change', selector, function(event) {
const targetSelect = '#' + this.dataset['relatedSelect'];
// if the related target select does not exist, we do not need to load the related data
if (jQuery(targetSelect).length === 0) {
return;
}
let formPrefix = this.dataset['formPrefix'];
if (formPrefix === undefined || formPrefix === null) {
formPrefix = '';
} else if (formPrefix.length > 0) {
formPrefix += '_';
}
let newApiUrl = self._buildUrlWithFormFields(this.dataset['apiUrl'], formPrefix);
const selectValue = jQuery(this).val();
// Problem: select a project with activities and then select a customer that has no project
// results in a wrong URL, it triggers "activities?project=" instead of using the "emptyUrl"
if (selectValue === undefined || selectValue === null || selectValue === '' || (Array.isArray(selectValue) && selectValue.length === 0)) {
if (this.dataset['emptyUrl'] === undefined) {
self._updateSelect(targetSelect, {});
jQuery(targetSelect).attr('disabled', 'disabled');
return;
}
newApiUrl = self._buildUrlWithFormFields(this.dataset['emptyUrl'], formPrefix);
}
jQuery(targetSelect).removeAttr('disabled');
API.get(newApiUrl, {}, function(data){
self._updateSelect(targetSelect, data);
});
});
}
_buildUrlWithFormFields(apiUrl, formPrefix) {
let newApiUrl = apiUrl;
apiUrl.split('?')[1].split('&').forEach(item => {
const [key, value] = item.split('=');
const decoded = decodeURIComponent(value);
const test = decoded.match(/%(.*)%/);
if (test !== null) {
const targetField = jQuery('#' + formPrefix + test[1]);
let newValue = '';
if (targetField.length === 0) {
// happens for example:
// - in duration only mode, when the end field is not found
// console.log('ERROR: Cannot find field with name "' + test[1] + '" by selector: #' + formPrefix + test[1]);
} else {
if (targetField.val() !== null) {
newValue = targetField.val();
if (newValue !== '') {
// having that special case here is far from being perfect... but for now it works ;-)
if (targetField.data('daterangepicker') !== undefined) {
if (key === 'begin' || key === 'start' || targetField.data('daterangepicker').singleDatePicker) {
newValue = targetField.data('daterangepicker').startDate.format(moment.HTML5_FMT.DATETIME_LOCAL_SECONDS);
} else if (key === 'end') {
newValue = targetField.data('daterangepicker').endDate.format(moment.HTML5_FMT.DATETIME_LOCAL_SECONDS);
}
} else if (targetField.data('format') !== undefined) {
if (moment(newValue, targetField.data('format')).isValid()) {
newValue = moment(newValue, targetField.data('format')).format(moment.HTML5_FMT.DATETIME_LOCAL_SECONDS);
}
}
} else {
// happens for example:
// - when the end date is not set on a timesheet record and the project list is loaded (as the URL contains the %end% replacer)
// console.log('Empty value found for field with name "' + test[1] + '" by selector: #' + formPrefix + test[1]);
}
} else {
// happens for example:
// - when a customer without projects is selected
// console.log('ERROR: Empty field with name "' + test[1] + '" by selector: #' + formPrefix + test[1]);
}
}
if (Array.isArray(newValue)) {
newValue = newValue.join(',');
}
newApiUrl = newApiUrl.replace(value, newValue);
}
});
return newApiUrl;
}
_updateSelect(selectName, data) {
const options = {};
for (const apiData of data) {
let title = '__empty__';
if (apiData.hasOwnProperty('parentTitle') && apiData.parentTitle !== null) {
title = apiData.parentTitle;
}
if (!options.hasOwnProperty(title)) {
options[title] = [];
}
options[title].push(apiData);
}
const ordered = {};
Object.keys(options).sort().forEach(function(key) {
ordered[key] = options[key];
});
/** @var {KimaiFormSelect} select */
const select = this.getContainer().getPlugin('form-select');
select.updateOptions(selectName, ordered);
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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] KimaiThemeInitializer: initialize theme functionality
*/
import jQuery from 'jquery';
import KimaiPlugin from '../KimaiPlugin';
export default class KimaiThemeInitializer extends KimaiPlugin {
init() {
this.registerGlobalAjaxErrorHandler();
this.registerAutomaticAlertRemove('div.alert-success', 5000);
// activate the dropdown functionality
jQuery('.dropdown-toggle').dropdown();
// activate the tooltip functionality
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.getConfiguration('login');
const alert = this.getContainer().getPlugin('alert');
const translation = this.getContainer().getTranslation().get('login.required');
jQuery(document).ajaxError(function(event, jqxhr, settings, thrownError) {
if (jqxhr.status !== undefined && jqxhr.status === 403) {
const loginRequired = jqxhr.getResponseHeader('login-required');
if (loginRequired !== null) {
alert.question(translation, function (result) {
if (result === true) {
window.location.replace(loginUrl);
}
});
}
}
});
}
/**
* auto hide success messages, as they are just meant as user feedback and not as a permanent information
*
* @param {string} selector
* @param {integer} interval
*/
registerAutomaticAlertRemove(selector, interval) {
const self = this;
this._alertRemoveHandler = setInterval(
function() {
self.hideAlert(selector);
},
interval
);
}
unregisterAutomaticAlertRemove() {
clearInterval(this._alertRemoveHandler);
}
/**
* @param {string} selector
*/
hideAlert(selector) {
jQuery(selector).alert('close');
}
}

View File

@@ -0,0 +1,173 @@
/*
* 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] KimaiToolbar: some event listener to handle the toolbar/data-table filter, toolbar and navigation
*/
import jQuery from 'jquery';
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiToolbar extends KimaiPlugin {
constructor(formSelector, formSubmitActionClass) {
super();
this.formSelector = formSelector;
this.actionClass = formSubmitActionClass;
}
getId() {
return 'toolbar';
}
init() {
const formSelector = this.getSelector();
const self = this;
const EVENT = self.getContainer().getPlugin('event');
this._registerPagination(formSelector, EVENT);
this._registerSortableTables(formSelector, EVENT);
this._registerAlternativeSubmitActions(formSelector, this.actionClass);
// 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) {
case 'order':
case 'orderBy':
case 'page':
break;
default:
jQuery(formSelector + ' input#page').val(1);
break;
}
self.triggerChange();
});
// when user selected a new customer or project, reset the pagination back to 1
// and then find out if the results should be reloaded
jQuery(formSelector + ' select').change(function (event) {
let reload = true;
switch (event.target.id) {
case 'customer':
if (jQuery(formSelector + ' select#project').length > 0) {
reload = false;
}
break;
case 'project':
if (jQuery(formSelector + ' select#activity').length > 0) {
reload = false;
}
break;
}
jQuery(formSelector + ' input#page').val(1);
if (reload) {
self.triggerChange();
}
});
}
/**
* Some actions utilize the filter from the search form and submit it to another URL.
* @private
*/
_registerAlternativeSubmitActions(toolbarSelector, actionBtnClass) {
document.addEventListener('click', function(event) {
let target = event.target;
while (target !== null && !target.matches('body')) {
if (target.classList.contains(actionBtnClass)) {
const form = document.querySelector(toolbarSelector);
if (form === null) {
return;
}
const prevAction = form.action;
const prevMethod = form.method;
form.target = '_blank';
form.action = target.href;
if (target.dataset.method !== undefined) {
form.method = target.dataset.method;
}
form.submit();
form.target = '';
form.action = prevAction;
form.method = prevMethod;
event.preventDefault();
event.stopPropagation();
}
target = target.parentNode;
}
});
}
/**
* Sortable datatables use hidden fields in the toolbar filter/search form
* @private
*/
_registerSortableTables(formSelector, EVENT) {
jQuery('body').on('click', 'th.sortable', function(event){
var $header = jQuery(event.target);
var order = 'DESC';
var orderBy = $header.data('order');
if ($header.hasClass('sorting_desc')) {
order = 'ASC';
}
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');
});
}
/**
* This catches all clicks on the pagination and prevents the default action, as we want to reload the page via JS
* @private
*/
_registerPagination(formSelector, EVENT) {
jQuery('body').on('click', 'div.navigation ul.pagination li a', function(event) {
let pager = jQuery(formSelector + " input#page");
if (pager.length === 0) {
return;
}
event.preventDefault();
event.stopPropagation();
let urlParts = jQuery(this).attr('href').split('/');
let page = urlParts[urlParts.length-1];
pager.val(page);
pager.trigger('change');
EVENT.trigger('pagination-change');
return false;
});
}
/**
* Triggers an event, that everyone can listen for.
*/
triggerChange() {
this.getContainer().getPlugin('event').trigger('toolbar-change');
}
/**
* Returns the CSS selector to target the toolbar form.
*
* @returns {string}
*/
getSelector() {
return this.formSelector;
}
}

View File

@@ -1,37 +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.
*/
$(document).ready(function () {
//$('.navbar-form select').selectpicker({});
// DateRange - TODO improve me, so users can type without reloading in between
$('.toolbar form input').change(function (event) {
$('.toolbar form').submit();
});
$('.toolbar form select').change(function (event) {
switch (event.target.id) {
case 'customer':
if ($(this).val() === '') {
$('.toolbar form select#project').parent().remove();
} else {
$('.toolbar form select#project').val('');
}
$('.toolbar form select#activity').parent().remove();
break;
case 'project':
if ($(this).val() === '') {
$('.toolbar form select#activity').parent().remove();
} else {
$('.toolbar form select#activity').val('');
}
break;
}
$('.toolbar form').submit();
});
});

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,97 @@
/*
* 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] KimaiPaginatedBoxWidget: handles box widgets that have a pagination
*/
import jQuery from "jquery";
export default class KimaiPaginatedBoxWidget {
constructor(boxId) {
this.selector = boxId;
this.overlay = jQuery('<div class="overlay"><div class="fas fa-sync fa-spin"></div></div>');
this.widget = jQuery(this.selector);
this.href = this.widget.data('href');
this.events = this.widget.data('reload').split(' ');
const self = this;
const reloadPage = function (event) {
const page = jQuery(self.selector + ' .box-tools').data('page');
const url = self._buildUrl(page);
self.loadPage(url);
};
for (const eventName of this.events) {
document.addEventListener(eventName, reloadPage);
}
this.widget.on('click', '.box-tools ul.pagination a', function (event) {
event.preventDefault();
self.loadPage(jQuery(event.currentTarget).attr('href'));
});
}
static create(elementId) {
return new KimaiPaginatedBoxWidget(elementId);
}
_showOverlay() {
this.widget.append(this.overlay);
}
_hideOverlay() {
jQuery(this.overlay).remove();
}
loadPage(url) {
const self = this;
const selector = this.selector;
self._showOverlay();
jQuery.ajax({
url: url,
data: {},
success: function (response) {
const html = jQuery(response);
jQuery(selector + ' .box-tools').replaceWith(html.find('.box-tools'));
jQuery(selector + ' .box-body').replaceWith(html.find('.box-body'));
jQuery(selector + ' .box-title').replaceWith(html.find('.box-title'));
if (jQuery(selector + ' .box-footer').length > 0) {
jQuery(selector + ' .box-footer').replaceWith(html.find('.box-footer'));
}
jQuery(selector + ' .box-body [data-toggle="tooltip"]').tooltip();
self.widget.removeData('error-retry');
self._hideOverlay();
},
dataType: 'html',
error: function(jqXHR, textStatus, errorThrown) {
if (jqXHR.status !== undefined && jqXHR.status === 500) {
if (self.widget.data('error-retry') !== undefined) {
// TODO show error message ?
return;
}
const page = jQuery(selector + ' .box-tools').data('page');
if (page > 1) {
self.widget.data('error-retry', 1);
var url = self._buildUrl(page - 1);
self.loadPage(url);
}
}
self._hideOverlay();
}
});
}
_buildUrl(page) {
return this.href.replace('1', page);
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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] KimaiReloadPageWidget: a simple helper to reload the page on events
*/
import jQuery from "jquery";
export default class KimaiReloadPageWidget {
constructor(events, fullReload) {
this.overlay = jQuery('<div class="overlay-wrapper"><div class="overlay"><div class="fas fa-sync fa-spin"></div></div></div>');
this.widget = jQuery('div.content-wrapper');
const self = this;
const reloadPage = function (event) {
if (fullReload) {
document.location.reload(true);
} else {
self.loadPage(document.location);
}
};
for (const eventName of events.split(' ')) {
document.addEventListener(eventName, reloadPage);
}
}
static create(events, fullReload) {
if (fullReload === undefined || fullReload === null) {
fullReload = false;
}
return new KimaiReloadPageWidget(events, fullReload);
}
_showOverlay() {
this.widget.append(this.overlay);
}
_hideOverlay() {
jQuery(this.overlay).remove();
}
loadPage(url) {
const self = this;
self._showOverlay();
jQuery.ajax({
url: url,
data: {},
success: function (response) {
jQuery('section.content').replaceWith(
jQuery(response).find('section.content')
);
document.dispatchEvent(new Event('kimai.reloadPage'));
self._hideOverlay();
},
dataType: 'html',
error: function(jqXHR, textStatus, errorThrown) {
self._hideOverlay();
document.location = url;
}
});
}
}

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);
}
}

34
assets/sass/app.scss Normal file
View File

@@ -0,0 +1,34 @@
/*
* 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.
*/
@import 'variables';
@import 'layout';
@import 'error-page';
@import 'print';
@import 'content';
@import 'box';
@import 'content-header';
@import 'toolbar';
@import 'sidebar';
@import 'footer';
@import 'datatable';
@import 'datatable-extensions';
@import 'calendar';
@import 'dashboard';
@import 'navbar';
@import 'daterangepicker';
@import 'skins';
@import 'sweetalert';
@import 'autocomplete';
@import 'selectpicker';
@import 'reporting';
@import 'forms';
@import 'modal';
@import 'progressbar';
@import 'avatar';
@import 'security';
@import 'tabs';

View File

@@ -0,0 +1,76 @@
/*
* 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.
*/
.ui-widget {
font-size: 1em/*{fsDefault}*/;
}
.ui-widget.ui-widget-content {
border: 1px solid #c5c5c5/*{borderColorDefault}*/;
}
.ui-widget-content {
border: 1px solid #dddddd/*{borderColorContent}*/;
background: #ffffff/*{bgColorContent}*/ /*{bgImgUrlContent}*/ /*{bgContentXPos}*/ /*{bgContentYPos}*/ /*{bgContentRepeat}*/;
color: #333333/*{fcContent}*/;
}
.ui-menu {
list-style: none;
padding: 0;
margin: 0;
display: block;
outline: 0;
}
.ui-menu .ui-menu-item {
margin: 0;
cursor: pointer;
}
.ui-autocomplete {
position: absolute;
top: 0;
left: 0;
cursor: default;
}
.ui-front {
z-index: 1200;
}
.ui-menu .ui-menu-item-wrapper {
position: relative;
padding: 3px 1em 3px .4em;
}
.ui-menu .ui-state-focus,
.ui-menu .ui-state-active {
margin: -1px;
}
.ui-state-active,
.ui-widget-content .ui-state-active,
.ui-widget-header .ui-state-active,
a.ui-button:active,
.ui-button:active,
.ui-button.ui-state-active:hover {
border: 1px solid #003eff/*{borderColorActive}*/;
background: #007fff/*{bgColorActive}*/ /*{bgImgUrlActive}*/ /*{bgActiveXPos}*/ /*{bgActiveYPos}*/ /*{bgActiveRepeat}*/;
font-weight: normal/*{fwDefault}*/;
color: #ffffff/*{fcActive}*/;
}
.ui-icon-background,
.ui-state-active .ui-icon-background {
border: #003eff/*{borderColorActive}*/;
background-color: #ffffff/*{fcActive}*/;
}
.ui-state-active a,
.ui-state-active a:link,
.ui-state-active a:visited {
color: #ffffff/*{fcActive}*/;
text-decoration: none;
}

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);
}

9
assets/sass/bootstrap.scss vendored Normal file
View File

@@ -0,0 +1,9 @@
/*
* 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.
*/
$icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
@import '~bootstrap-sass/assets/stylesheets/bootstrap';

22
assets/sass/box.scss Normal file
View File

@@ -0,0 +1,22 @@
.box {
/* used on detail pages for: customer, project and activity */
.box-body.no-padding div.comment,
.box-body.no-padding .box-padding {
padding: 10px;
}
.box-tools {
/* a button that is directly connected with a pagination element inside the box tools (eg. project list on customer detail page) */
.btn-pager {
float: left;
margin-right: 5px;
}
}
}
#customer_details_box,
#project_details_box,
#activity_details_box {
th {
width: 30%;
}
}

51
assets/sass/calendar.scss Normal file
View File

@@ -0,0 +1,51 @@
.popover-content {
.calendar-entry {
ul {
padding: 0;
list-style-type: none;
}
}
}
/* 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

@@ -0,0 +1,65 @@
/*
* 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.
*/
.content-header {
height: 50px;
border-top: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
background-color: #fff !important;
padding: 10px 0 0 10px;
h1 {
padding-top: 3px;
float: left;
small {
display: none;
}
}
}
/* Page based action buttons in the upper right corner of the content area */
.content-header>.breadcrumb {
position: absolute;
float: right;
background: transparent;
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-max) {
.content-header h1 {
font-size: 1.5em;
}
.content-header>.breadcrumb {
margin-top: 0;
}
}
@media (min-width: $screen-sm-min) {
.content-header>.breadcrumb {
right: 10px;
}
.content-header {
h1 {
small {
display: inline-block;
}
}
}
}

87
assets/sass/content.scss Normal file
View File

@@ -0,0 +1,87 @@
/*
* 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.
*/
.content {
padding: 15px 0;
}
@media (min-width: $screen-sm-min) {
.content {
padding: 15px;
}
}
@media (min-width: $screen-lg-min) {
.content {
padding: 20px;
}
}
td {
&.timesheet-description {
ul {
padding-left: 15px;
}
p {
margin: 0;
}
}
}
/* ABOUT SCREEN */
.box-body .menu-icon {
width: 35px;
height: 35px;
border-radius: 50%;
text-align: center;
line-height: 35px;
margin-right: 15px;
}
.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 */
.dropdown-menu > li.delete > a {
color: #dd4b39;
}
.open-edit {
cursor: pointer;
}
/* allow minimized table columns, eg. customer team & visibility */
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;
}

View File

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

View File

@@ -0,0 +1,134 @@
/*
* 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.
*/
@import "variables";
table.dataTable.table > tbody > tr > td {
vertical-align: middle;
.img-circle {
max-width: 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;
color: $gray-lte;
}
}
table.dataTable {
/* action column */
.actions {
width: 40px;
}
tr {
/* summary row - provided in the users own timesheet table */
&.summary td {
font-weight: bold;
border-bottom: 1px solid #ccc;
background-color: #eaeaea;
}
th.multiCheckbox {
width: 15px;
}
&.overlapping {
border-top: 2px dotted red;
}
&.exported {
opacity: 0.7;
}
}
td {
/*
Make sure that the action buttons do not line-break if another column takes all available space
See https://github.com/twbs/bootstrap/issues/9939#issuecomment-37682952
*/
.btn-group {
display: flex;
}
.label {
font-size: 85%;
padding: .3em .6em .3em;
line-height: 24px;
}
span.label-activity,
span.label-project,
span.label-customer {
a {
color: unset;
padding-bottom: 2px;
border-bottom: 1px dotted $gray-lte;
&:hover {
border-bottom: 1px dotted darken($gray-lte, 20);
}
}
}
span.label-invisible {
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

@@ -5,6 +5,43 @@
* file that was distributed with this source code.
*/
/* Loading indicator: overwritten from AdminLTE for positioning and supporting fas classes */
.box .overlay > .fas,
section.content .overlay > .fas,
.overlay-wrapper .overlay > .fas {
position: absolute;
top: 50vh;
left: 50vw;
margin-left: -15px;
margin-top: -15px;
color: #000;
font-size: 30px;
}
.box > .overlay,
.overlay-wrapper > .overlay,
section.content > .overlay,
.box > .loading-img,
.overlay-wrapper > .loading-img {
position: fixed; /* see #1330 */
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.box .overlay,
section.content .overlay,
.overlay-wrapper .overlay {
z-index: 50;
background: rgba(255, 255, 255, 0.7);
border-radius: $box-border-radius;
}
.box .overlay.dark,
section.content .overlay.dark,
.overlay-wrapper .overlay.dark {
background: rgba(0, 0, 0, 0.5);
}
/*
dataTables.bootstrap.css
*/
@@ -88,39 +125,43 @@ table.dataTable thead .sorting_desc_disabled {
position: relative;
}
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 {
position: absolute;
top: 8px;
right: 8px;
display: block;
font-family: 'Glyphicons Halflings';
padding-left: 5px;
font-family: 'Font Awesome 5 Free';
opacity: 0.5;
font-size: 12px;
}
table.dataTable thead .sorting:after {
opacity: 0.2;
content: "\e150"; /* sort */
content: "\f0dc"; /* sort */
}
table.dataTable thead .sorting_asc:after {
content: "\e155"; /* sort-by-attributes */
content: "\f062";
}
table.dataTable thead .sorting_desc:after {
content: "\e156"; /* sort-by-attributes-alt */
content: "\f063";
}
div.dataTables_scrollBody table.dataTable thead .sorting:after,
div.dataTables_scrollBody table.dataTable thead .sorting_asc:after,
div.dataTables_scrollBody table.dataTable thead .sorting_desc:after {
div.dataTables_scrollBody table.dataTable thead .sorting:before,
div.dataTables_scrollBody table.dataTable thead .sorting_asc:before,
div.dataTables_scrollBody table.dataTable thead .sorting_desc:before {
display: none;
}
table.dataTable thead .sorting_asc_disabled:after,
table.dataTable thead .sorting_desc_disabled:after {
table.dataTable thead .sorting_asc_disabled:before,
table.dataTable thead .sorting_desc_disabled:before {
color: #eee;
}
table.dataTable thead > tr > th {
padding-right: 30px;
vertical-align: top;
white-space: nowrap;
}
table.dataTable th:active {
@@ -133,9 +174,9 @@ table.dataTable.table-condensed thead > tr > th {
padding-right: 20px;
}
table.dataTable.table-condensed thead .sorting:after,
table.dataTable.table-condensed thead .sorting_asc:after,
table.dataTable.table-condensed thead .sorting_desc:after {
table.dataTable.table-condensed thead .sorting:before,
table.dataTable.table-condensed thead .sorting_asc:before,
table.dataTable.table-condensed thead .sorting_desc:before {
top: 6px;
right: 6px;
}

View File

@@ -0,0 +1,13 @@
@import '~daterangepicker/daterangepicker.css';
.drp-calendar {
.calendar-table {
td.today:not(.active) {
background-color: lighten(#357ebd, 40);
color: #357ebd;
}
select.yearselect{
width: unset;
}
}
}

View File

@@ -0,0 +1,10 @@
/*
* 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.
*/
.error-page {
margin-bottom: 50px;
}

12
assets/sass/fontawesome.scss vendored Normal file
View File

@@ -0,0 +1,12 @@
/*
* 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.
*/
$fa-font-path: "~@fortawesome/fontawesome-free/webfonts/";
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/solid';
@import '~@fortawesome/fontawesome-free/scss/brands';

11
assets/sass/footer.scss Normal file
View File

@@ -0,0 +1,11 @@
/*
* 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.
*/
footer.main-footer {
padding: 5px;
font-size: 80%;
}

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

@@ -0,0 +1,55 @@
/* 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;
}
}
/* 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;
}

View File

@@ -0,0 +1,116 @@
/*
* 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.
*/
body {
font-family: sans-serif;
font-size: 10pt;
margin: 0;
padding: 0;
}
table, tr, td, th, p, h1, h2, h3, h4, h5 {
padding: 0;
margin: 0;
}
th {
border: none;
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-right {
text-align: right;
}
.text-nowrap {
white-space: nowrap;
}
.date {
color: #666;
font-size: 80%;
text-align: right;
padding-top: 6px;
}
.wrapper {
margin: 4px;
}
table {
width: 100%;
border-spacing: 0;
}
table.addresses, p {
line-height: 14pt;
}
/* The address table */
table.addresses {
margin-bottom: 30px;
}
/* The PDF header */
table.header {
padding-bottom: 4px;
border-bottom: 1px solid #999;
}
table.header .title {
font-weight: normal;
font-size: 140%;
}
/* The PDF footer */
table.footer {
border-top: 1px solid #999;
font-size: 80%;
padding-top: 8px;
line-height: 14px;
}
table.footer td {
vertical-align: bottom;
}
/* The invoice items list */
table.items {
border-collapse: collapse;
margin-top: 50px;
margin-bottom: 60px;
}
table.items thead th,
table.items tbody td {
border-bottom: 1px solid #ccc;
}
table.items thead th.first,
table.items tbody td.first {
padding-left: 0;
}
table.items thead th.last,
table.items tbody td.last,
table.items tfoot td.last {
padding-right: 0;
}
table.items td,
table.items th {
padding: 8px 6px;
}
table.items tfoot td,
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;
}

298
assets/sass/invoice.scss Normal file
View File

@@ -0,0 +1,298 @@
/*
* 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.
*/
@import "~bootstrap-sass/assets/stylesheets/bootstrap/variables";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/mixins";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/normalize";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/print";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/scaffolding";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/type";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/grid";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/tables";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/list-group";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/panels";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/wells";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/utilities";
@import "~bootstrap-sass/assets/stylesheets/bootstrap/responsive-utilities";
body.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;
}
h3 {
border-color: #ddd;
}
}
/*
.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-items {
margin-top: 2em;
margin-bottom: 3em;
.table {
thead th {
font-weight: bold;
border-bottom: 1px solid #ddd;
padding-bottom: 15px
}
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;
}
}
/* ================================ 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;
}
}
}

8
assets/sass/layout.scss Normal file
View File

@@ -0,0 +1,8 @@
@media (max-width: $screen-sm-max) {
.main-header .logo {
display: none;
}
.fixed .content-wrapper, .fixed .right-side, .control-sidebar, .main-sidebar {
padding-top: 50px;
}
}

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);
}

157
assets/sass/navbar.scss Normal file
View File

@@ -0,0 +1,157 @@
/*
* 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.
*/
.navbar-custom-menu {
.navbar-nav {
li>.ddt-small {
padding-top: 10px;
padding-bottom: 10px;
}
}
}
.navbar-nav {
img.img-circle {
max-height: 26px;
margin-top: -2px;
}
.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 {
color: #dd4b39;
}
a .pull-left i {
color: #444;
}
}
.messages-menu>.dropdown-menu>li .menu>li>a>p {
overflow: hidden;
text-overflow: ellipsis;
}
.messages-menu>.dropdown-menu>li .menu>li>a>h4>span {
margin-right: 55px;
}
.dropdown-menu {
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;
width: unset !important;
}
.user-menu {
ul {
li {
a {
color: #444;
&:hover {
background-color: #f4f4f4;
}
i {
padding-right: 10px;
}
}
hr {
margin: 0;
}
}
}
}
}
@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-max) {
.navbar-custom-menu>.navbar-nav>li>.dropdown-menu {
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
}
}
@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;
}
}
@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;
}
}

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