diff options
-rw-r--r-- | lib/Controller/PageController.php | 3 | ||||
-rw-r--r-- | package-lock.json | 100 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/components/EntityPicker/EntityPicker.vue | 21 | ||||
-rw-r--r-- | src/views/Contacts.vue | 33 | ||||
-rw-r--r-- | tests/unit/Controller/PageControllerTest.php | 16 |
6 files changed, 83 insertions, 92 deletions
diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index 95fca90b..3999bbac 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -29,10 +29,11 @@ use OCP\AppFramework\Controller; use OCP\AppFramework\Http\TemplateResponse; use OCA\Contacts\AppInfo\Application; +use OCA\Contacts\Service\SocialApiService; use OCP\IConfig; use OCP\IInitialStateService; -use OCP\IUserSession; use OCP\IRequest; +use OCP\IUserSession; use OCP\L10N\IFactory; use OCP\Util; diff --git a/package-lock.json b/package-lock.json index 511a80da..217a0d36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2673,21 +2673,9 @@ } }, "@nextcloud/vue": { -<<<<<<< HEAD -<<<<<<< HEAD "version": "2.3.0", "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-2.3.0.tgz", "integrity": "sha512-6uf7Hu4Obaet7BOs9H/Ng63xAYqks9CL7hsOOHGUzWFYrPPBxgt79iD9OOPpPfJuLQ3Nnuibh942X1QreCBRkw==", -======= - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-2.2.0.tgz", - "integrity": "sha512-F7KA39DrBQT/IFY42rqfcA0NvOqQ06PUtI6Htph5quXXgXdvqIqRSb+w2/aWkmprKwHRaBMtCX3Dxrd+uGdqpw==", ->>>>>>> 90efae4b... Add PatchPlugin -======= - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-2.2.1.tgz", - "integrity": "sha512-A2vrP+8cMM67Q9q5ZhUriNn4WDb/X6Q7zNqUT6iCQWI5pf/aun0DbWatZQRtH9OIDfdoj5seUlpNXlPFd8eccg==", ->>>>>>> 952908a4... Bump @nextcloud/vue "requires": { "@nextcloud/auth": "^1.2.3", "@nextcloud/axios": "^1.3.2", @@ -3780,8 +3768,8 @@ "dev": true }, "cdav-library": { - "version": "git+https://github.com/nextcloud/cdav-library.git#c2002a9f4e327ff8ae188ba1d5fc977f60b486a0", - "from": "git+https://github.com/nextcloud/cdav-library.git#c2002a9f4e327ff8ae188ba1d5fc977f60b486a0", + "version": "git+https://github.com/nextcloud/cdav-library.git#a41be4f7c4793ce9b681151ad33dc872989e701d", + "from": "git+https://github.com/nextcloud/cdav-library.git", "requires": { "core-js": "^3.6.5", "regenerator-runtime": "^0.13.7" @@ -4259,43 +4247,26 @@ } }, "css-loader": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.2.1.tgz", - "integrity": "sha512-MoqmF1if7Z0pZIEXA4ZF9PgtCXxWbfzfJM+3p+OYfhcrwcqhaCRb74DSnfzRl7e024xEiCRn5hCvfUbTf2sgFA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", "dev": true, "requires": { - "camelcase": "^6.0.0", + "camelcase": "^5.3.1", "cssesc": "^3.0.0", "icss-utils": "^4.1.1", - "loader-utils": "^2.0.0", + "loader-utils": "^1.2.3", "normalize-path": "^3.0.0", "postcss": "^7.0.32", "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.3", + "postcss-modules-local-by-default": "^3.0.2", "postcss-modules-scope": "^2.2.0", "postcss-modules-values": "^3.0.0", "postcss-value-parser": "^4.1.0", "schema-utils": "^2.7.0", - "semver": "^7.3.2" + "semver": "^6.3.0" }, "dependencies": { - "camelcase": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz", - "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==", - "dev": true - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, "postcss": { "version": "7.0.32", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", @@ -4307,12 +4278,6 @@ "supports-color": "^6.1.0" } }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4361,15 +4326,9 @@ } }, "date-fns": { -<<<<<<< HEAD "version": "2.15.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.15.0.tgz", "integrity": "sha512-ZCPzAMJZn3rNUvvQIMlXhDr4A+Ar07eLeGsGREoWU19a3Pqf5oYa+ccd+B3F6XVtQY6HANMFdOQ8A+ipFnvJdQ==" -======= - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.14.0.tgz", - "integrity": "sha512-1zD+68jhFgDIM0rF05rcwYO8cExdNqxjq4xP1QKM60Q45mnO6zaMWB4tOzrIr4M4GSLntsKeE4c9Bdl2jhL/yw==" ->>>>>>> 90efae4b... Add PatchPlugin }, "date-format-parse": { "version": "0.2.5", @@ -4675,9 +4634,9 @@ } }, "emoji-mart-vue-fast": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/emoji-mart-vue-fast/-/emoji-mart-vue-fast-7.0.2.tgz", - "integrity": "sha512-7OftneG98Jb9wkJgPBeUdEWrMMdGvd08erHMjNviKSuQSBsBAIFnQyW7lroBZ+dLT7uTZKuZfWdWwUfWpk965w==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/emoji-mart-vue-fast/-/emoji-mart-vue-fast-7.0.4.tgz", + "integrity": "sha512-VZuyclCe7ZNPhSvt7WT258MscqRBZTB2Is/7vBilCXgpiZqByaA4AhM1xdIIZZik/aA+5BQiZVmbsDK0jk78Eg==", "requires": { "@babel/polyfill": "7.2.5", "@babel/runtime": "7.3.4", @@ -6222,6 +6181,14 @@ "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "optional": true + } } }, "readable-stream": { @@ -7752,13 +7719,13 @@ "dev": true }, "md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", "requires": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" } }, "md5.js": { @@ -7989,8 +7956,7 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "minimist-options": { "version": "3.0.2", @@ -11718,9 +11684,9 @@ "integrity": "sha512-yaX2its9XAJKGuQqf7LsiZHHSkxsIK8rmCOQOvEGEoF41blKRK8qr9my4qYoD6ikdLss4n8tKqYBecmaY0+WJg==" }, "vue2-datepicker": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/vue2-datepicker/-/vue2-datepicker-3.6.1.tgz", - "integrity": "sha512-U6iQWSDsNoq/u6QJCtAMcyWlcZSx0rmPmqaJ8LQtGvwu9x12jXDoe3YNeG4y7E45OYAMLXs9WzGkDqDmNj3jkw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/vue2-datepicker/-/vue2-datepicker-3.6.2.tgz", + "integrity": "sha512-J2fCwUmCxIOPUvwQ12e8evFY9cCv6vJmgxRD9fGeUv6JeMMeLwkdpeQZOcqbMf/4mk1cSrY2/9Fr8DaB30LBpA==", "requires": { "date-fns": "^2.0.1", "date-format-parse": "^0.2.5" @@ -11982,15 +11948,9 @@ } }, "webpack-node-externals": { -<<<<<<< HEAD "version": "2.5.1", "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-2.5.1.tgz", "integrity": "sha512-RWxKGibUU5kuJT6JDYmXGa3QsZskqIaiBvZ2wBxHlJzWVJPOyBMnroXf23uxEHnj1rYS8jNdyUfrNAXJ2bANNw==", -======= - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-2.5.0.tgz", - "integrity": "sha512-g7/Z7Q/gsP8GkJkKZuJggn6RSb5PvxW1YD5vvmRZIxaSxAzkqjfL5n9CslVmNYlSqBVCyiqFgOqVS2IOObCSRg==", ->>>>>>> 90efae4b... Add PatchPlugin "dev": true }, "webpack-sources": { diff --git a/package.json b/package.json index 469684c0..27440d89 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "@nextcloud/eslint-plugin": "^1.4.0", "babel-eslint": "^10.1.0", "babel-loader": "^8.1.0", - "css-loader": "^4.2.1", + "css-loader": "^3.6.0", "eslint": "^6.8.0", "eslint-config-standard": "^14.1.1", "eslint-loader": "^4.0.2", diff --git a/src/components/EntityPicker/EntityPicker.vue b/src/components/EntityPicker/EntityPicker.vue index f4f11e5e..a35da7c1 100644 --- a/src/components/EntityPicker/EntityPicker.vue +++ b/src/components/EntityPicker/EntityPicker.vue @@ -75,6 +75,7 @@ {{ t('contacts', 'Cancel') }} </button> <button + :disabled="isEmptySelection" class="navigation__button-right primary" @click="onSubmit"> {{ t('contacts', 'Add to group') }} @@ -159,6 +160,19 @@ export default { return !(this.dataTypes.length > 1) }, + /** + * Is the current selection empty + * @returns {boolean} + */ + isEmptySelection() { + return Object.keys(this.selection).length === 0 + }, + + /** + * Formatted search input placeholder based on + * available types + * @returns {string} + */ searchPlaceholderTypes() { const types = this.dataTypes .map(type => type.label) @@ -182,7 +196,7 @@ export default { /** * Returns available entities grouped by type(s) if any - * @returns {Array[]} + * @returns {Object[]} */ availableEntities() { // If only one type, return the full set directly @@ -347,6 +361,11 @@ $icon-margin: ($clickable-area - $icon-size) / 2; } } +// Properly center Entity Picker empty content +.empty-content { + margin: 0; +} + /** Size full in the modal component doesn't have border radius, this adds it back */ ::v-deep .modal-container { diff --git a/src/views/Contacts.vue b/src/views/Contacts.vue index 5e1db112..f4141314 100644 --- a/src/views/Contacts.vue +++ b/src/views/Contacts.vue @@ -285,7 +285,6 @@ export default { // Create group isCreatingGroup: false, isNewGroupMenuOpen: false, - loading: true, createGroupError: null, // Add to group picker @@ -294,7 +293,7 @@ export default { contactPickerforGroup: null, pickerTypes: [{ id: 'contact', - label: t('contacts', 'contacts'), + label: t('contacts', 'Contacts'), }], // Bulk processing @@ -395,18 +394,6 @@ export default { recentlyContactedContacts() { return this.groups.find(group => group.name === t('contactsinteraction', 'Recently contacted')) }, - - /** - * Contacts formatted for the EntityPicker - * @returns {Array} - */ - pickerData() { - return Object.values(this.contacts).map(contact => ({ - id: contact.key, - label: contact.displayName, - type: 'contact', - })) - }, }, watch: { @@ -689,11 +676,29 @@ export default { } } + // Init data set + this.pickerData = this.sortedContacts + .map(({ key }) => { + const contact = this.contacts[key] + return { + id: contact.key, + label: contact.displayName, + type: 'contact', + readOnly: contact.addressbook.readOnly, + groups: contact.groups, + } + }) + // No read only contacts + .filter(contact => !contact.readOnly) + // No contacts already present in group + .filter(contact => contact.groups.indexOf(group.name) === -1) + this.showContactPicker = true this.contactPickerforGroup = group }, onContactPickerClose() { + this.pickerData = [] this.showContactPicker = false }, diff --git a/tests/unit/Controller/PageControllerTest.php b/tests/unit/Controller/PageControllerTest.php index 853bc29f..c7570f99 100644 --- a/tests/unit/Controller/PageControllerTest.php +++ b/tests/unit/Controller/PageControllerTest.php @@ -24,16 +24,17 @@ namespace OCA\Contacts\Controller; +use ChristophWurst\Nextcloud\Testing\TestCase; +use OCA\Contacts\Service\SocialApiService; use OCP\AppFramework\Http\TemplateResponse; +use OCP\IAppManager; use OCP\IConfig; -use PHPUnit\Framework\MockObject\MockObject; use OCP\IInitialStateService; +use OCP\IRequest; use OCP\IUser; use OCP\IUserSession; -use OCP\IRequest; use OCP\L10N\IFactory; -use OCA\Contacts\Service\SocialApiService; -use ChristophWurst\Nextcloud\Testing\TestCase; +use PHPUnit\Framework\MockObject\MockObject; class PageControllerTest extends TestCase { private $controller; @@ -56,6 +57,9 @@ class PageControllerTest extends TestCase { /** @var SocialApiService|MockObject*/ private $socialApi; + /** @var IAppManager|MockObject*/ + private $appManager; + public function setUp() { parent::setUp(); @@ -65,6 +69,7 @@ class PageControllerTest extends TestCase { $this->languageFactory = $this->createMock(IFactory::class); $this->userSession = $this->createMock(IUserSession::class); $this->socialApi = $this->createMock(SocialApiService::class); + $this->appManager = $this->createMock(IAppManager::class); $this->controller = new PageController( $this->request, @@ -72,7 +77,8 @@ class PageControllerTest extends TestCase { $this->initialStateService, $this->languageFactory, $this->userSession, - $this->socialApi + $this->socialApi, + $this->appManager ); } |