summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2020-07-24 10:56:59 +0200
committerJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2020-08-21 10:05:42 +0200
commitd3f883752f24ab3661c77d78b10b62dc0b2d2414 (patch)
tree393371c96a4e4409d0d08eb0d89274ec6a1de181
parent68cb27a5b4ef0eecd7a0af597d3050bc709c5754 (diff)
Improve performance, sort contacts, exclude read-only and exclude already selected ones
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
-rw-r--r--lib/Controller/PageController.php3
-rw-r--r--package-lock.json100
-rw-r--r--package.json2
-rw-r--r--src/components/EntityPicker/EntityPicker.vue21
-rw-r--r--src/views/Contacts.vue33
-rw-r--r--tests/unit/Controller/PageControllerTest.php16
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
);
}