diff --git a/css/collections.css b/css/collections.css new file mode 100644 index 000000000..333101086 --- /dev/null +++ b/css/collections.css @@ -0,0 +1,10 @@ +.icon-deck { + background-image: url('../img/deck-dark.svg'); +} + +.resource-type-deck img { + opacity: 0.4 !important; +} +.resource-type-deck:hover img { + opacity: 0.7 !important; +} diff --git a/js/controller/BoardController.js b/js/controller/BoardController.js index 41729c8aa..dd0dab315 100644 --- a/js/controller/BoardController.js +++ b/js/controller/BoardController.js @@ -21,8 +21,11 @@ */ import app from '../app/App.js'; +import Vue from 'vue'; +import CollaborationView from '../views/CollaborationView'; + /* global oc_defaults OC OCP OCA */ -app.controller('BoardController', function ($rootScope, $scope, $stateParams, StatusService, BoardService, StackService, CardService, LabelService, $state, $transitions, $filter, FileService) { +app.controller('BoardController', function ($rootScope, $scope, $element, $stateParams, StatusService, BoardService, StackService, CardService, LabelService, $state, $transitions, $filter, FileService) { $scope.sidebar = $rootScope.sidebar; @@ -148,6 +151,31 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St } }); + const ComponentVM = new Vue({ + render: h => h(CollaborationView), + data: { + model: BoardService.getCurrent() + }, + }); + $scope.mountCollections = () => { + console.log('mountCollections'); + const MountingPoint = document.getElementById('collaborationResources'); + if (MountingPoint) { + console.log(MountingPoint); + ComponentVM.model = BoardService.getCurrent(); + ComponentVM.$mount(MountingPoint); + } + }; + $scope.$$postDigest($scope.mountCollections); + $scope.$watch(function () { + return BoardService.getCurrent(); + }, function() { + ComponentVM.model = BoardService.getCurrent(); + if ($scope.sidebar.show) { + $scope.$$postDigest($scope.mountCollections); + } + }); + $scope.toggleCompactMode = function() { $rootScope.compactMode = !$rootScope.compactMode; localStorage.setItem('deck.compactMode', JSON.stringify($rootScope.compactMode)); diff --git a/js/init-collections.js b/js/init-collections.js new file mode 100644 index 000000000..75209e499 --- /dev/null +++ b/js/init-collections.js @@ -0,0 +1,67 @@ +/* + * @copyright Copyright (c) 2019 Julius Härtl + * + * @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 . + * + */ + +'use strict'; + +/* global __webpack_nonce__ OC */ +__webpack_nonce__ = btoa(OC.requestToken); // eslint-disable-line no-native-reassign +__webpack_public_path__ = OC.linkTo('deck', 'js/build/'); + +import Vue from 'vue'; +import BoardSelector from './views/BoardSelector'; + +import './../css/collections.css'; + +(function(OCP) { + + Vue.prototype.$ = $ + Vue.prototype.t = t + Vue.prototype.n = n + Vue.prototype.OC = OC + + OCP.Collaboration.registerType('deck', { + action: () => { + return new Promise((resolve, reject) => { + const container = document.createElement('div'); + container.id = 'deck-board-select'; + const body = document.getElementById('body-user'); + body.append(container); + const ComponentVM = new Vue({ + render: h => h(BoardSelector), + }); + ComponentVM.$mount(container); + ComponentVM.$root.$on('close', () => { + ComponentVM.$el.remove(); + ComponentVM.$destroy(); + reject(); + }); + ComponentVM.$root.$on('select', (id) => { + resolve(id); + ComponentVM.$el.remove(); + ComponentVM.$destroy(); + }); + }); + }, + typeString: t('deck', 'board'), + typeIconClass: 'icon-deck' + }); +})(window.OCP); diff --git a/js/init.js b/js/init.js index 06c78f373..8f1fc9d94 100644 --- a/js/init.js +++ b/js/init.js @@ -2,6 +2,7 @@ /* global __webpack_nonce__ OC */ __webpack_nonce__ = btoa(OC.requestToken); // eslint-disable-line no-native-reassign +__webpack_public_path__ = OC.linkTo('deck', 'js/build/'); // used for building a vendor stylesheet import 'ng-sortable/dist/ng-sortable.css'; diff --git a/js/package-lock.json b/js/package-lock.json index 09791e2e1..0078d2320 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -682,6 +682,15 @@ "@babel/helper-plugin-utils": "^7.0.0" } }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", + "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, "@babel/plugin-syntax-json-strings": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", @@ -1171,6 +1180,73 @@ "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-5.0.23.tgz", "integrity": "sha512-rwFOH++z/KY8y+h0IOpQ5uC8Nim6E0EBCQrIjhVCr+XKYXgpK+VdtuOLFdogvbJ3AAi5Z7ei00qdEr7Did5CAg==" }, + "@vue/component-compiler-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz", + "integrity": "sha512-IHjxt7LsOFYc0DkTncB7OXJL7UzwOLPPQCfEUNyxL2qt+tF12THV+EO33O1G2Uk4feMSWua3iD39Itszx0f0bw==", + "dev": true, + "requires": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.14", + "postcss-selector-parser": "^5.0.0", + "prettier": "1.16.3", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", + "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -1575,6 +1651,15 @@ "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", "dev": true }, + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, "babel-loader": { "version": "8.0.5", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz", @@ -2045,8 +2130,24 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, "chokidar": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", @@ -2239,6 +2340,15 @@ "date-now": "^0.1.4" } }, + "consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "dev": true, + "requires": { + "bluebird": "^3.1.1" + } + }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", @@ -2379,6 +2489,11 @@ "which": "^1.2.9" } }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -2423,12 +2538,6 @@ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, - "camelcase": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", - "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", - "dev": true - }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -2493,6 +2602,12 @@ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", "dev": true }, + "de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3051,6 +3166,11 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" + }, "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", @@ -3166,7 +3286,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", - "dev": true, "requires": { "debug": "^3.2.6" }, @@ -3175,7 +3294,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -3183,8 +3301,7 @@ "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } } }, @@ -3243,9 +3360,9 @@ "dev": true }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", + "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", "dev": true, "optional": true, "requires": { @@ -3272,7 +3389,7 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, @@ -3298,7 +3415,7 @@ } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -3337,7 +3454,7 @@ } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -3386,7 +3503,7 @@ } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, @@ -3406,12 +3523,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -3476,17 +3593,17 @@ "optional": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, "optional": true, "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, @@ -3510,7 +3627,7 @@ "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.2.4", "bundled": true, "dev": true, "optional": true, @@ -3521,18 +3638,18 @@ } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.10.3", "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", - "needle": "^2.2.0", + "needle": "^2.2.1", "nopt": "^4.0.1", "npm-packlist": "^1.1.6", "npmlog": "^4.0.2", - "rc": "^1.1.7", + "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", "tar": "^4" @@ -3549,13 +3666,13 @@ } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.5", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.2.0", "bundled": true, "dev": true, "optional": true, @@ -3632,12 +3749,12 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -3667,16 +3784,16 @@ } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, "dev": true, "optional": true @@ -3694,7 +3811,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.6.0", "bundled": true, "dev": true, "optional": true @@ -3747,17 +3864,17 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.2" } }, @@ -3768,12 +3885,12 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { @@ -3783,7 +3900,7 @@ "optional": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true, "optional": true @@ -3888,6 +4005,11 @@ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, + "hammerjs": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", + "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -4002,6 +4124,12 @@ "safe-buffer": "^5.0.1" } }, + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", + "dev": true + }, "hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -4012,6 +4140,12 @@ "minimalistic-assert": "^1.0.1" } }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -4189,8 +4323,7 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-callable": { "version": "1.1.4", @@ -4512,6 +4645,11 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==" + }, "log4js": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.0.2.tgz", @@ -4617,6 +4755,16 @@ "resolved": "https://registry.npmjs.org/markdown-it-link-target/-/markdown-it-link-target-1.0.2.tgz", "integrity": "sha1-0v1FV181FI6cXiNet4ertvlGCmc=" }, + "md5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", + "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", + "requires": { + "charenc": "~0.0.1", + "crypt": "~0.0.1", + "is-buffer": "~1.1.1" + } + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -4660,6 +4808,23 @@ "readable-stream": "^2.0.1" } }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -4904,6 +5069,60 @@ "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", "dev": true }, + "nextcloud-axios": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/nextcloud-axios/-/nextcloud-axios-0.1.3.tgz", + "integrity": "sha512-M2eLX0qrP8xy1VEGDhPXGwvV4W4gMnU1ysjnURVen8ehR1qRLdb/JfhJHab6XRsme7vWWMgSTEj+o3ibQ94N6g==", + "requires": { + "axios": "^0.18.0" + } + }, + "nextcloud-vue": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/nextcloud-vue/-/nextcloud-vue-0.8.0.tgz", + "integrity": "sha512-6qXcWTgtrbM4W1AjyHSWn0cHOFm/Q39A//OibrY7M332orQnDvCrDoGloUUOW6+vbXJarI+L7t7scL6mkRw4Qg==", + "requires": { + "hammerjs": "^2.0.8", + "md5": "^2.2.1", + "nextcloud-axios": "^0.1.3", + "v-tooltip": "^2.0.0-rc.33", + "vue": "^2.6.7", + "vue-click-outside": "^1.0.7", + "vue-multiselect": "^2.1.3", + "vue2-datepicker": "^2.10.0" + } + }, + "nextcloud-vue-collections": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nextcloud-vue-collections/-/nextcloud-vue-collections-0.2.0.tgz", + "integrity": "sha512-LDbJyUZffu8ZIkkXAMXkfqkUK36GaUiuS4IdgoOLe/z9prV/Iic7uwrDME015FsCv9GmfheOs7cfiU6xBIidGA==", + "requires": { + "nextcloud-axios": "^0.1.2", + "nextcloud-vue": "^0.9.0", + "v-tooltip": "^2.0.0-rc.33", + "vue": "^2.6.6", + "vue-click-outside": "^1.0.7", + "vuex": "^3.1.0" + }, + "dependencies": { + "nextcloud-vue": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/nextcloud-vue/-/nextcloud-vue-0.9.2.tgz", + "integrity": "sha512-gw0A+qIEHP+P+iRhb+btSXuS3mkEgTyVr1aaJf8CvNXMlfxJMYMo25jQ+lHc9uRbl9MdGzl3U8gY84kTQffPjw==", + "requires": { + "hammerjs": "^2.0.8", + "md5": "^2.2.1", + "nextcloud-axios": "^0.1.3", + "v-tooltip": "^2.0.0-rc.33", + "vue": "^2.6.7", + "vue-click-outside": "^1.0.7", + "vue-multiselect": "^2.1.3", + "vue-visible": "^1.0.2", + "vue2-datepicker": "^2.10.0" + } + } + } + }, "ng-infinite-scroll": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ng-infinite-scroll/-/ng-infinite-scroll-1.3.0.tgz", @@ -5127,7 +5346,7 @@ }, "p-is-promise": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", "dev": true }, @@ -5286,6 +5505,11 @@ "find-up": "^3.0.0" } }, + "popper.js": { + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.7.tgz", + "integrity": "sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ==" + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -5303,42 +5527,11 @@ "supports-color": "^6.1.0" }, "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -5360,6 +5553,19 @@ "postcss": "^7.0.6", "postcss-selector-parser": "^6.0.0", "postcss-value-parser": "^3.3.1" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } } }, "postcss-modules-scope": { @@ -5370,6 +5576,19 @@ "requires": { "postcss": "^7.0.6", "postcss-selector-parser": "^6.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } } }, "postcss-modules-values": { @@ -5383,14 +5602,22 @@ } }, "postcss-selector-parser": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", - "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", "dev": true, "requires": { - "cssesc": "^3.0.0", + "cssesc": "^2.0.0", "indexes-of": "^1.0.1", "uniq": "^1.0.1" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + } } }, "postcss-value-parser": { @@ -5399,6 +5626,12 @@ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true }, + "prettier": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz", + "integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==", + "dev": true + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -6298,10 +6531,20 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "style-loader": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", + "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + } + }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -6728,6 +6971,17 @@ } } }, + "url-loader": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", + "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" + } + }, "use": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", @@ -6786,6 +7040,21 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true }, + "v-click-outside": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/v-click-outside/-/v-click-outside-2.0.2.tgz", + "integrity": "sha512-4dDekJloLi7WbVUM6IC/Gdv8qYaE+a2LY3sLUkzJc2WBf92kL0VPHGCTxVkTzZjHLVdkcjX0haiLXofrhZfHXA==" + }, + "v-tooltip": { + "version": "2.0.0-rc.33", + "resolved": "https://registry.npmjs.org/v-tooltip/-/v-tooltip-2.0.0-rc.33.tgz", + "integrity": "sha1-ePfY6cNCZWIr5lup3HjGfx3AK3M=", + "requires": { + "lodash.merge": "^4.6.0", + "popper.js": "^1.12.9", + "vue-resize": "^0.4.3" + } + }, "v8-compile-cache": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz", @@ -6807,6 +7076,89 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, + "vue": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.8.tgz", + "integrity": "sha512-+vp9lEC2Kt3yom673pzg1J7T1NVGuGzO9j8Wxno+rQN2WYVBX2pyo/RGQ3fXCLh2Pk76Skw/laAPCuBuEQ4diw==" + }, + "vue-click-outside": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/vue-click-outside/-/vue-click-outside-1.0.7.tgz", + "integrity": "sha1-zdKxYF48SUR4TheU6uShKg9wC9Y=" + }, + "vue-hot-reload-api": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.3.tgz", + "integrity": "sha512-KmvZVtmM26BQOMK1rwUZsrqxEGeKiYSZGA7SNWE6uExx8UX/cj9hq2MRV/wWC3Cq6AoeDGk57rL9YMFRel/q+g==", + "dev": true + }, + "vue-loader": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.7.0.tgz", + "integrity": "sha512-x+NZ4RIthQOxcFclEcs8sXGEWqnZHodL2J9Vq+hUz+TDZzBaDIh1j3d9M2IUlTjtrHTZy4uMuRdTi8BGws7jLA==", + "dev": true, + "requires": { + "@vue/component-compiler-utils": "^2.5.1", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + } + }, + "vue-multiselect": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.4.tgz", + "integrity": "sha512-ryd2Ybl56LE81IxlwbZUo4gAWnUSG45iUGX4KgVwsteitK2R+cOLwJaJescobpIDJnVlVorRUnX5u7my1vBu2w==" + }, + "vue-resize": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.4.5.tgz", + "integrity": "sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg==" + }, + "vue-style-loader": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz", + "integrity": "sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ==", + "dev": true, + "requires": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + } + }, + "vue-template-compiler": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.8.tgz", + "integrity": "sha512-SwWKANE5ee+oJg+dEJmsdxsxWYICPsNwk68+1AFjOS8l0O/Yz2845afuJtFqf3UjS/vXG7ECsPeHHEAD65Cjng==", + "dev": true, + "requires": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, + "vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", + "dev": true + }, + "vue-visible": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vue-visible/-/vue-visible-1.0.2.tgz", + "integrity": "sha512-yaX2its9XAJKGuQqf7LsiZHHSkxsIK8rmCOQOvEGEoF41blKRK8qr9my4qYoD6ikdLss4n8tKqYBecmaY0+WJg==" + }, + "vue2-datepicker": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/vue2-datepicker/-/vue2-datepicker-2.10.0.tgz", + "integrity": "sha512-WGL7ou0TdBiJQuHVp29BtBw3rSkLrIYwXWU/ELmaLdnAerI0EdGVAu7DvZV2iIxY4lsHyjqocApxdvXTmwLrAw==", + "requires": { + "fecha": "^2.3.3" + } + }, + "vuex": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.1.0.tgz", + "integrity": "sha512-mdHeHT/7u4BncpUZMlxNaIdcN/HIt1GsGG5LKByArvYG/v6DvHcOxvDCts+7SRdCoIRGllK8IMZvQtQXLppDYg==" + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", @@ -6891,6 +7243,17 @@ "supports-color": "^5.5.0", "v8-compile-cache": "^2.0.2", "yargs": "^12.0.5" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "webpack-merge": { diff --git a/js/package.json b/js/package.json index 04c88708e..0792f21e7 100644 --- a/js/package.json +++ b/js/package.json @@ -3,7 +3,6 @@ "description": "Frontend for the Nextcloud Deck app", "repository": "https://github.com/nextcloud/deck", "version": "1.0.0", - "main": "Gruntfile.js", "directories": { "test": "tests" }, @@ -17,25 +16,37 @@ "babel-polyfill": "^6.26.0", "markdown-it": "^8.4.2", "markdown-it-link-target": "^1.0.2", + "nextcloud-axios": "^0.1.3", + "nextcloud-vue": "^0.8.0", + "nextcloud-vue-collections": "^0.2.0", "ng-infinite-scroll": "^1.3.0", "ng-sortable": "^1.3.8", - "ui-select": "^0.19.8" + "ui-select": "^0.19.8", + "v-click-outside": "^2.0.2", + "vue": "^2.6.8", + "vuex": "^3.1.0" }, "devDependencies": { "@babel/core": "^7.4.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/polyfill": "^7.4.0", "@babel/preset-env": "^7.4.2", "babel-loader": "^8.0.5", "css-loader": "^2.1.1", "karma": "^4.0.1", "mini-css-extract-plugin": "^0.5.0", + "style-loader": "^0.23.1", "uglifyjs-webpack-plugin": "^2.1.2", + "url-loader": "^1.1.2", + "vue-loader": "^15.7.0", + "vue-style-loader": "^4.1.2", + "vue-template-compiler": "^2.6.8", "webpack": "^4.29.6", "webpack-cli": "^3.3.0", "webpack-merge": "^4.2.1" }, "scripts": { - "build": "./node_modules/webpack-cli/bin/cli.js --mode production --config webpack.prod.config.js", + "build": "NODE_ENV=production ./node_modules/webpack-cli/bin/cli.js --mode production --config webpack.prod.config.js", "dev": "./node_modules/webpack-cli/bin/cli.js --mode development --config webpack.dev.config.js", "watch": "./node_modules/webpack-cli/bin/cli.js --mode development --config webpack.dev.config.js --watch", "test": "echo \"Warning: no test specified\" && exit 0" diff --git a/js/views/BoardSelector.vue b/js/views/BoardSelector.vue new file mode 100644 index 000000000..d9f038f80 --- /dev/null +++ b/js/views/BoardSelector.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/js/views/CollaborationView.vue b/js/views/CollaborationView.vue new file mode 100644 index 000000000..e1e66c75f --- /dev/null +++ b/js/views/CollaborationView.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/js/webpack.config.js b/js/webpack.config.js index 8961df4ec..d667cfe89 100644 --- a/js/webpack.config.js +++ b/js/webpack.config.js @@ -1,66 +1,76 @@ const path = require('path'); const webpack = require('webpack'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const { VueLoaderPlugin } = require('vue-loader'); module.exports = { - node: { - fs: 'empty', - }, - entry: { - deck: ['./init.js'], - }, - output: { - filename: '[name].js', - path: __dirname + '/build' - }, - resolve: { - modules: [path.resolve(__dirname), 'node_modules'], - }, - module: { - rules: [ - { - test: /\.js$/, - exclude: /node_modules/, - loader: 'babel-loader', - query: { - presets: ['@babel/preset-env'], - } - }, - { - test: /\.css$/, - use: [ - MiniCssExtractPlugin.loader, - 'css-loader' - ] - } - ] - }, - optimization: { - splitChunks: { - cacheGroups: { - /* separate vendor chunk for node_modules and legacy scripts */ - commons: { - test: /[\\/]node_modules[\\/]/, - name: 'vendor', - chunks: 'all' - }, - legacy: { - test: /[\\/]legacy[\\/]/, - name: 'vendor', - chunks: 'all' - } - } - } - }, - /* use external jQuery from server */ - externals: { - 'jquery': 'jQuery' - }, - plugins: [ - new MiniCssExtractPlugin('[name].css'), - new webpack.ProvidePlugin({ - $: 'jquery', - jQuery: 'jquery' - }) - ] + node: { + fs: 'empty', + }, + entry: { + deck: ['./init.js'], + collections: ['./init-collections.js'] + }, + output: { + filename: '[name].js', + path: __dirname + '/build' + }, + module: { + rules: [ + { + test: /\.css$/, + use: ['vue-style-loader', 'style-loader', 'css-loader'] + }, + { + test: /\.vue$/, + loader: 'vue-loader' + }, + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel-loader', + query: { + presets: ['@babel/preset-env'], + plugins: ['@babel/plugin-syntax-dynamic-import'] + } + }, + { + test: /\.scss$/, + use: [ + 'vue-style-loader', + 'css-loader', + 'sass-loader' + ] + }, + { + test: /\.(png|jpg|gif|svg)$/, + loader: 'url-loader', + options: { + name: '[name].[ext]?[hash]' + } + }, + ] + }, + /* use external jQuery from server */ + externals: { + 'jquery': 'jQuery' + }, + resolve: { + alias: { + vue$: 'vue/dist/vue.esm.js' + }, + extensions: ['*', '.js', '.vue', '.json'], + modules: [ + path.resolve(__dirname), + path.join(__dirname, 'node_modules'), + 'node_modules' + ] + }, + plugins: [ + new VueLoaderPlugin(), + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery' + }) + ] }; diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index a8826e301..82b61c383 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -24,6 +24,7 @@ namespace OCA\Deck\AppInfo; use OCA\Deck\Activity\CommentEventHandler; +use OCA\Deck\Collaboration\Resources\ResourceProvider; use OCA\Deck\Db\Acl; use OCA\Deck\Db\AclMapper; use OCA\Deck\Db\AssignedUsersMapper; @@ -32,6 +33,8 @@ use OCA\Deck\Middleware\ExceptionMiddleware; use OCA\Deck\Notification\Notifier; use OCP\AppFramework\App; use OCA\Deck\Middleware\SharingMiddleware; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\Collaboration\Resources\IManager; use OCP\Comments\CommentsEntityEvent; use OCP\IGroup; use OCP\IUser; @@ -100,6 +103,8 @@ class Application extends App { } }); + $this->registerCollaborationResources(); + } public function registerNavigationEntry() { @@ -147,4 +152,16 @@ class Application extends App { return $this->getContainer()->query(CommentEventHandler::class); }); } + + protected function registerCollaborationResources() { + /** + * Register Collaboration ResourceProvider + */ + /** @var IManager $resourceManager */ + $resourceManager = $this->getContainer()->query(IManager::class); + $resourceManager->registerResourceProvider(ResourceProvider::class); + \OC::$server->getEventDispatcher()->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', function () { + \OCP\Util::addScript('deck', 'build/collections'); + }); + } } diff --git a/lib/Collaboration/Resources/ResourceProvider.php b/lib/Collaboration/Resources/ResourceProvider.php new file mode 100644 index 000000000..afaa28a4e --- /dev/null +++ b/lib/Collaboration/Resources/ResourceProvider.php @@ -0,0 +1,133 @@ + + * + * @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 OCA\Deck\Collaboration\Resources; + + +use OCA\Deck\Db\Acl; +use OCA\Deck\Db\Board; +use OCA\Deck\Db\BoardMapper; +use OCA\Deck\Service\PermissionService; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\QueryException; +use OCP\Collaboration\Resources\IManager; +use OCP\Collaboration\Resources\IProvider; +use OCP\Collaboration\Resources\IResource; +use OCP\Collaboration\Resources\ResourceException; +use OCP\IUser; + +class ResourceProvider implements IProvider { + + const RESOURCE_TYPE = 'deck'; + + private $boardMapper; + private $permissionService; + + /** @var array */ + protected $nodes = []; + + public function __construct(BoardMapper $boardMapper, PermissionService $permissionService) { + $this->boardMapper = $boardMapper; + $this->permissionService = $permissionService; + } + + /** + * Get the type of a resource + * + * @param IResource $resource + * @return string + * @since 15.0.0 + */ + public function getType(): string { + return self::RESOURCE_TYPE; + } + + /** + * Get the rich object data of a resource + * + * @param IResource $resource + * @return array + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @since 16.0.0 + */ + public function getResourceRichObject(IResource $resource): array { + $board = $this->getBoard($resource); + $link = \OC::$server->getURLGenerator()->linkToRoute('deck.page.index') . '#!/board/' . $resource->getId(); + + return [ + 'type' => self::RESOURCE_TYPE, + 'id' => $resource->getId(), + 'name' => $board->getTitle(), + 'link' => $link, + 'iconUrl' => \OC::$server->getURLGenerator()->imagePath('deck', 'deck-dark.svg') + ]; + + } + + /** + * Can a user/guest access the collection + * + * @param IResource $resource + * @param IUser|null $user + * @return bool + * @since 16.0.0 + */ + public function canAccessResource(IResource $resource, ?IUser $user): bool { + if ($resource->getType() !== self::RESOURCE_TYPE || !$user instanceof IUser) { + return false; + } + $board = $this->getBoard($resource); + if ($board === null) { + return false; + } + if ($board->getOwner() === $user->getUID()) { + return true; + } + return $this->permissionService->userCan($board->getAcl(), Acl::PERMISSION_READ, $user->getUID()); + } + + private function getBoard(IResource $resource) { + try { + return $this->boardMapper->find($resource->getId(), false, true); + } catch (DoesNotExistException $e) { + } catch (MultipleObjectsReturnedException $e) { + return null; + } + } + + public function invalidateAccessCache($boardId = null) { + try { + /** @var IManager $resourceManager */ + $resourceManager = \OC::$server->query(IManager::class); + } catch (QueryException $e) { + } + if ($boardId !== null) { + $resource = $resourceManager->getResourceForUser(self::RESOURCE_TYPE, (string)$boardId, null); + $resourceManager->invalidateAccessCacheForResource($resource); + } else { + $resourceManager->invalidateAccessCacheForProvider($this); + } + } +} diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index d39ba969b..8f539a406 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -25,6 +25,7 @@ namespace OCA\Deck\Service; use OCA\Deck\Activity\ActivityManager; use OCA\Deck\Activity\ChangeSet; +use OCA\Deck\Collaboration\Resources\ResourceProvider; use OCA\Deck\Db\Acl; use OCA\Deck\Db\AclMapper; use OCA\Deck\Db\AssignedUsersMapper; @@ -59,6 +60,7 @@ class BoardService { private $userId; private $activityManager; private $changeHelper; + private $resourceProvider; public function __construct( BoardMapper $boardMapper, @@ -73,6 +75,7 @@ class BoardService { IGroupManager $groupManager, ActivityManager $activityManager, ChangeHelper $changeHelper, + ResourceProvider $resourceProvider, $userId ) { $this->boardMapper = $boardMapper; @@ -87,6 +90,7 @@ class BoardService { $this->groupManager = $groupManager; $this->activityManager = $activityManager; $this->changeHelper = $changeHelper; + $this->resourceProvider = $resourceProvider; $this->userId = $userId; } @@ -459,6 +463,7 @@ class BoardService { $this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $newAcl, ActivityManager::SUBJECT_BOARD_SHARE); $this->boardMapper->mapAcl($newAcl); $this->changeHelper->boardChanged($boardId); + $this->resourceProvider->invalidateAccessCache($boardId); return $newAcl; } @@ -529,6 +534,7 @@ class BoardService { } $this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $acl, ActivityManager::SUBJECT_BOARD_UNSHARE); $this->changeHelper->boardChanged($acl->getBoardId()); + $this->resourceProvider->invalidateAccessCache($acl->getBoardId()); return $this->aclMapper->delete($acl); } diff --git a/lib/Service/PermissionService.php b/lib/Service/PermissionService.php index e6f8db541..c00ca703d 100644 --- a/lib/Service/PermissionService.php +++ b/lib/Service/PermissionService.php @@ -127,7 +127,7 @@ class PermissionService { * @return bool * @throws NoPermissionException */ - public function checkPermission($mapper, $id, $permission) { + public function checkPermission($mapper, $id, $permission, $userId = null) { $boardId = $id; if ($mapper instanceof IPermissionMapper) { $boardId = $mapper->findBoardId($id); @@ -141,12 +141,12 @@ class PermissionService { return false; } - if ($this->userIsBoardOwner($boardId)) { + if ($this->userIsBoardOwner($boardId, $userId)) { return true; } $acls = $this->aclMapper->findAll($boardId); - $result = $this->userCan($acls, $permission); + $result = $this->userCan($acls, $permission, $userId); if ($result) { return true; } @@ -159,10 +159,13 @@ class PermissionService { * @param $boardId * @return bool */ - public function userIsBoardOwner($boardId) { + public function userIsBoardOwner($boardId, $userId = null) { + if ($userId === null) { + $userId = $this->userId; + } try { $board = $this->boardMapper->find($boardId); - return $board && $this->userId === $board->getOwner(); + return $board && $userId === $board->getOwner(); } catch (DoesNotExistException $e) { } catch (MultipleObjectsReturnedException $e) { return false; @@ -176,17 +179,20 @@ class PermissionService { * @param $permission * @return bool */ - public function userCan(array $acls, $permission) { + public function userCan(array $acls, $permission, $userId = null) { + if ($userId === null) { + $userId = $this->userId; + } // check for users foreach ($acls as $acl) { - if ($acl->getType() === Acl::PERMISSION_TYPE_USER && $acl->getParticipant() === $this->userId) { + if ($acl->getType() === Acl::PERMISSION_TYPE_USER && $acl->getParticipant() === $userId) { return $acl->getPermission($permission); } } // check for groups $hasGroupPermission = false; foreach ($acls as $acl) { - if (!$hasGroupPermission && $acl->getType() === Acl::PERMISSION_TYPE_GROUP && $this->groupManager->isInGroup($this->userId, $acl->getParticipant())) { + if (!$hasGroupPermission && $acl->getType() === Acl::PERMISSION_TYPE_GROUP && $this->groupManager->isInGroup($userId, $acl->getParticipant())) { $hasGroupPermission = $acl->getPermission($permission); } } diff --git a/templates/main.php b/templates/main.php index cc583fab5..59944e6e9 100644 --- a/templates/main.php +++ b/templates/main.php @@ -32,8 +32,8 @@ Util::addStyle('activity', 'style'); Util::addStyle('comments', 'comments'); Util::addScript('oc-backbone-webdav'); -Util::addStyle('deck', '../js/build/vendor'); -Util::addScript('deck', 'build/vendor'); +//Util::addStyle('deck', '../js/build/vendor'); +//Util::addScript('deck', 'build/vendor'); Util::addStyle('deck', 'style'); Util::addScript('deck', 'build/deck'); @@ -41,6 +41,7 @@ Util::addScript('deck', 'build/deck'); if (\OC_Util::getVersion()[0] < 14) { Util::addStyle('deck', 'comp-13'); } +\OC::$server->getEventDispatcher()->dispatch('\OCP\Collaboration\Resources::loadAdditionalScripts'); ?>
t('Group')); ?>) - {{ sharee.participant.displayname }} + {{ sharee.participant.displayname }} @@ -82,6 +82,8 @@ t('Sharing has been disabled for your account.')); ?> +

Collections

+