diff --git a/.gitignore b/.gitignore index 680bd19c8e..0b6eeaec46 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ !/apps/cloud_federation_api !/apps/comments !/apps/contactsinteraction +!/apps/dashboard !/apps/dav !/apps/files !/apps/federation diff --git a/apps/dashboard/appinfo/info.xml b/apps/dashboard/appinfo/info.xml new file mode 100644 index 0000000000..9d3b7fc841 --- /dev/null +++ b/apps/dashboard/appinfo/info.xml @@ -0,0 +1,30 @@ + + + dashboard + Dashboard + Dashboard app + + 7.0.0 + agpl + Julius Härtl + Dashboard + + + customization + + https://github.com/nextcloud/server/issues + + + + + + + + Dashboard + dashboard.dashboard.index + dashboard.svg + -1 + + + diff --git a/apps/dashboard/appinfo/routes.php b/apps/dashboard/appinfo/routes.php new file mode 100644 index 0000000000..34792a9d47 --- /dev/null +++ b/apps/dashboard/appinfo/routes.php @@ -0,0 +1,31 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +return [ + 'routes' => [ + ['name' => 'dashboard#index', 'url' => '/', 'verb' => 'GET'], + ] +]; diff --git a/apps/dashboard/img/dashboard.svg b/apps/dashboard/img/dashboard.svg new file mode 100644 index 0000000000..07d838ec9f --- /dev/null +++ b/apps/dashboard/img/dashboard.svg @@ -0,0 +1 @@ + diff --git a/apps/dashboard/js/dashboard.js b/apps/dashboard/js/dashboard.js new file mode 100644 index 0000000000..9085eeaffd --- /dev/null +++ b/apps/dashboard/js/dashboard.js @@ -0,0 +1,2 @@ +!function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/js/",n(n.s=117)}([function(t,e,n){(function(e){var n=function(t){return t&&t.Math==Math&&t};t.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof e&&e)||Function("return this")()}).call(this,n(13))},function(t,e,n){var r=n(0),o=n(43),i=n(3),a=n(27),s=n(48),u=n(77),c=o("wks"),f=r.Symbol,l=u?f:f&&f.withoutSetter||a;t.exports=function(t){return i(c,t)||(s&&i(f,t)?c[t]=f[t]:c[t]=l("Symbol."+t)),c[t]}},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var r=n(6),o=n(39),i=n(8),a=n(23),s=Object.defineProperty;e.f=r?s:function(t,e,n){if(i(t),e=a(e,!0),i(n),o)try{return s(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},function(t,e,n){var r=n(2);t.exports=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},function(t,e,n){var r=n(6),o=n(5),i=n(14);t.exports=r?function(t,e,n){return o.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r=n(4);t.exports=function(t){if(!r(t))throw TypeError(String(t)+" is not an object");return t}},function(t,e,n){var r=n(0),o=n(37).f,i=n(7),a=n(10),s=n(24),u=n(69),c=n(45);t.exports=function(t,e){var n,f,l,p,d,v=t.target,h=t.global,m=t.stat;if(n=h?r:m?r[v]||s(v,{}):(r[v]||{}).prototype)for(f in e){if(p=e[f],l=t.noTargetGet?(d=o(n,f))&&d.value:n[f],!c(h?f:v+(m?".":"#")+f,t.forced)&&void 0!==l){if(typeof p==typeof l)continue;u(p,l)}(t.sham||l&&l.sham)&&i(p,"sham",!0),a(n,f,p,t)}}},function(t,e,n){var r=n(0),o=n(7),i=n(3),a=n(24),s=n(41),u=n(16),c=u.get,f=u.enforce,l=String(String).split("String");(t.exports=function(t,e,n,s){var u=!!s&&!!s.unsafe,c=!!s&&!!s.enumerable,p=!!s&&!!s.noTargetGet;"function"==typeof n&&("string"!=typeof e||i(n,"name")||o(n,"name",e),f(n).source=l.join("string"==typeof e?e:"")),t!==r?(u?!p&&t[e]&&(c=!0):delete t[e],c?t[e]=n:o(t,e,n)):c?t[e]=n:a(e,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&c(this).source||s(this)}))},function(t,e){t.exports={}},function(t,e,n){"use strict";(function(t,n){var r=Object.freeze({});function o(t){return null==t}function i(t){return null!=t}function a(t){return!0===t}function s(t){return"string"==typeof t||"number"==typeof t||"symbol"==typeof t||"boolean"==typeof t}function u(t){return null!==t&&"object"==typeof t}var c=Object.prototype.toString;function f(t){return"[object Object]"===c.call(t)}function l(t){return"[object RegExp]"===c.call(t)}function p(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function d(t){return i(t)&&"function"==typeof t.then&&"function"==typeof t.catch}function v(t){return null==t?"":Array.isArray(t)||f(t)&&t.toString===c?JSON.stringify(t,null,2):String(t)}function h(t){var e=parseFloat(t);return isNaN(e)?t:e}function m(t,e){for(var n=Object.create(null),r=t.split(","),o=0;o-1)return t.splice(n,1)}}var b=Object.prototype.hasOwnProperty;function _(t,e){return b.call(t,e)}function E(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}var O=/-(\w)/g,w=E((function(t){return t.replace(O,(function(t,e){return e?e.toUpperCase():""}))})),x=E((function(t){return t.charAt(0).toUpperCase()+t.slice(1)})),A=/\B([A-Z])/g,I=E((function(t){return t.replace(A,"-$1").toLowerCase()}));var C=Function.prototype.bind?function(t,e){return t.bind(e)}:function(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n};function S(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function T(t,e){for(var n in e)t[n]=e[n];return t}function R(t){for(var e={},n=0;n0,Z=W&&W.indexOf("edge/")>0,J=(W&&W.indexOf("android"),W&&/iphone|ipad|ipod|ios/.test(W)||"ios"===q),Q=(W&&/chrome\/\d+/.test(W),W&&/phantomjs/.test(W),W&&W.match(/firefox\/(\d+)/)),tt={}.watch,et=!1;if(z)try{var nt={};Object.defineProperty(nt,"passive",{get:function(){et=!0}}),window.addEventListener("test-passive",null,nt)}catch(t){}var rt=function(){return void 0===V&&(V=!z&&!H&&void 0!==t&&(t.process&&"server"===t.process.env.VUE_ENV)),V},ot=z&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function it(t){return"function"==typeof t&&/native code/.test(t.toString())}var at,st="undefined"!=typeof Symbol&&it(Symbol)&&"undefined"!=typeof Reflect&&it(Reflect.ownKeys);at="undefined"!=typeof Set&&it(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var ut=L,ct=0,ft=function(){this.id=ct++,this.subs=[]};ft.prototype.addSub=function(t){this.subs.push(t)},ft.prototype.removeSub=function(t){g(this.subs,t)},ft.prototype.depend=function(){ft.target&&ft.target.addDep(this)},ft.prototype.notify=function(){var t=this.subs.slice();for(var e=0,n=t.length;e-1)if(i&&!_(o,"default"))a=!1;else if(""===a||a===I(t)){var u=Gt(String,o.type);(u<0||s0&&(fe((u=t(u,(n||"")+"_"+r))[0])&&fe(f)&&(l[c]=yt(f.text+u[0].text),u.shift()),l.push.apply(l,u)):s(u)?fe(f)?l[c]=yt(f.text+u):""!==u&&l.push(yt(u)):fe(u)&&fe(f)?l[c]=yt(f.text+u.text):(a(e._isVList)&&i(u.tag)&&o(u.key)&&i(n)&&(u.key="__vlist"+n+"_"+r+"__"),l.push(u)));return l}(t):void 0}function fe(t){return i(t)&&i(t.text)&&!1===t.isComment}function le(t,e){if(t){for(var n=Object.create(null),r=st?Reflect.ownKeys(t):Object.keys(t),o=0;o0,a=t?!!t.$stable:!i,s=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(a&&n&&n!==r&&s===n.$key&&!i&&!n.$hasNormal)return n;for(var u in o={},t)t[u]&&"$"!==u[0]&&(o[u]=he(e,u,t[u]))}else o={};for(var c in e)c in o||(o[c]=me(e,c));return t&&Object.isExtensible(t)&&(t._normalized=o),G(o,"$stable",a),G(o,"$key",s),G(o,"$hasNormal",i),o}function he(t,e,n){var r=function(){var t=arguments.length?n.apply(null,arguments):n({});return(t=t&&"object"==typeof t&&!Array.isArray(t)?[t]:ce(t))&&(0===t.length||1===t.length&&t[0].isComment)?void 0:t};return n.proxy&&Object.defineProperty(t,e,{get:r,enumerable:!0,configurable:!0}),r}function me(t,e){return function(){return t[e]}}function ye(t,e){var n,r,o,a,s;if(Array.isArray(t)||"string"==typeof t)for(n=new Array(t.length),r=0,o=t.length;rdocument.createEvent("Event").timeStamp&&(un=function(){return cn.now()})}function fn(){var t,e;for(sn=un(),on=!0,tn.sort((function(t,e){return t.id-e.id})),an=0;anan&&tn[n].id>t.id;)n--;tn.splice(n+1,0,t)}else tn.push(t);rn||(rn=!0,ee(fn))}}(this)},pn.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||u(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(t){Bt(t,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,t,e)}}},pn.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},pn.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},pn.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||g(this.vm._watchers,this);for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1}};var dn={enumerable:!0,configurable:!0,get:L,set:L};function vn(t,e,n){dn.get=function(){return this[e][n]},dn.set=function(t){this[e][n]=t},Object.defineProperty(t,n,dn)}function hn(t){t._watchers=[];var e=t.$options;e.props&&function(t,e){var n=t.$options.propsData||{},r=t._props={},o=t.$options._propKeys=[];t.$parent&&wt(!1);var i=function(i){o.push(i);var a=Dt(i,e,n,t);It(r,i,a),i in t||vn(t,"_props",i)};for(var a in e)i(a);wt(!0)}(t,e.props),e.methods&&function(t,e){t.$options.props;for(var n in e)t[n]="function"!=typeof e[n]?L:C(e[n],t)}(t,e.methods),e.data?function(t){var e=t.$options.data;f(e=t._data="function"==typeof e?function(t,e){pt();try{return t.call(e,e)}catch(t){return Bt(t,e,"data()"),{}}finally{dt()}}(e,t):e||{})||(e={});var n=Object.keys(e),r=t.$options.props,o=(t.$options.methods,n.length);for(;o--;){var i=n[o];0,r&&_(r,i)||(a=void 0,36!==(a=(i+"").charCodeAt(0))&&95!==a&&vn(t,"_data",i))}var a;At(e,!0)}(t):At(t._data={},!0),e.computed&&function(t,e){var n=t._computedWatchers=Object.create(null),r=rt();for(var o in e){var i=e[o],a="function"==typeof i?i:i.get;0,r||(n[o]=new pn(t,a||L,L,mn)),o in t||yn(t,o,i)}}(t,e.computed),e.watch&&e.watch!==tt&&function(t,e){for(var n in e){var r=e[n];if(Array.isArray(r))for(var o=0;o-1:"string"==typeof t?t.split(",").indexOf(e)>-1:!!l(t)&&t.test(e)}function Cn(t,e){var n=t.cache,r=t.keys,o=t._vnode;for(var i in n){var a=n[i];if(a){var s=An(a.componentOptions);s&&!e(s)&&Sn(n,i,r,o)}}}function Sn(t,e,n,r){var o=t[e];!o||r&&o.tag===r.tag||o.componentInstance.$destroy(),t[e]=null,g(n,e)}!function(t){t.prototype._init=function(t){var e=this;e._uid=En++,e._isVue=!0,t&&t._isComponent?function(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var o=r.componentOptions;n.propsData=o.propsData,n._parentListeners=o.listeners,n._renderChildren=o.children,n._componentTag=o.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}(e,t):e.$options=Pt(On(e.constructor),t||{},e),e._renderProxy=e,e._self=e,function(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}(e),function(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&We(t,e)}(e),function(t){t._vnode=null,t._staticTrees=null;var e=t.$options,n=t.$vnode=e._parentVnode,o=n&&n.context;t.$slots=pe(e._renderChildren,o),t.$scopedSlots=r,t._c=function(e,n,r,o){return Fe(t,e,n,r,o,!1)},t.$createElement=function(e,n,r,o){return Fe(t,e,n,r,o,!0)};var i=n&&n.data;It(t,"$attrs",i&&i.attrs||r,null,!0),It(t,"$listeners",e._parentListeners||r,null,!0)}(e),Qe(e,"beforeCreate"),function(t){var e=le(t.$options.inject,t);e&&(wt(!1),Object.keys(e).forEach((function(n){It(t,n,e[n])})),wt(!0))}(e),hn(e),function(t){var e=t.$options.provide;e&&(t._provided="function"==typeof e?e.call(t):e)}(e),Qe(e,"created"),e.$options.el&&e.$mount(e.$options.el)}}(wn),function(t){var e={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(t.prototype,"$data",e),Object.defineProperty(t.prototype,"$props",n),t.prototype.$set=Ct,t.prototype.$delete=St,t.prototype.$watch=function(t,e,n){if(f(e))return _n(this,t,e,n);(n=n||{}).user=!0;var r=new pn(this,t,e,n);if(n.immediate)try{e.call(this,r.value)}catch(t){Bt(t,this,'callback for immediate watcher "'+r.expression+'"')}return function(){r.teardown()}}}(wn),function(t){var e=/^hook:/;t.prototype.$on=function(t,n){var r=this;if(Array.isArray(t))for(var o=0,i=t.length;o1?S(n):n;for(var r=S(arguments,1),o='event handler for "'+t+'"',i=0,a=n.length;iparseInt(this.max)&&Sn(a,s[0],s,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={get:function(){return F}};Object.defineProperty(t,"config",e),t.util={warn:ut,extend:T,mergeOptions:Pt,defineReactive:It},t.set=Ct,t.delete=St,t.nextTick=ee,t.observable=function(t){return At(t),t},t.options=Object.create(null),M.forEach((function(e){t.options[e+"s"]=Object.create(null)})),t.options._base=t,T(t.options.components,Rn),function(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=S(arguments,1);return n.unshift(this),"function"==typeof t.install?t.install.apply(t,n):"function"==typeof t&&t.apply(null,n),e.push(t),this}}(t),function(t){t.mixin=function(t){return this.options=Pt(this.options,t),this}}(t),xn(t),function(t){M.forEach((function(e){t[e]=function(t,n){return n?("component"===e&&f(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&"function"==typeof n&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}}))}(t)}(wn),Object.defineProperty(wn.prototype,"$isServer",{get:rt}),Object.defineProperty(wn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(wn,"FunctionalRenderContext",{value:Ne}),wn.version="2.6.11";var Ln=m("style,class"),Nn=m("input,textarea,option,select,progress"),kn=m("contenteditable,draggable,spellcheck"),$n=m("events,caret,typing,plaintext-only"),jn=m("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),Pn="http://www.w3.org/1999/xlink",Mn=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},Dn=function(t){return Mn(t)?t.slice(6,t.length):""},Fn=function(t){return null==t||!1===t};function Un(t){for(var e=t.data,n=t,r=t;i(r.componentInstance);)(r=r.componentInstance._vnode)&&r.data&&(e=Gn(r.data,e));for(;i(n=n.parent);)n&&n.data&&(e=Gn(e,n.data));return function(t,e){if(i(t)||i(e))return Bn(t,Vn(e));return""}(e.staticClass,e.class)}function Gn(t,e){return{staticClass:Bn(t.staticClass,e.staticClass),class:i(t.class)?[t.class,e.class]:e.class}}function Bn(t,e){return t?e?t+" "+e:t:e||""}function Vn(t){return Array.isArray(t)?function(t){for(var e,n="",r=0,o=t.length;r-1?pr(t,e,n):jn(e)?Fn(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):kn(e)?t.setAttribute(e,function(t,e){return Fn(e)||"false"===e?"false":"contenteditable"===t&&$n(e)?e:"true"}(e,n)):Mn(e)?Fn(n)?t.removeAttributeNS(Pn,Dn(e)):t.setAttributeNS(Pn,e,n):pr(t,e,n)}function pr(t,e,n){if(Fn(n))t.removeAttribute(e);else{if(K&&!Y&&"TEXTAREA"===t.tagName&&"placeholder"===e&&""!==n&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener("input",r)};t.addEventListener("input",r),t.__ieph=!0}t.setAttribute(e,n)}}var dr={create:fr,update:fr};function vr(t,e){var n=e.elm,r=e.data,a=t.data;if(!(o(r.staticClass)&&o(r.class)&&(o(a)||o(a.staticClass)&&o(a.class)))){var s=Un(e),u=n._transitionClasses;i(u)&&(s=Bn(s,Vn(u))),s!==n._prevClass&&(n.setAttribute("class",s),n._prevClass=s)}}var hr,mr={create:vr,update:vr};function yr(t,e,n){var r=hr;return function o(){var i=e.apply(null,arguments);null!==i&&_r(t,o,n,r)}}var gr=qt&&!(Q&&Number(Q[1])<=53);function br(t,e,n,r){if(gr){var o=sn,i=e;e=i._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=o||t.timeStamp<=0||t.target.ownerDocument!==document)return i.apply(this,arguments)}}hr.addEventListener(t,e,et?{capture:n,passive:r}:n)}function _r(t,e,n,r){(r||hr).removeEventListener(t,e._wrapper||e,n)}function Er(t,e){if(!o(t.data.on)||!o(e.data.on)){var n=e.data.on||{},r=t.data.on||{};hr=e.elm,function(t){if(i(t.__r)){var e=K?"change":"input";t[e]=[].concat(t.__r,t[e]||[]),delete t.__r}i(t.__c)&&(t.change=[].concat(t.__c,t.change||[]),delete t.__c)}(n),ae(n,r,br,_r,yr,e.context),hr=void 0}}var Or,wr={create:Er,update:Er};function xr(t,e){if(!o(t.data.domProps)||!o(e.data.domProps)){var n,r,a=e.elm,s=t.data.domProps||{},u=e.data.domProps||{};for(n in i(u.__ob__)&&(u=e.data.domProps=T({},u)),s)n in u||(a[n]="");for(n in u){if(r=u[n],"textContent"===n||"innerHTML"===n){if(e.children&&(e.children.length=0),r===s[n])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===n&&"PROGRESS"!==a.tagName){a._value=r;var c=o(r)?"":String(r);Ar(a,c)&&(a.value=c)}else if("innerHTML"===n&&Hn(a.tagName)&&o(a.innerHTML)){(Or=Or||document.createElement("div")).innerHTML=""+r+"";for(var f=Or.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;f.firstChild;)a.appendChild(f.firstChild)}else if(r!==s[n])try{a[n]=r}catch(t){}}}}function Ar(t,e){return!t.composing&&("OPTION"===t.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}(t,e)||function(t,e){var n=t.value,r=t._vModifiers;if(i(r)){if(r.number)return h(n)!==h(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}(t,e))}var Ir={create:xr,update:xr},Cr=E((function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach((function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}})),e}));function Sr(t){var e=Tr(t.style);return t.staticStyle?T(t.staticStyle,e):e}function Tr(t){return Array.isArray(t)?R(t):"string"==typeof t?Cr(t):t}var Rr,Lr=/^--/,Nr=/\s*!important$/,kr=function(t,e,n){if(Lr.test(e))t.style.setProperty(e,n);else if(Nr.test(n))t.style.setProperty(I(e),n.replace(Nr,""),"important");else{var r=jr(e);if(Array.isArray(n))for(var o=0,i=n.length;o-1?e.split(Dr).forEach((function(e){return t.classList.add(e)})):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function Ur(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(Dr).forEach((function(e){return t.classList.remove(e)})):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" "+(t.getAttribute("class")||"")+" ",r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function Gr(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&T(e,Br(t.name||"v")),T(e,t),e}return"string"==typeof t?Br(t):void 0}}var Br=E((function(t){return{enterClass:t+"-enter",enterToClass:t+"-enter-to",enterActiveClass:t+"-enter-active",leaveClass:t+"-leave",leaveToClass:t+"-leave-to",leaveActiveClass:t+"-leave-active"}})),Vr=z&&!Y,Xr="transition",zr="transitionend",Hr="animation",qr="animationend";Vr&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(Xr="WebkitTransition",zr="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Hr="WebkitAnimation",qr="webkitAnimationEnd"));var Wr=z?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function Kr(t){Wr((function(){Wr(t)}))}function Yr(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),Fr(t,e))}function Zr(t,e){t._transitionClasses&&g(t._transitionClasses,e),Ur(t,e)}function Jr(t,e,n){var r=to(t,e),o=r.type,i=r.timeout,a=r.propCount;if(!o)return n();var s="transition"===o?zr:qr,u=0,c=function(){t.removeEventListener(s,f),n()},f=function(e){e.target===t&&++u>=a&&c()};setTimeout((function(){u0&&(n="transition",f=a,l=i.length):"animation"===e?c>0&&(n="animation",f=c,l=u.length):l=(n=(f=Math.max(a,c))>0?a>c?"transition":"animation":null)?"transition"===n?i.length:u.length:0,{type:n,timeout:f,propCount:l,hasTransform:"transition"===n&&Qr.test(r[Xr+"Property"])}}function eo(t,e){for(;t.length1}function so(t,e){!0!==e.data.show&&ro(e)}var uo=function(t){var e,n,r={},u=t.modules,c=t.nodeOps;for(e=0;ev?b(t,o(n[y+1])?null:n[y+1].elm,n,d,y,r):d>y&&E(e,p,v)}(p,m,y,n,f):i(y)?(i(t.text)&&c.setTextContent(p,""),b(p,null,y,0,y.length-1,n)):i(m)?E(m,0,m.length-1):i(t.text)&&c.setTextContent(p,""):t.text!==e.text&&c.setTextContent(p,e.text),i(v)&&i(d=v.hook)&&i(d=d.postpatch)&&d(t,e)}}}function A(t,e,n){if(a(n)&&i(t.parent))t.parent.data.pendingInsert=e;else for(var r=0;r-1,a.selected!==i&&(a.selected=i);else if($(vo(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));o||(t.selectedIndex=-1)}}function po(t,e){return e.every((function(e){return!$(e,t)}))}function vo(t){return"_value"in t?t._value:t.value}function ho(t){t.target.composing=!0}function mo(t){t.target.composing&&(t.target.composing=!1,yo(t.target,"input"))}function yo(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function go(t){return!t.componentInstance||t.data&&t.data.transition?t:go(t.componentInstance._vnode)}var bo={model:co,show:{bind:function(t,e,n){var r=e.value,o=(n=go(n)).data&&n.data.transition,i=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;r&&o?(n.data.show=!0,ro(n,(function(){t.style.display=i}))):t.style.display=r?i:"none"},update:function(t,e,n){var r=e.value;!r!=!e.oldValue&&((n=go(n)).data&&n.data.transition?(n.data.show=!0,r?ro(n,(function(){t.style.display=t.__vOriginalDisplay})):oo(n,(function(){t.style.display="none"}))):t.style.display=r?t.__vOriginalDisplay:"none")},unbind:function(t,e,n,r,o){o||(t.style.display=t.__vOriginalDisplay)}}},_o={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function Eo(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?Eo(Xe(e.children)):t}function Oo(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var o=n._parentListeners;for(var i in o)e[w(i)]=o[i];return e}function wo(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}var xo=function(t){return t.tag||Ve(t)},Ao=function(t){return"show"===t.name},Io={name:"transition",props:_o,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(xo)).length){0;var r=this.mode;0;var o=n[0];if(function(t){for(;t=t.parent;)if(t.data.transition)return!0}(this.$vnode))return o;var i=Eo(o);if(!i)return o;if(this._leaving)return wo(t,o);var a="__transition-"+this._uid+"-";i.key=null==i.key?i.isComment?a+"comment":a+i.tag:s(i.key)?0===String(i.key).indexOf(a)?i.key:a+i.key:i.key;var u=(i.data||(i.data={})).transition=Oo(this),c=this._vnode,f=Eo(c);if(i.data.directives&&i.data.directives.some(Ao)&&(i.data.show=!0),f&&f.data&&!function(t,e){return e.key===t.key&&e.tag===t.tag}(i,f)&&!Ve(f)&&(!f.componentInstance||!f.componentInstance._vnode.isComment)){var l=f.data.transition=T({},u);if("out-in"===r)return this._leaving=!0,se(l,"afterLeave",(function(){e._leaving=!1,e.$forceUpdate()})),wo(t,o);if("in-out"===r){if(Ve(i))return c;var p,d=function(){p()};se(u,"afterEnter",d),se(u,"enterCancelled",d),se(l,"delayLeave",(function(t){p=t}))}}return o}}},Co=T({tag:String,moveClass:String},_o);function So(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function To(t){t.data.newPos=t.elm.getBoundingClientRect()}function Ro(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,o=e.top-n.top;if(r||o){t.data.moved=!0;var i=t.elm.style;i.transform=i.WebkitTransform="translate("+r+"px,"+o+"px)",i.transitionDuration="0s"}}delete Co.mode;var Lo={Transition:Io,TransitionGroup:{props:Co,beforeMount:function(){var t=this,e=this._update;this._update=function(n,r){var o=Ye(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,o(),e.call(t,n,r)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,o=this.$slots.default||[],i=this.children=[],a=Oo(this),s=0;s-1?Wn[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:Wn[t]=/HTMLUnknownElement/.test(e.toString())},T(wn.options.directives,bo),T(wn.options.components,Lo),wn.prototype.__patch__=z?uo:L,wn.prototype.$mount=function(t,e){return function(t,e,n){var r;return t.$el=e,t.$options.render||(t.$options.render=mt),Qe(t,"beforeMount"),r=function(){t._update(t._render(),n)},new pn(t,r,L,{before:function(){t._isMounted&&!t._isDestroyed&&Qe(t,"beforeUpdate")}},!0),n=!1,null==t.$vnode&&(t._isMounted=!0,Qe(t,"mounted")),t}(this,t=t&&z?function(t){if("string"==typeof t){var e=document.querySelector(t);return e||document.createElement("div")}return t}(t):void 0,e)},z&&setTimeout((function(){F.devtools&&ot&&ot.emit("init",wn)}),0),e.a=wn}).call(this,n(13),n(112).setImmediate)},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e,n){var r=n(38),o=n(22);t.exports=function(t){return r(o(t))}},function(t,e,n){var r,o,i,a=n(68),s=n(0),u=n(4),c=n(7),f=n(3),l=n(25),p=n(17),d=s.WeakMap;if(a){var v=new d,h=v.get,m=v.has,y=v.set;r=function(t,e){return y.call(v,t,e),e},o=function(t){return h.call(v,t)||{}},i=function(t){return m.call(v,t)}}else{var g=l("state");p[g]=!0,r=function(t,e){return c(t,g,e),e},o=function(t){return f(t,g)?t[g]:{}},i=function(t){return f(t,g)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!u(e)||(n=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},function(t,e){t.exports={}},function(t,e,n){var r=n(71),o=n(0),i=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?i(r[t])||i(o[t]):r[t]&&r[t][e]||o[t]&&o[t][e]}},function(t,e,n){var r=n(28),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(115);"string"==typeof r&&(r=[[t.i,r,""]]),r.locals&&(t.exports=r.locals);(0,n(118).default)("7f4dcefc",r,!0,{})},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){var r=n(4);t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){var r=n(0),o=n(7);t.exports=function(t,e){try{o(r,t,e)}catch(n){r[t]=e}return e}},function(t,e,n){var r=n(43),o=n(27),i=r("keys");t.exports=function(t){return i[t]||(i[t]=o(t))}},function(t,e){t.exports=!1},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++n+r).toString(36)}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(t,e,n){var r=n(22);t.exports=function(t){return Object(r(t))}},function(t,e,n){var r=n(80);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 0:return function(){return t.call(e)};case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e,n){var r,o=n(8),i=n(88),a=n(29),s=n(17),u=n(90),c=n(40),f=n(25),l=f("IE_PROTO"),p=function(){},d=function(t){return"\n\n\n","import mod from \"-!../../../node_modules/babel-loader/lib/index.js!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../../node_modules/babel-loader/lib/index.js!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./App.vue?vue&type=template&id=4746e018&scoped=true&\"\nimport script from \"./App.vue?vue&type=script&lang=js&\"\nexport * from \"./App.vue?vue&type=script&lang=js&\"\nimport style0 from \"./App.vue?vue&type=style&index=0&id=4746e018&lang=scss&scoped=true&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"4746e018\",\n null\n \n)\n\nexport default component.exports","/* globals __VUE_SSR_CONTEXT__ */\n\n// IMPORTANT: Do NOT use ES2015 features in this file (except for modules).\n// This module is a runtime utility for cleaner component module output and will\n// be included in the final webpack user bundle.\n\nexport default function normalizeComponent (\n scriptExports,\n render,\n staticRenderFns,\n functionalTemplate,\n injectStyles,\n scopeId,\n moduleIdentifier, /* server only */\n shadowMode /* vue-cli only */\n) {\n // Vue.extend constructor export interop\n var options = typeof scriptExports === 'function'\n ? scriptExports.options\n : scriptExports\n\n // render functions\n if (render) {\n options.render = render\n options.staticRenderFns = staticRenderFns\n options._compiled = true\n }\n\n // functional template\n if (functionalTemplate) {\n options.functional = true\n }\n\n // scopedId\n if (scopeId) {\n options._scopeId = 'data-v-' + scopeId\n }\n\n var hook\n if (moduleIdentifier) { // server build\n hook = function (context) {\n // 2.3 injection\n context =\n context || // cached call\n (this.$vnode && this.$vnode.ssrContext) || // stateful\n (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional\n // 2.2 with runInNewContext: true\n if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {\n context = __VUE_SSR_CONTEXT__\n }\n // inject component styles\n if (injectStyles) {\n injectStyles.call(this, context)\n }\n // register component module identifier for async chunk inferrence\n if (context && context._registeredComponents) {\n context._registeredComponents.add(moduleIdentifier)\n }\n }\n // used by ssr in case component is cached and beforeCreate\n // never gets called\n options._ssrRegister = hook\n } else if (injectStyles) {\n hook = shadowMode\n ? function () {\n injectStyles.call(\n this,\n (options.functional ? this.parent : this).$root.$options.shadowRoot\n )\n }\n : injectStyles\n }\n\n if (hook) {\n if (options.functional) {\n // for template-only hot-reload because in that case the render fn doesn't\n // go through the normalizer\n options._injectStyles = hook\n // register for functional component in vue file\n var originalRender = options.render\n options.render = function renderWithStyleInjection (h, context) {\n hook.call(context)\n return originalRender(h, context)\n }\n } else {\n // inject component registration as beforeCreate hook\n var existing = options.beforeCreate\n options.beforeCreate = existing\n ? [].concat(existing, hook)\n : [hook]\n }\n }\n\n return {\n exports: scriptExports,\n options: options\n }\n}\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{attrs:{\"id\":\"app-dashboard\"}},[_c('h2',[_vm._v(_vm._s(_vm.greeting.icon)+\" \"+_vm._s(_vm.greeting.text))]),_vm._v(\" \"),_c('div',{staticClass:\"panels\"},_vm._l((_vm.panels),function(panel){return _c('div',{key:panel.id,staticClass:\"panel\"},[_c('a',{attrs:{\"href\":panel.url}},[_c('h3',{class:panel.iconClass},[_vm._v(\"\\n\\t\\t\\t\\t\\t\"+_vm._s(panel.title)+\"\\n\\t\\t\\t\\t\")])]),_vm._v(\" \"),_c('div',{ref:panel.id,refInFor:true,attrs:{\"data-id\":panel.id}})])}),0)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import Vue from 'vue'\nimport App from './App.vue'\n\nconst Dashboard = Vue.extend(App)\nconst Instance = new Dashboard({}).$mount('#app')\n\nwindow.OCA.Dashboard = {\n\tregister: (app, callback) => Instance.register(app, callback),\n}\n","/**\n * Translates the list format produced by css-loader into something\n * easier to manipulate.\n */\nexport default function listToStyles (parentId, list) {\n var styles = []\n var newStyles = {}\n for (var i = 0; i < list.length; i++) {\n var item = list[i]\n var id = item[0]\n var css = item[1]\n var media = item[2]\n var sourceMap = item[3]\n var part = {\n id: parentId + ':' + i,\n css: css,\n media: media,\n sourceMap: sourceMap\n }\n if (!newStyles[id]) {\n styles.push(newStyles[id] = { id: id, parts: [part] })\n } else {\n newStyles[id].parts.push(part)\n }\n }\n return styles\n}\n","/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n Modified by Evan You @yyx990803\n*/\n\nimport listToStyles from './listToStyles'\n\nvar hasDocument = typeof document !== 'undefined'\n\nif (typeof DEBUG !== 'undefined' && DEBUG) {\n if (!hasDocument) {\n throw new Error(\n 'vue-style-loader cannot be used in a non-browser environment. ' +\n \"Use { target: 'node' } in your Webpack config to indicate a server-rendering environment.\"\n ) }\n}\n\n/*\ntype StyleObject = {\n id: number;\n parts: Array\n}\n\ntype StyleObjectPart = {\n css: string;\n media: string;\n sourceMap: ?string\n}\n*/\n\nvar stylesInDom = {/*\n [id: number]: {\n id: number,\n refs: number,\n parts: Array<(obj?: StyleObjectPart) => void>\n }\n*/}\n\nvar head = hasDocument && (document.head || document.getElementsByTagName('head')[0])\nvar singletonElement = null\nvar singletonCounter = 0\nvar isProduction = false\nvar noop = function () {}\nvar options = null\nvar ssrIdKey = 'data-vue-ssr-id'\n\n// Force single-tag solution on IE6-9, which has a hard limit on the # of diff --git a/apps/dashboard/src/main.js b/apps/dashboard/src/main.js new file mode 100644 index 0000000000..998f538356 --- /dev/null +++ b/apps/dashboard/src/main.js @@ -0,0 +1,9 @@ +import Vue from 'vue' +import App from './App.vue' + +const Dashboard = Vue.extend(App) +const Instance = new Dashboard({}).$mount('#app') + +window.OCA.Dashboard = { + register: (app, callback) => Instance.register(app, callback), +} diff --git a/apps/dashboard/templates/index.php b/apps/dashboard/templates/index.php new file mode 100644 index 0000000000..bca9fa3049 --- /dev/null +++ b/apps/dashboard/templates/index.php @@ -0,0 +1,4 @@ + +
diff --git a/apps/dashboard/webpack.js b/apps/dashboard/webpack.js new file mode 100644 index 0000000000..ac45549892 --- /dev/null +++ b/apps/dashboard/webpack.js @@ -0,0 +1,11 @@ +const path = require('path') + +module.exports = { + entry: path.join(__dirname, 'src', 'main.js'), + output: { + path: path.resolve(__dirname, './js'), + publicPath: '/js/', + filename: 'dashboard.js', + jsonpFunction: 'webpackJsonpDashboard' + } +} diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 54a335a738..5e80e620d7 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -166,11 +166,14 @@ return array( 'OCP\\Dashboard\\Exceptions\\DashboardAppNotAvailableException' => $baseDir . '/lib/public/Dashboard/Exceptions/DashboardAppNotAvailableException.php', 'OCP\\Dashboard\\IDashboardManager' => $baseDir . '/lib/public/Dashboard/IDashboardManager.php', 'OCP\\Dashboard\\IDashboardWidget' => $baseDir . '/lib/public/Dashboard/IDashboardWidget.php', + 'OCP\\Dashboard\\IManager' => $baseDir . '/lib/public/Dashboard/IManager.php', + 'OCP\\Dashboard\\IPanel' => $baseDir . '/lib/public/Dashboard/IPanel.php', 'OCP\\Dashboard\\Model\\IWidgetConfig' => $baseDir . '/lib/public/Dashboard/Model/IWidgetConfig.php', 'OCP\\Dashboard\\Model\\IWidgetRequest' => $baseDir . '/lib/public/Dashboard/Model/IWidgetRequest.php', 'OCP\\Dashboard\\Model\\WidgetSetting' => $baseDir . '/lib/public/Dashboard/Model/WidgetSetting.php', 'OCP\\Dashboard\\Model\\WidgetSetup' => $baseDir . '/lib/public/Dashboard/Model/WidgetSetup.php', 'OCP\\Dashboard\\Model\\WidgetTemplate' => $baseDir . '/lib/public/Dashboard/Model/WidgetTemplate.php', + 'OCP\\Dashboard\\RegisterPanelEvent' => $baseDir . '/lib/public/Dashboard/RegisterPanelEvent.php', 'OCP\\Dashboard\\Service\\IEventsService' => $baseDir . '/lib/public/Dashboard/Service/IEventsService.php', 'OCP\\Dashboard\\Service\\IWidgetsService' => $baseDir . '/lib/public/Dashboard/Service/IWidgetsService.php', 'OCP\\Defaults' => $baseDir . '/lib/public/Defaults.php', @@ -942,6 +945,7 @@ return array( 'OC\\DB\\SchemaWrapper' => $baseDir . '/lib/private/DB/SchemaWrapper.php', 'OC\\DB\\SetTransactionIsolationLevel' => $baseDir . '/lib/private/DB/SetTransactionIsolationLevel.php', 'OC\\Dashboard\\DashboardManager' => $baseDir . '/lib/private/Dashboard/DashboardManager.php', + 'OC\\Dashboard\\Manager' => $baseDir . '/lib/private/Dashboard/Manager.php', 'OC\\DatabaseException' => $baseDir . '/lib/private/DatabaseException.php', 'OC\\DatabaseSetupException' => $baseDir . '/lib/private/DatabaseSetupException.php', 'OC\\DateTimeFormatter' => $baseDir . '/lib/private/DateTimeFormatter.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 1320041cfe..4cffa4e4a6 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -195,11 +195,14 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Dashboard\\Exceptions\\DashboardAppNotAvailableException' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Exceptions/DashboardAppNotAvailableException.php', 'OCP\\Dashboard\\IDashboardManager' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IDashboardManager.php', 'OCP\\Dashboard\\IDashboardWidget' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IDashboardWidget.php', + 'OCP\\Dashboard\\IManager' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IManager.php', + 'OCP\\Dashboard\\IPanel' => __DIR__ . '/../../..' . '/lib/public/Dashboard/IPanel.php', 'OCP\\Dashboard\\Model\\IWidgetConfig' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/IWidgetConfig.php', 'OCP\\Dashboard\\Model\\IWidgetRequest' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/IWidgetRequest.php', 'OCP\\Dashboard\\Model\\WidgetSetting' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetSetting.php', 'OCP\\Dashboard\\Model\\WidgetSetup' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetSetup.php', 'OCP\\Dashboard\\Model\\WidgetTemplate' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Model/WidgetTemplate.php', + 'OCP\\Dashboard\\RegisterPanelEvent' => __DIR__ . '/../../..' . '/lib/public/Dashboard/RegisterPanelEvent.php', 'OCP\\Dashboard\\Service\\IEventsService' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Service/IEventsService.php', 'OCP\\Dashboard\\Service\\IWidgetsService' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Service/IWidgetsService.php', 'OCP\\Defaults' => __DIR__ . '/../../..' . '/lib/public/Defaults.php', @@ -971,6 +974,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\DB\\SchemaWrapper' => __DIR__ . '/../../..' . '/lib/private/DB/SchemaWrapper.php', 'OC\\DB\\SetTransactionIsolationLevel' => __DIR__ . '/../../..' . '/lib/private/DB/SetTransactionIsolationLevel.php', 'OC\\Dashboard\\DashboardManager' => __DIR__ . '/../../..' . '/lib/private/Dashboard/DashboardManager.php', + 'OC\\Dashboard\\Manager' => __DIR__ . '/../../..' . '/lib/private/Dashboard/Manager.php', 'OC\\DatabaseException' => __DIR__ . '/../../..' . '/lib/private/DatabaseException.php', 'OC\\DatabaseSetupException' => __DIR__ . '/../../..' . '/lib/private/DatabaseSetupException.php', 'OC\\DateTimeFormatter' => __DIR__ . '/../../..' . '/lib/private/DateTimeFormatter.php', diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php index 3edc0f9747..358e71d785 100644 --- a/lib/private/AppFramework/Bootstrap/Coordinator.php +++ b/lib/private/AppFramework/Bootstrap/Coordinator.php @@ -30,6 +30,7 @@ use OC_App; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\QueryException; +use OCP\Dashboard\IManager; use OCP\EventDispatcher\IEventDispatcher; use OCP\ILogger; use OCP\IServerContainer; @@ -47,6 +48,9 @@ class Coordinator { /** @var Registry */ private $registry; + /** @var IManager */ + private $dashboardManager; + /** @var IEventDispatcher */ private $eventDispatcher; @@ -58,10 +62,12 @@ class Coordinator { public function __construct(IServerContainer $container, Registry $registry, + IManager $dashboardManager, IEventDispatcher $eventListener, ILogger $logger) { $this->serverContainer = $container; $this->registry = $registry; + $this->dashboardManager = $dashboardManager; $this->eventDispatcher = $eventListener; $this->logger = $logger; } @@ -117,6 +123,7 @@ class Coordinator { */ $this->registrationContext->delegateCapabilityRegistrations($apps); $this->registrationContext->delegateCrashReporterRegistrations($apps, $this->registry); + $this->registrationContext->delegateDashboardPanelRegistrations($apps, $this->dashboardManager); $this->registrationContext->delegateEventListenerRegistrations($this->eventDispatcher); $this->registrationContext->delegateContainerRegistrations($apps); $this->registrationContext->delegateMiddlewareRegistrations($apps); diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php index 15b1cfa51e..270035a290 100644 --- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -29,6 +29,7 @@ use Closure; use OC\Support\CrashReport\Registry; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\Dashboard\IManager; use OCP\EventDispatcher\IEventDispatcher; use OCP\ILogger; use Throwable; @@ -41,6 +42,9 @@ class RegistrationContext { /** @var array[] */ private $crashReporters = []; + /** @var array[] */ + private $dashboardPanels = []; + /** @var array[] */ private $services = []; @@ -93,6 +97,13 @@ class RegistrationContext { ); } + public function registerDashboardPanel(string $panelClass): void { + $this->context->registerDashboardPanel( + $this->appId, + $panelClass + ); + } + public function registerService(string $name, callable $factory, bool $shared = true): void { $this->context->registerService( $this->appId, @@ -157,6 +168,13 @@ class RegistrationContext { ]; } + public function registerDashboardPanel(string $appId, string $panelClass): void { + $this->dashboardPanels[] = [ + 'appId' => $appId, + 'class' => $panelClass + ]; + } + public function registerService(string $appId, string $name, callable $factory, bool $shared = true): void { $this->services[] = [ "appId" => $appId, @@ -241,6 +259,23 @@ class RegistrationContext { } } + /** + * @param App[] $apps + */ + public function delegateDashboardPanelRegistrations(array $apps, IManager $dashboardManager): void { + foreach ($this->dashboardPanels as $panel) { + try { + $dashboardManager->lazyRegisterPanel($panel['class']); + } catch (Throwable $e) { + $appId = $panel['appId']; + $this->logger->logException($e, [ + 'message' => "Error during dashboard registration of $appId: " . $e->getMessage(), + 'level' => ILogger::ERROR, + ]); + } + } + } + public function delegateEventListenerRegistrations(IEventDispatcher $eventDispatcher): void { foreach ($this->eventListeners as $registration) { try { diff --git a/lib/private/Dashboard/Manager.php b/lib/private/Dashboard/Manager.php new file mode 100644 index 0000000000..0c285a8b53 --- /dev/null +++ b/lib/private/Dashboard/Manager.php @@ -0,0 +1,113 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OC\Dashboard; + +use InvalidArgumentException; +use OCP\AppFramework\QueryException; +use OCP\Dashboard\IManager; +use OCP\Dashboard\IPanel; +use OCP\ILogger; +use OCP\IServerContainer; +use Throwable; + +class Manager implements IManager { + + /** @var array */ + private $lazyPanels = []; + + /** @var IPanel[] */ + private $panels = []; + + /** @var IServerContainer */ + private $serverContainer; + + public function __construct(IServerContainer $serverContainer) { + $this->serverContainer = $serverContainer; + } + + private function registerPanel(IPanel $panel): void { + if (array_key_exists($panel->getId(), $this->panels)) { + throw new InvalidArgumentException('Dashboard panel with this id has already been registered'); + } + + $this->panels[$panel->getId()] = $panel; + } + + public function lazyRegisterPanel(string $panelClass): void { + $this->lazyPanels[] = $panelClass; + } + + public function loadLazyPanels(): void { + $classes = $this->lazyPanels; + foreach ($classes as $class) { + try { + /** @var IPanel $panel */ + $panel = $this->serverContainer->query($class); + } catch (QueryException $e) { + /* + * There is a circular dependency between the logger and the registry, so + * we can not inject it. Thus the static call. + */ + \OC::$server->getLogger()->logException($e, [ + 'message' => 'Could not load lazy dashbaord panel: ' . $e->getMessage(), + 'level' => ILogger::FATAL, + ]); + } + /** + * Try to register the loaded reporter. Theoretically it could be of a wrong + * type, so we might get a TypeError here that we should catch. + */ + try { + $this->registerPanel($panel); + } catch (Throwable $e) { + /* + * There is a circular dependency between the logger and the registry, so + * we can not inject it. Thus the static call. + */ + \OC::$server->getLogger()->logException($e, [ + 'message' => 'Could not register lazy dashboard panel: ' . $e->getMessage(), + 'level' => ILogger::FATAL, + ]); + } + + try { + $panel->load(); + } catch (Throwable $e) { + \OC::$server->getLogger()->logException($e, [ + 'message' => 'Error during dashboard panel loading: ' . $e->getMessage(), + 'level' => ILogger::FATAL, + ]); + } + } + $this->lazyPanels = []; + } + + public function getPanels(): array { + $this->loadLazyPanels(); + return $this->panels; + } +} diff --git a/lib/private/Server.php b/lib/private/Server.php index eff190176b..582718cd7c 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1357,6 +1357,7 @@ class Server extends ServerContainer implements IServerContainer { }); $this->registerAlias(IDashboardManager::class, DashboardManager::class); + $this->registerAlias(\OCP\Dashboard\IManager::class, \OC\Dashboard\Manager::class); $this->registerAlias(IFullTextSearchManager::class, FullTextSearchManager::class); $this->registerAlias(ISubAdmin::class, SubAdmin::class); diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index 12367e5ed0..8ce140996b 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -55,6 +55,15 @@ interface IRegistrationContext { */ public function registerCrashReporter(string $reporterClass): void; + /** + * Register an implementation of \OCP\Dashboard\IPanel that + * will handle the implementation of a dashboard panel + * + * @param string $panelClass + * @return void + * @since 20.0.0 + */ + public function registerDashboardPanel(string $panelClass): void; /** * Register a service * diff --git a/lib/public/Dashboard/IDashboardManager.php b/lib/public/Dashboard/IDashboardManager.php index 812338bfb3..164a86cd8b 100644 --- a/lib/public/Dashboard/IDashboardManager.php +++ b/lib/public/Dashboard/IDashboardManager.php @@ -38,6 +38,7 @@ use OCP\Dashboard\Service\IWidgetsService; * The call can be done from any Service. * * @since 15.0.0 + * @deprecated 20.0.0 * * @package OCP\Dashboard */ @@ -48,6 +49,7 @@ interface IDashboardManager { * Register a IWidgetsService. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param IWidgetsService $widgetsService */ @@ -58,6 +60,7 @@ interface IDashboardManager { * Register a IEventsService. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param IEventsService $eventsService */ @@ -70,6 +73,7 @@ interface IDashboardManager { * @see IWidgetConfig * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $widgetId * @param string $userId @@ -92,6 +96,7 @@ interface IDashboardManager { * that are running dashboard. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $widgetId * @param array $users @@ -106,6 +111,7 @@ interface IDashboardManager { * Create push notifications for groups. (ie. createUsersEvent()) * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $widgetId * @param array $groups @@ -120,6 +126,7 @@ interface IDashboardManager { * Create push notifications for everyone. (ie. createUsersEvent()) * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $widgetId * @param array $payload diff --git a/lib/public/Dashboard/IDashboardWidget.php b/lib/public/Dashboard/IDashboardWidget.php index ef8b9c74d1..4d1b0c1147 100644 --- a/lib/public/Dashboard/IDashboardWidget.php +++ b/lib/public/Dashboard/IDashboardWidget.php @@ -45,6 +45,7 @@ use OCP\Dashboard\Model\WidgetTemplate; * Multiple widget can be defined in the same appinfo/info.xml. * * @since 15.0.0 + * @deprecated 20.0.0 * * @package OCP\Dashboard */ @@ -54,6 +55,7 @@ interface IDashboardWidget { * Should returns the (unique) Id of the widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -64,6 +66,7 @@ interface IDashboardWidget { * Should returns the [display] name of the widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -75,6 +78,7 @@ interface IDashboardWidget { * This description is displayed in the listing of the available widgets. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -88,6 +92,7 @@ interface IDashboardWidget { * @see WidgetTemplate * * @since 15.0.0 + * @deprecated 20.0.0 * * @return WidgetTemplate */ @@ -101,6 +106,7 @@ interface IDashboardWidget { * @see WidgetSetup * * @since 15.0.0 + * @deprecated 20.0.0 * * @return WidgetSetup */ @@ -119,6 +125,7 @@ interface IDashboardWidget { * @see IWidgetConfig * * @since 15.0.0 + * @deprecated 20.0.0 * * @param IWidgetConfig $settings */ @@ -134,6 +141,7 @@ interface IDashboardWidget { * @see IWidgetRequest * * @since 15.0.0 + * @deprecated 20.0.0 * * @param IWidgetRequest $request */ diff --git a/lib/public/Dashboard/IManager.php b/lib/public/Dashboard/IManager.php new file mode 100644 index 0000000000..985c8c7838 --- /dev/null +++ b/lib/public/Dashboard/IManager.php @@ -0,0 +1,49 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCP\Dashboard; + +/** + * Interface IManager + * + * @package OCP\Dashboard + * @since 20.0.0 + */ +interface IManager { + + /** + * @param string $panelClass + * @since 20.0.0 + */ + public function lazyRegisterPanel(string $panelClass): void; + + /** + * @since 20.0.0 + * + * @return IPanel[] + */ + public function getPanels(): array; +} diff --git a/lib/public/Dashboard/IPanel.php b/lib/public/Dashboard/IPanel.php new file mode 100644 index 0000000000..59d88f7a7e --- /dev/null +++ b/lib/public/Dashboard/IPanel.php @@ -0,0 +1,72 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCP\Dashboard; + +/** + * Interface IPanel + * + * @package OCP\Dashboard + * @since 20.0.0 + */ +interface IPanel { + + /** + * @return string Unique id that identifies the panel, e.g. the app id + * @since 20.0.0 + */ + public function getId(): string; + + /** + * @return string User facing title of the panel + * @since 20.0.0 + */ + public function getTitle(): string; + + /** + * @return int Initial order for panel sorting + * @since 20.0.0 + */ + public function getOrder(): int; + + /** + * @return string css class that displays an icon next to the panel title + * @since 20.0.0 + */ + public function getIconClass(): string; + + /** + * @return string|null The absolute url to the apps own view + * @since 20.0.0 + */ + public function getUrl(): ?string; + + /** + * Execute panel bootstrap code like loading scripts and providing initial state + * @since 20.0.0 + */ + public function load(): void; +} diff --git a/lib/public/Dashboard/Model/IWidgetConfig.php b/lib/public/Dashboard/Model/IWidgetConfig.php index 41c9e23317..078c14c742 100644 --- a/lib/public/Dashboard/Model/IWidgetConfig.php +++ b/lib/public/Dashboard/Model/IWidgetConfig.php @@ -36,6 +36,7 @@ use OCP\Dashboard\IDashboardWidget; * @see IDashboardWidget::loadWidget * * @since 15.0.0 + * @deprecated 20.0.0 * * @package OCP\Dashboard\Model */ @@ -46,6 +47,7 @@ interface IWidgetConfig { * Returns the userId * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -56,6 +58,7 @@ interface IWidgetConfig { * Returns the widgetId * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -75,6 +78,7 @@ interface IWidgetConfig { * ] * * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ @@ -105,6 +109,7 @@ interface IWidgetConfig { * Dashboard app. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ @@ -115,6 +120,7 @@ interface IWidgetConfig { * Returns if the widget is enabled/displayed in this user's dashboard. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return bool */ diff --git a/lib/public/Dashboard/Model/IWidgetRequest.php b/lib/public/Dashboard/Model/IWidgetRequest.php index 18ad855006..5f1f2e396c 100644 --- a/lib/public/Dashboard/Model/IWidgetRequest.php +++ b/lib/public/Dashboard/Model/IWidgetRequest.php @@ -38,6 +38,7 @@ use OCP\Dashboard\IDashboardWidget; * @see IDashboardWidget::requestWidget * * @since 15.0.0 + * @deprecated 20.0.0 * * @package OCP\Dashboard\Model */ @@ -47,6 +48,7 @@ interface IWidgetRequest { * Get the widgetId. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -57,6 +59,7 @@ interface IWidgetRequest { * Get the WidgetClass. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return IDashboardWidget */ @@ -76,6 +79,7 @@ interface IWidgetRequest { * callback); * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -88,6 +92,7 @@ interface IWidgetRequest { * @see getRequest * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -98,6 +103,7 @@ interface IWidgetRequest { * Returns the result. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ @@ -108,6 +114,7 @@ interface IWidgetRequest { * add a result (as string) * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $key * @param string $result @@ -120,6 +127,7 @@ interface IWidgetRequest { * add a result (as array) * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $key * @param array $result diff --git a/lib/public/Dashboard/Model/WidgetSetting.php b/lib/public/Dashboard/Model/WidgetSetting.php index 6242960760..406811e1f8 100644 --- a/lib/public/Dashboard/Model/WidgetSetting.php +++ b/lib/public/Dashboard/Model/WidgetSetting.php @@ -45,6 +45,7 @@ use JsonSerializable; * @see WidgetTemplate::addSetting * * @since 15.0.0 + * @deprecated 20.0.0 * * @package OCP\Dashboard\Model */ @@ -73,6 +74,7 @@ final class WidgetSetting implements JsonSerializable { * WidgetSetting constructor. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $type */ @@ -85,6 +87,7 @@ final class WidgetSetting implements JsonSerializable { * Set the name of the setting (full string, no space) * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $name * @@ -100,6 +103,7 @@ final class WidgetSetting implements JsonSerializable { * Get the name of the setting * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -112,6 +116,7 @@ final class WidgetSetting implements JsonSerializable { * Set the title/display name of the setting. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $title * @@ -127,6 +132,7 @@ final class WidgetSetting implements JsonSerializable { * Get the title of the setting * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -139,6 +145,7 @@ final class WidgetSetting implements JsonSerializable { * Set the type of the setting (input, checkbox, ...) * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $type * @@ -154,6 +161,7 @@ final class WidgetSetting implements JsonSerializable { * Get the type of the setting. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -166,6 +174,7 @@ final class WidgetSetting implements JsonSerializable { * Set the placeholder (in case of type=input) * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $text * @@ -181,6 +190,7 @@ final class WidgetSetting implements JsonSerializable { * Get the placeholder. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -193,6 +203,7 @@ final class WidgetSetting implements JsonSerializable { * Set the default value of the setting. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $value * @@ -208,6 +219,7 @@ final class WidgetSetting implements JsonSerializable { * Get the default value. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -218,6 +230,7 @@ final class WidgetSetting implements JsonSerializable { /** * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ diff --git a/lib/public/Dashboard/Model/WidgetSetup.php b/lib/public/Dashboard/Model/WidgetSetup.php index 18dc0abd48..2a1fc87741 100644 --- a/lib/public/Dashboard/Model/WidgetSetup.php +++ b/lib/public/Dashboard/Model/WidgetSetup.php @@ -38,6 +38,7 @@ use JsonSerializable; * @see IDashboardWidget::getWidgetSetup * * @since 15.0.0 + * @deprecated 20.0.0 * * @package OCP\Dashboard\Model */ @@ -73,6 +74,7 @@ final class WidgetSetup implements JsonSerializable { * * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $type * @@ -90,6 +92,7 @@ final class WidgetSetup implements JsonSerializable { * Returns all sizes defined for the widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ @@ -101,6 +104,7 @@ final class WidgetSetup implements JsonSerializable { * Add a new size to the setup. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $type * @param int $width @@ -121,6 +125,7 @@ final class WidgetSetup implements JsonSerializable { * Returns menu entries. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ @@ -136,6 +141,7 @@ final class WidgetSetup implements JsonSerializable { * $text is the display name of the menu entry. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $function * @param string $icon @@ -161,6 +167,7 @@ final class WidgetSetup implements JsonSerializable { * $delay is the time in seconds between each call. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $function * @param int $delay @@ -180,6 +187,7 @@ final class WidgetSetup implements JsonSerializable { * Get delayed jobs. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ @@ -192,6 +200,7 @@ final class WidgetSetup implements JsonSerializable { * Get the push function, called when an event is send to the front-end * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -204,6 +213,7 @@ final class WidgetSetup implements JsonSerializable { * frontend. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $function * @@ -220,6 +230,7 @@ final class WidgetSetup implements JsonSerializable { * Returns the default settings for a widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ @@ -235,6 +246,7 @@ final class WidgetSetup implements JsonSerializable { * @see WidgetSetting * * @since 15.0.0 + * @deprecated 20.0.0 * * @param array $settings * @@ -249,6 +261,7 @@ final class WidgetSetup implements JsonSerializable { /** * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ diff --git a/lib/public/Dashboard/Model/WidgetTemplate.php b/lib/public/Dashboard/Model/WidgetTemplate.php index e25abb0254..10285cfb00 100644 --- a/lib/public/Dashboard/Model/WidgetTemplate.php +++ b/lib/public/Dashboard/Model/WidgetTemplate.php @@ -37,6 +37,7 @@ use JsonSerializable; * @see IDashboardWidget::getWidgetTemplate * * @since 15.0.0 + * @deprecated 20.0.0 * * @package OCP\Dashboard\Model */ @@ -66,6 +67,7 @@ final class WidgetTemplate implements JsonSerializable { * Get the icon class of the widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -80,6 +82,7 @@ final class WidgetTemplate implements JsonSerializable { * @see addCss * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $icon * @@ -95,6 +98,7 @@ final class WidgetTemplate implements JsonSerializable { * Get CSS files to be included when displaying a widget * * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ @@ -106,6 +110,7 @@ final class WidgetTemplate implements JsonSerializable { * path and name of CSS files * * @since 15.0.0 + * @deprecated 20.0.0 * * @param array $css * @@ -121,6 +126,7 @@ final class WidgetTemplate implements JsonSerializable { * Add a CSS file to be included when displaying a widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $css * @@ -136,6 +142,7 @@ final class WidgetTemplate implements JsonSerializable { * Get JS files to be included when loading a widget * * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ @@ -147,6 +154,7 @@ final class WidgetTemplate implements JsonSerializable { * Set an array of JS files to be included when loading a widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param array $js * @@ -162,6 +170,7 @@ final class WidgetTemplate implements JsonSerializable { * Add a JS file to be included when loading a widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $js * @@ -177,6 +186,7 @@ final class WidgetTemplate implements JsonSerializable { * Get the HTML file that contains the content of the widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -188,6 +198,7 @@ final class WidgetTemplate implements JsonSerializable { * Set the HTML file that contains the content of the widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $content * @@ -203,6 +214,7 @@ final class WidgetTemplate implements JsonSerializable { * Get the JS function to be called when loading the widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @return string */ @@ -215,6 +227,7 @@ final class WidgetTemplate implements JsonSerializable { * dashboard * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $function * @@ -232,6 +245,7 @@ final class WidgetTemplate implements JsonSerializable { * @see WidgetSetting * * @since 15.0.0 + * @deprecated 20.0.0 * * @return WidgetSetting[] */ @@ -243,6 +257,7 @@ final class WidgetTemplate implements JsonSerializable { * Define all WidgetSetting for the widget. * * @since 15.0.0 + * @deprecated 20.0.0 * * @see WidgetSetting * @@ -262,6 +277,7 @@ final class WidgetTemplate implements JsonSerializable { * @see WidgetSetting * * @since 15.0.0 + * @deprecated 20.0.0 * * @param WidgetSetting $setting * @@ -279,6 +295,7 @@ final class WidgetTemplate implements JsonSerializable { * @see WidgetSetting::setName * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $key * @@ -295,6 +312,7 @@ final class WidgetTemplate implements JsonSerializable { /** * @since 15.0.0 + * @deprecated 20.0.0 * * @return array */ diff --git a/lib/public/Dashboard/RegisterPanelEvent.php b/lib/public/Dashboard/RegisterPanelEvent.php new file mode 100644 index 0000000000..2bd157127f --- /dev/null +++ b/lib/public/Dashboard/RegisterPanelEvent.php @@ -0,0 +1,59 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCP\Dashboard; + +use OCP\EventDispatcher\Event; + +/** + * Class RegisterPanelEvent + * + * This event is dispatched to allow apps supporting older Nextcloud versions to + * still register their dashboard panels so that they are only constructed when + * they are needed. Deprecated right away so we can drop it again after 19 is EOL + * and backward compatible apps can use OCP\AppFramework\Bootstrap\IBootstrap + * + * @package OCP\Dashboard + * @since 20.0.0 + * @deprecated 20.0.0 + */ +class RegisterPanelEvent extends Event { + private $manager; + + public function __construct(IManager $manager) { + parent::__construct(); + + $this->manager = $manager; + } + + /** + * @param string $panelClass + * @since 20.0.0 + */ + public function registerPanel(string $panelClass) { + $this->manager->lazyRegisterPanel($panelClass); + } +} diff --git a/lib/public/Dashboard/Service/IEventsService.php b/lib/public/Dashboard/Service/IEventsService.php index f79d1a28e5..0e5931878e 100644 --- a/lib/public/Dashboard/Service/IEventsService.php +++ b/lib/public/Dashboard/Service/IEventsService.php @@ -35,6 +35,7 @@ use OCP\Dashboard\IDashboardManager; * are used by the IDashboardManager when creating push event. * * @since 15.0.0 + * @deprecated 20.0.0 * * @package OCP\Dashboard\Service */ @@ -47,6 +48,7 @@ interface IEventsService { * @see IDashboardManager::createUsersEvent * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $widgetId * @param array $users @@ -62,6 +64,7 @@ interface IEventsService { * @see IDashboardManager::createGroupsEvent * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $widgetId * @param array $groups @@ -77,6 +80,7 @@ interface IEventsService { * @see IDashboardManager::createGlobalEvent * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $widgetId * @param array $payload diff --git a/lib/public/Dashboard/Service/IWidgetsService.php b/lib/public/Dashboard/Service/IWidgetsService.php index dea20489e1..059d91a666 100644 --- a/lib/public/Dashboard/Service/IWidgetsService.php +++ b/lib/public/Dashboard/Service/IWidgetsService.php @@ -36,6 +36,7 @@ use OCP\Dashboard\Model\IWidgetConfig; * configuration of a widget for a user. * * @since 15.0.0 + * @deprecated 20.0.0 * * @package OCP\Dashboard\Service */ @@ -45,6 +46,7 @@ interface IWidgetsService { * Returns the IWidgetConfig for a widgetId and userId * * @since 15.0.0 + * @deprecated 20.0.0 * * @param string $widgetId * @param string $userId diff --git a/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php b/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php index c12e5eeb15..1fca34423d 100644 --- a/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php +++ b/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php @@ -33,6 +33,7 @@ use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\QueryException; +use OCP\Dashboard\IManager; use OCP\EventDispatcher\IEventDispatcher; use OCP\ILogger; use OCP\IServerContainer; @@ -50,6 +51,9 @@ class CoordinatorTest extends TestCase { /** @var Registry|MockObject */ private $crashReporterRegistry; + /** @var IManager|MockObject */ + private $dashboardManager; + /** @var IEventDispatcher|MockObject */ private $eventDispatcher; @@ -65,12 +69,14 @@ class CoordinatorTest extends TestCase { $this->appManager = $this->createMock(IAppManager::class); $this->serverContainer = $this->createMock(IServerContainer::class); $this->crashReporterRegistry = $this->createMock(Registry::class); + $this->dashboardManager = $this->createMock(IManager::class); $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->logger = $this->createMock(ILogger::class); $this->coordinator = new Coordinator( $this->serverContainer, $this->crashReporterRegistry, + $this->dashboardManager, $this->eventDispatcher, $this->logger ); diff --git a/webpack.common.js b/webpack.common.js index ee8db43e72..249647c314 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -6,6 +6,7 @@ const { VueLoaderPlugin } = require('vue-loader') const accessibility = require('./apps/accessibility/webpack') const comments = require('./apps/comments/webpack') const core = require('./core/webpack') +const dashboard = require('./apps/dashboard/webpack') const files = require('./apps/files/webpack') const files_sharing = require('./apps/files_sharing/webpack') const files_trashbin = require('./apps/files_trashbin/webpack') @@ -21,6 +22,7 @@ const modules = { accessibility, comments, core, + dashboard, files, files_sharing, files_trashbin,