diff --git a/README.md b/README.md index 0d9f7a43..493ad02d 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,12 @@ It is built with modern technologies such as Symfony, Bootstrap, RESTful API, re ### About -This new version of the open source timetracker Kimai. It is in a stable development phase, usable in production and -with most advanced features from Kimai 1 and many new ones: +This is new version of the open source timetracker Kimai. It is in a stable development phase, usable in production and +with most advanced features from Kimai 1 and many new ones, including but not limited to: JSON API, invoicing, data exports, multi-timer and punch-in punch-out mode, tagging, multi-user and multi-timezones, -LDAP and built-in authentication, customizable role permissions, responsive and usable on your mobile device, -hourly and fixed rates, advanced filtering, support for plugins and many more. +LDAP and built-in authentication, customizable role permissions, responsive and ready for your mobile device, +hourly and fixed rates, advanced filtering, money and time budgets and report, support for plugins and many more. ## Installation @@ -40,7 +40,7 @@ hourly and fixed rates, advanced filtering, support for plugins and many more. - [Docker](https://www.kimai.org/documentation/docker.html) - containerized - [Development](https://www.kimai.org/documentation/installation.html#development-installation) - on your local machine - [1-click installer](https://www.kimai.org/documentation/installation.html#hosting-and-1-click-installations) - hosted environments -- [FTP](https://www.kimai.org/documentation/installation.html#ftp-installation) - unfortunately still widely used +- [FTP](https://www.kimai.org/documentation/installation.html#ftp-installation) - unfortunately still widely used ;-) ### Updating Kimai @@ -49,7 +49,7 @@ hourly and fixed rates, advanced filtering, support for plugins and many more. ### Plugins -- [Plugin marketplace](https://www.kimai.org/store/) - users find existing plugins here +- [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 ## Roadmap and releases diff --git a/UPGRADING.md b/UPGRADING.md index 8ad9909d..9eb2ea3e 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -35,6 +35,7 @@ Removed permission: - 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, now you know [where to look for help](https://www.kimai.org/documentation/dashboard.html) ## [0.9](https://github.com/kevinpapst/kimai2/releases/tag/0.9) diff --git a/assets/js/plugins/KimaiAlert.js b/assets/js/plugins/KimaiAlert.js index 6b2527f8..2e773b56 100644 --- a/assets/js/plugins/KimaiAlert.js +++ b/assets/js/plugins/KimaiAlert.js @@ -41,7 +41,8 @@ export default class KimaiAlert extends KimaiPlugin { } Swal.fire({ - timer: 1500, + timer: 2000, + toast: true, position: 'top-end', showConfirmButton: false, type: 'success', diff --git a/composer.lock b/composer.lock index 53fa4cfd..fc4f83dc 100644 --- a/composer.lock +++ b/composer.lock @@ -2971,33 +2971,37 @@ }, { "name": "kevinpapst/adminlte-bundle", - "version": "2.7.3", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/kevinpapst/AdminLTEBundle.git", - "reference": "bbe650bda5319ac55637457e23d60bcafb734da1" + "reference": "62df10d0565f2ed5971b1a28ef30195ad1893807" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kevinpapst/AdminLTEBundle/zipball/bbe650bda5319ac55637457e23d60bcafb734da1", - "reference": "bbe650bda5319ac55637457e23d60bcafb734da1", + "url": "https://api.github.com/repos/kevinpapst/AdminLTEBundle/zipball/62df10d0565f2ed5971b1a28ef30195ad1893807", + "reference": "62df10d0565f2ed5971b1a28ef30195ad1893807", "shasum": "" }, "require": { "php": "^7.1.3", - "symfony/config": ">3.4", - "symfony/dependency-injection": ">3.4", - "symfony/event-dispatcher": ">3.4", - "symfony/http-foundation": ">3.4", - "symfony/http-kernel": ">3.4", - "symfony/options-resolver": ">3.4", - "symfony/security-core": ">3.4", + "symfony/config": ">4.0", + "symfony/dependency-injection": ">4.0", + "symfony/event-dispatcher": ">4.0", + "symfony/http-foundation": ">4.0", + "symfony/http-kernel": ">4.0", + "symfony/options-resolver": ">4.0", + "symfony/security-core": ">4.0", "twig/twig": ">2.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.10", + "knplabs/knp-menu-bundle": "^2.2", "phpspec/prophecy": "^1.6", - "phpunit/phpunit": "^7.3" + "phpstan/phpstan": "^0.11.8", + "phpstan/phpstan-phpunit": "^0.11.2", + "phpunit/phpunit": "^7.3", + "symfony/framework-bundle": ">4.0" }, "suggest": { "friendsofsymfony/user-bundle": "Allows easy user management and security support", @@ -3028,7 +3032,7 @@ } ], "description": "Admin theme bundle for Symfony 4 based on AdminLTE 2.4.8 with FOSUserBundle support", - "time": "2019-05-13T16:17:08+00:00" + "time": "2019-06-13T11:25:39+00:00" }, { "name": "kimai/kimai2-composer", diff --git a/config/packages/jms_serializer.yaml b/config/packages/jms_serializer.yaml index fe0f7f3e..74bdc08e 100644 --- a/config/packages/jms_serializer.yaml +++ b/config/packages/jms_serializer.yaml @@ -13,5 +13,12 @@ jms_serializer: App: namespace_prefix: "App" path: "%kernel.root_dir%/../config/serializer/App" + warmup: + paths: + included: + - "%kernel.root_dir%/Entity/" + - "%kernel.root_dir%/API/Model/" + - "%kernel.root_dir%/../vendor/friendsofsymfony/user-bundle/Model" + excluded: [] property_naming: id: 'jms_serializer.identical_property_naming_strategy' diff --git a/config/packages/kimai.yaml b/config/packages/kimai.yaml index 3d4dbd36..8d436c3a 100644 --- a/config/packages/kimai.yaml +++ b/config/packages/kimai.yaml @@ -169,7 +169,8 @@ kimai: title: dashboard.you order: 10 permission: ROLE_USER - widgets: [userDurationToday, userDurationWeek, userDurationMonth, userDurationYear] + type: 'compoundChart' + widgets: [DailyWorkingTimeChart, userDurationToday, userDurationWeek, userDurationMonth, userDurationYear] user_rates: title: ~ order: 20 @@ -190,34 +191,6 @@ kimai: order: 50 permission: view_rate_other_timesheet widgets: [amountToday, amountWeek, amountMonth, amountYear] - - widgets: - userDurationToday: { title: stats.durationToday, query: duration, user: true, begin: '00:00:00', end: '23:59:59', icon: duration, color: green } - userDurationWeek: { title: stats.durationWeek, query: duration, user: true, begin: 'monday this week 00:00:00', end: 'sunday this week 23:59:59', icon: duration, color: blue } - userDurationMonth: { title: stats.durationMonth, query: duration, user: true, begin: 'first day of this month 00:00:00', end: 'last day of this month 23:59:59', icon: duration, color: purple } - userDurationYear: { title: stats.durationYear, query: duration, user: true, begin: '01 january this year 00:00:00', end: '31 december this year 23:59:59', icon: duration, color: yellow } - userDurationTotal: { title: stats.durationTotal, query: duration, user: true, icon: duration, color: red } - userAmountToday: { title: stats.amountToday, query: rate, user: true, begin: '00:00:00', end: '23:59:59', icon: money, color: green } - userAmountWeek: { title: stats.amountWeek, query: rate, user: true, begin: 'monday this week 00:00:00', end: 'sunday this week 23:59:59', icon: money, color: blue } - userAmountMonth: { title: stats.amountMonth, query: rate, user: true, begin: 'first day of this month 00:00:00', end: 'last day of this month 23:59:59', icon: money, color: purple } - userAmountYear: { title: stats.amountYear, query: rate, user: true, begin: '01 january this year 00:00:00', end: '31 december this year 23:59:59', icon: money, color: yellow } - userAmountTotal: { title: stats.amountTotal, query: rate, user: true, icon: money, color: red } - durationToday: { title: stats.durationToday, query: duration, begin: '00:00:00', end: '23:59:59', icon: duration, color: green } - durationWeek: { title: stats.durationWeek, query: duration, begin: 'monday this week 00:00:00', end: 'sunday this week 23:59:59', icon: duration, color: blue } - durationMonth: { title: stats.durationMonth, query: duration, begin: 'first day of this month 00:00:00', end: 'last day of this month 23:59:59', icon: duration, color: purple } - durationYear: { title: stats.durationYear, query: duration, begin: '01 january this year 00:00:00', end: '31 december this year 23:59:59', icon: duration, color: yellow } - durationTotal: { title: stats.durationTotal, query: duration, icon: duration, color: red } - amountToday: { title: stats.amountToday, query: rate, begin: '00:00:00', end: '23:59:59', icon: money, color: green } - amountWeek: { title: stats.amountWeek, query: rate, begin: 'monday this week 00:00:00', end: 'sunday this week 23:59:59', icon: money, color: blue } - amountMonth: { title: stats.amountMonth, query: rate, begin: 'first day of this month 00:00:00', end: 'last day of this month 23:59:59', icon: money, color: purple } - amountYear: { title: stats.amountYear, query: rate, begin: '01 january this year 00:00:00', end: '31 december this year 23:59:59', icon: money, color: yellow } - amountTotal: { title: stats.amountTotal, query: rate, icon: money, color: red } - activeUsersToday: { title: stats.userActiveToday, query: users, begin: '00:00:00', end: '23:59:59', icon: user, color: green } - activeUsersWeek: { title: stats.userActiveWeek, query: users, begin: 'monday this week 00:00:00', end: 'sunday this week 23:59:59', icon: user, color: blue } - activeUsersMonth: { title: stats.userActiveMonth, query: users, begin: 'first day of this month 00:00:00', end: 'last day of this month 23:59:59', icon: user, color: purple } - activeUsersYear: { title: stats.userActiveYear, query: users, begin: '01 january this year 00:00:00', end: '31 december this year 23:59:59', icon: user, color: yellow } - activeUsersTotal: { title: stats.userActiveTotal, query: users, icon: user, color: red } - activeRecordings: { title: stats.activeRecordings, query: active, icon: duration, color: red } # -------------------------------------------------------------------------------- diff --git a/config/services.yaml b/config/services.yaml index 4d79a39d..e7ef3a45 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -77,6 +77,10 @@ services: App\Export\ServiceExport: arguments: [!tagged export.renderer] + App\Widget\WidgetService: + arguments: + $renderer: !tagged widget.renderer + # ================================================================================ # DATABASE # ================================================================================ diff --git a/public/build/app.26c26669.js b/public/build/app.0ac6f178.js similarity index 75% rename from public/build/app.26c26669.js rename to public/build/app.0ac6f178.js index ae056544..d5d2b798 100644 --- a/public/build/app.26c26669.js +++ b/public/build/app.0ac6f178.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([["app"],{"+2oP":function(t,e,n){"use strict";var i=n("I+eb"),o=n("hh1v"),s=n("6LWA"),r=n("I8vh"),a=n("UMSQ"),l=n("/GqU"),c=n("hBjN"),u=n("Hd5f"),d=n("tiKp")("species"),h=[].slice,f=Math.max;i({target:"Array",proto:!0,forced:!u("slice")},{slice:function(t,e){var n,i,u,p=l(this),m=a(p.length),g=r(t,m),v=r(void 0===e?m:e,m);if(s(p)&&("function"!=typeof(n=p.constructor)||n!==Array&&!s(n.prototype)?o(n)&&null===(n=n[d])&&(n=void 0):n=void 0,n===Array||void 0===n))return h.call(p,g,v);for(i=new(void 0===n?Array:n)(f(v-g,0)),u=0;g")}),u=!s(function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var n="ab".split(t);return 2!==n.length||"a"!==n[0]||"b"!==n[1]});t.exports=function(t,e,n,d){var h=r(t),f=!s(function(){var e={};return e[h]=function(){return 7},7!=""[t](e)}),p=f&&!s(function(){var e=!1,n=/a/;return n.exec=function(){return e=!0,null},"split"===t&&(n.constructor={},n.constructor[l]=function(){return n}),n[h](""),!e});if(!f||!p||"replace"===t&&!c||"split"===t&&!u){var m=/./[h],g=n(h,""[t],function(t,e,n,i,o){return e.exec===a?f&&!o?{done:!0,value:m.call(e,n,i)}:{done:!0,value:t.call(n,e,i)}:{done:!1}}),v=g[0],b=g[1];o(String.prototype,t,v),o(RegExp.prototype,h,2==e?function(t,e){return b.call(t,this,e)}:function(t){return b.call(t,this)}),d&&i(RegExp.prototype[h],"sham",!0)}}},"1E5z":function(t,e,n){var i=n("m/L8").f,o=n("UTVS"),s=n("tiKp")("toStringTag");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,s)&&i(t,s,{configurable:!0,value:e})}},"1Wo5":function(t,e,n){(function(t){var e=n("EVdn");t.$=t.jQuery=e,n("VSY+"),n("Onkx"),n("DPhY");var i=n("wd/R");t.moment=i,n("tGlX"),n("bpih"),n("nyYc"),n("iYuL"),n("lXzo"),n("jnO4"),n("WxRl"),n("0tRk"),n("X709"),n("B55N"),n("eHjp"),n("+jAj"),n("Qiut"),n("vh7O"),n("WySY"),t.$.AdminLTE={},t.$.AdminLTE.options={},n("qG+3"),n("NlKh"),n("zcCC"),n("9/yf")}).call(this,n("yLpj"))},"2B1R":function(t,e,n){"use strict";var i=n("I+eb"),o=n("P0SU"),s=n("Hd5f"),r=o(1);i({target:"Array",proto:!0,forced:!s("map")},{map:function(t){return r(this,t,arguments[1])}})},"2oRo":function(t,e,n){(function(e){var n="object",i=function(t){return t&&t.Math==Math&&t};t.exports=i(typeof globalThis==n&&globalThis)||i(typeof window==n&&window)||i(typeof self==n&&self)||i(typeof e==n&&e)||Function("return this")()}).call(this,n("yLpj"))},"33Wh":function(t,e,n){var i=n("yoRg"),o=n("eDl+");t.exports=Object.keys||function(t){return i(t,o)}},"3UD+":function(t,e){t.exports=function(t){if(!t.webpackPolyfill){var e=Object.create(t);e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),Object.defineProperty(e,"exports",{enumerable:!0}),e.webpackPolyfill=1}return e}},"3bBZ":function(t,e,n){var i=n("2oRo"),o=n("/byt"),s=n("4mDm"),r=n("X2U+"),a=n("tiKp"),l=a("iterator"),c=a("toStringTag"),u=s.values;for(var d in o){var h=i[d],f=h&&h.prototype;if(f){if(f[l]!==u)try{r(f,l,u)}catch(t){f[l]=u}if(f[c]||r(f,c,d),o[d])for(var p in s)if(f[p]!==s[p])try{r(f,p,s[p])}catch(t){f[p]=s[p]}}}},"4Brf":function(t,e,n){"use strict";var i=n("I+eb"),o=n("g6v/"),s=n("2oRo"),r=n("UTVS"),a=n("hh1v"),l=n("m/L8").f,c=n("6JNq"),u=s.Symbol;if(o&&"function"==typeof u&&(!("description"in u.prototype)||void 0!==u().description)){var d={},h=function(){var t=arguments.length<1||void 0===arguments[0]?void 0:String(arguments[0]),e=this instanceof h?new u(t):void 0===t?u():u(t);return""===t&&(d[e]=!0),e};c(h,u);var f=h.prototype=u.prototype;f.constructor=h;var p=f.toString,m="Symbol(test)"==String(u("test")),g=/^Symbol\((.*)\)[^)]+$/;l(f,"description",{configurable:!0,get:function(){var t=a(this)?this.valueOf():this,e=p.call(t);if(r(d,t))return"";var n=m?e.slice(7,-1):e.replace(g,"$1");return""===n?void 0:n}}),i({global:!0,forced:!0},{Symbol:h})}},"4WOD":function(t,e,n){var i=n("UTVS"),o=n("ewvW"),s=n("93I0"),r=n("4Xet"),a=s("IE_PROTO"),l=Object.prototype;t.exports=r?Object.getPrototypeOf:function(t){return t=o(t),i(t,a)?t[a]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?l:null}},"4Xet":function(t,e,n){var i=n("0Dky");t.exports=!i(function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype})},"4l63":function(t,e,n){var i=n("I+eb"),o=n("5YOQ");i({global:!0,forced:parseInt!=o},{parseInt:o})},"4mDm":function(t,e,n){"use strict";var i=n("/GqU"),o=n("RNIs"),s=n("P4y1"),r=n("afO8"),a=n("fdAy"),l=r.set,c=r.getterFor("Array Iterator");t.exports=a(Array,"Array",function(t,e){l(this,{type:"Array Iterator",target:i(t),index:0,kind:e})},function(){var t=c(this),e=t.target,n=t.kind,i=t.index++;return!e||i>=e.length?(t.target=void 0,{value:void 0,done:!0}):"keys"==n?{value:i,done:!1}:"values"==n?{value:e[i],done:!1}:{value:[i,e[i]],done:!1}},"values"),s.Arguments=s.Array,o("keys"),o("values"),o("entries")},"5YOQ":function(t,e,n){var i=n("2oRo"),o=n("WKiH"),s=n("WJkJ"),r=i.parseInt,a=/^[+-]?0[Xx]/,l=8!==r(s+"08")||22!==r(s+"0x16");t.exports=l?function(t,e){var n=o(String(t),3);return r(n,e>>>0||(a.test(n)?16:10))}:r},"5dW1":function(t,e,n){var i=n("ppGB"),o=n("HYAF");t.exports=function(t,e,n){var s,r,a=String(o(t)),l=i(e),c=a.length;return l<0||l>=c?n?"":void 0:(s=a.charCodeAt(l))<55296||s>56319||l+1===c||(r=a.charCodeAt(l+1))<56320||r>57343?n?a.charAt(l):s:n?a.slice(l,l+2):r-56320+(s-55296<<10)+65536}},"6JNq":function(t,e,n){var i=n("UTVS"),o=n("Vu81"),s=n("Bs8V"),r=n("m/L8");t.exports=function(t,e){for(var n=o(e),a=r.f,l=s.f,c=0;c",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var e,n,i,o=this.element[0].nodeName.toLowerCase(),s="textarea"===o,r="input"===o;this.isMultiLine=s||!r&&this._isContentEditable(this.element),this.valueMethod=this.element[s||r?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(o){if(this.element.prop("readOnly"))return e=!0,i=!0,void(n=!0);e=!1,i=!1,n=!1;var s=t.ui.keyCode;switch(o.keyCode){case s.PAGE_UP:e=!0,this._move("previousPage",o);break;case s.PAGE_DOWN:e=!0,this._move("nextPage",o);break;case s.UP:e=!0,this._keyEvent("previous",o);break;case s.DOWN:e=!0,this._keyEvent("next",o);break;case s.ENTER:this.menu.active&&(e=!0,o.preventDefault(),this.menu.select(o));break;case s.TAB:this.menu.active&&this.menu.select(o);break;case s.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(o),o.preventDefault());break;default:n=!0,this._searchTimeout(o)}},keypress:function(i){if(e)return e=!1,void(this.isMultiLine&&!this.menu.element.is(":visible")||i.preventDefault());if(!n){var o=t.ui.keyCode;switch(i.keyCode){case o.PAGE_UP:this._move("previousPage",i);break;case o.PAGE_DOWN:this._move("nextPage",i);break;case o.UP:this._keyEvent("previous",i);break;case o.DOWN:this._keyEvent("next",i)}}},input:function(t){if(i)return i=!1,void t.preventDefault();this._searchTimeout(t)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){this.cancelBlur?delete this.cancelBlur:(clearTimeout(this.searching),this.close(t),this._change(t))}}),this._initSource(),this.menu=t("