From 3a27c1bbfcc048b99aca5007157bcfa82836a3c2 Mon Sep 17 00:00:00 2001 From: Cozy Pierre Date: Wed, 10 Aug 2022 17:50:43 +0200 Subject: [PATCH 1/9] feat(deps): Upgrade cozy-bar to be able to call onSelect function --- CHANGELOG.md | 3 ++- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c58896c76c..2bb013b51e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## ✨ Features +* Upgrade cozy-bar@7.20.0 to be able to call onSelect function * Update cozy-stack-client and cozy-pouch-link to sync with cozy-client version * Update cozy-ui - Modify Viewers to handle [68.0.0 BC](https://github.com/cozy/cozy-ui/releases/tag/v68.0.0) @@ -12,7 +13,7 @@ * Improve cozy-bar implementation to fix UI bugs in Amirale * Fix navigation through mobile Flagship on Note creation and opening -* Remove unused contacts permissions on Photos +* Remove unused contacts permissions on Photos ## 🔧 Tech diff --git a/package.json b/package.json index 9a1986fe83..c63c337910 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "classnames": "2.3.1", "copy-text-to-clipboard": "1.0.4", "cozy-authentication": "2.8.3", - "cozy-bar": "7.19.1", + "cozy-bar": "7.20.0", "cozy-ci": "0.4.1", "cozy-client": "^32.2.8", "cozy-client-js": "0.19.0", diff --git a/yarn.lock b/yarn.lock index 9e4df2322b..b86d2a7c04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5895,10 +5895,10 @@ cozy-authentication@2.8.3: snarkdown "1.2.2" url-polyfill "1.1.7" -cozy-bar@7.19.1: - version "7.19.1" - resolved "https://registry.yarnpkg.com/cozy-bar/-/cozy-bar-7.19.1.tgz#ed20e3909ed2452a07596c1afb214499165a61bb" - integrity sha512-0lgy5PayOUTtaoyrvdMzbNr5nEesK1n3B5VV+Za8BhZReJx5/GXp+5yTgNJcwLBLwR6/Dl6EhvNogLiCgtO1yg== +cozy-bar@7.20.0: + version "7.20.0" + resolved "https://registry.yarnpkg.com/cozy-bar/-/cozy-bar-7.20.0.tgz#b16d0fcacd29ad762e1423ea6e7059fb022cee5f" + integrity sha512-+hkczI7A4+PKB3vFMUgS6BWAsGV2b6BY/N/nkGCezpKOlGtb5An87aX9JPaUcK0IoBfdBP06nOV9gW/nWgFsaw== dependencies: "@cozy/minilog" "^1.0.0" cozy-client "^27.14.4" From f1e5acfaac8fdf88ebf6aa2c82b9da57929f8ab3 Mon Sep 17 00:00:00 2001 From: Cozy Pierre Date: Wed, 10 Aug 2022 17:52:46 +0200 Subject: [PATCH 2/9] feat(deps): Upgrade cozy-client to be able to findAll in FileCollection --- CHANGELOG.md | 1 + package.json | 6 +++--- yarn.lock | 28 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bb013b51e..be86dbc032 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## ✨ Features +* Upgrade cozy-stack-client@32.7.0 to be able to findAll in FileCollection * Upgrade cozy-bar@7.20.0 to be able to call onSelect function * Update cozy-stack-client and cozy-pouch-link to sync with cozy-client version * Update cozy-ui diff --git a/package.json b/package.json index c63c337910..e812259b3c 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "cozy-authentication": "2.8.3", "cozy-bar": "7.20.0", "cozy-ci": "0.4.1", - "cozy-client": "^32.2.8", + "cozy-client": "^32.7.0", "cozy-client-js": "0.19.0", "cozy-device-helper": "^2.1.0", "cozy-doctypes": "1.82.2", @@ -125,12 +125,12 @@ "cozy-intent": "^1.17.1", "cozy-keys-lib": "4.1.9", "cozy-logger": "1.9.0", - "cozy-pouch-link": "^32.2.8", + "cozy-pouch-link": "^32.7.0", "cozy-realtime": "3.14.4", "cozy-scanner": "2.0.2", "cozy-scripts": "^6.3.8", "cozy-sharing": "4.1.5", - "cozy-stack-client": "^32.2.5", + "cozy-stack-client": "^32.7.0", "cozy-ui": "^68.4.0", "date-fns": "1.30.1", "diacritics": "1.3.0", diff --git a/yarn.lock b/yarn.lock index b86d2a7c04..186d009b68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5974,16 +5974,16 @@ cozy-client@^27.14.4: sift "^6.0.0" url-search-params-polyfill "^8.0.0" -cozy-client@^32.2.8: - version "32.2.8" - resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-32.2.8.tgz#149dc0c696061b4aa7403263194179797f3a9c0d" - integrity sha512-23lFqnfpfbKkYAmLWCXZQxAODQLU4w9atKJA4Ej6vMK4bFJ3AsmXexDqFEfN0sCwzysoiqhWcqtVX7isaQHQ7w== +cozy-client@^32.7.0: + version "32.7.0" + resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-32.7.0.tgz#8b997d9d9f704e5699fdd5da51b7470cd6eafb1f" + integrity sha512-91L3mf2WIWhjM2von4bTTMIspoP4405QxF+MT4hYS1viWnoADbKsDhCu2s3ZTOxca9ri3AJrzjxtYdUoyXAnYA== dependencies: "@cozy/minilog" "1.0.0" "@types/jest" "^26.0.20" "@types/lodash" "^4.14.170" btoa "^1.2.1" - cozy-stack-client "^32.2.5" + cozy-stack-client "^32.7.0" json-stable-stringify "^1.0.1" lodash "^4.17.13" microee "^0.0.6" @@ -6128,12 +6128,12 @@ cozy-logger@^1.3.0, cozy-logger@^1.6.0, cozy-logger@^1.7.0: chalk "^2.4.2" json-stringify-safe "5.0.1" -cozy-pouch-link@^32.2.8: - version "32.2.8" - resolved "https://registry.yarnpkg.com/cozy-pouch-link/-/cozy-pouch-link-32.2.8.tgz#86ceb1d6d909849d85dcd05ef2880e1cd380485e" - integrity sha512-4EjOmlFiGaT3HPZe8fl/nh/MW55x+hLYVE6FNrblZF65lQxG4wdA9qj8tlEXp6qaCPhtpxk7aVUEQSsxWOrVgA== +cozy-pouch-link@^32.7.0: + version "32.7.0" + resolved "https://registry.yarnpkg.com/cozy-pouch-link/-/cozy-pouch-link-32.7.0.tgz#7766cde69783a98502f8ee75b642708b23195bb6" + integrity sha512-Kxr7VZpr6VXenqXmtggZYdwtgmy5VcYtIy+wmDX23WH8IFobLottoR4L/v53Diqai4l1jeuAZCvJV+2VwPzOCw== dependencies: - cozy-client "^32.2.8" + cozy-client "^32.7.0" pouchdb-browser "^7.2.2" pouchdb-find "^7.2.2" @@ -6252,10 +6252,10 @@ cozy-stack-client@^27.21.0: mime "^2.4.0" qs "^6.7.0" -cozy-stack-client@^32.2.5: - version "32.2.5" - resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-32.2.5.tgz#ffb798fb8a9de6126d53abbf68b7b6f90a0db9e2" - integrity sha512-RJKOc7Vd6CAmDEpdohU84PT8KYTnC/UsYm1IsBPrqzzeZCZXceHJWtALB1rpwfTdLTvu3heYYAuLjJqtqVbBGQ== +cozy-stack-client@^32.7.0: + version "32.7.0" + resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-32.7.0.tgz#7990c54427a56436b2685750c9d4665fecb6edd4" + integrity sha512-UxAooLfgKVYdoyCvG/Qrx5h0niRBmIiFA8mDKnWUkZMMaOHs3s5X3DqYqmF3ki+tKlhMO4l9eugsbdwoKItK3w== dependencies: detect-node "^2.0.4" mime "^2.4.0" From 1133fb967dac522a0712f7e4c3d6c9c1c1a8cf7b Mon Sep 17 00:00:00 2001 From: Cozy Pierre Date: Thu, 4 Aug 2022 17:49:00 +0200 Subject: [PATCH 3/9] feat(search): improve search by querying fewer data Selector is mandatory when using .select or .partialIndex https://github.com/cozy/cozy-client/issues/1216 --- .eslintrc.json | 11 +- CHANGELOG.md | 1 + src/drive/web/modules/queries.js | 31 +++++ .../components/SuggestionProvider.jsx | 86 ++++++++------ .../components/SuggestionProvider.spec.jsx | 109 ++++++++++++++++++ .../modules/services/components/helpers.js | 20 +++- .../services/components/helpers.spec.js | 29 ++--- test/dummies/dummyFile.js | 33 ++++++ 8 files changed, 258 insertions(+), 62 deletions(-) create mode 100644 src/drive/web/modules/services/components/SuggestionProvider.spec.jsx create mode 100644 test/dummies/dummyFile.js diff --git a/.eslintrc.json b/.eslintrc.json index 938f4e68e3..9a1264d8b8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,6 @@ "no-console": 1, "no-param-reassign": "error", "react-hooks/exhaustive-deps": "error" - }, "globals": { "fixture": false @@ -13,5 +12,13 @@ "react": { "version": "detect" } - } + }, + "overrides": [ + { + "files": ["*.spec.js[x]"], + "rules": { + "react/display-name": "off" + } + } + ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index be86dbc032..70618b568b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Upgrade cozy-stack-client@32.7.0 to be able to findAll in FileCollection * Upgrade cozy-bar@7.20.0 to be able to call onSelect function +* Improve speed of search suggestion by querying fewer data * Update cozy-stack-client and cozy-pouch-link to sync with cozy-client version * Update cozy-ui - Modify Viewers to handle [68.0.0 BC](https://github.com/cozy/cozy-ui/releases/tag/v68.0.0) diff --git a/src/drive/web/modules/queries.js b/src/drive/web/modules/queries.js index f1592dad6c..1efe3af6b7 100644 --- a/src/drive/web/modules/queries.js +++ b/src/drive/web/modules/queries.js @@ -325,6 +325,37 @@ export const buildEncryptionByIdQuery = id => ({ } }) +/** + * Provide selector and options to fetch files + * + * @returns {{options: {MangoQueryOptions}, selector: object}} A minimalist file list + */ +export const prepareSuggestionQuery = () => { + const selector = { + _id: { + $gt: null + } + } + const options = { + partialFilter: { + _id: { + $ne: TRASH_DIR_ID + }, + path: { + // this predicate is necessary until the trashed attribute is more reliable + $or: [{ $exists: false }, { $regex: '^(?!/.cozy_trash)' }] + }, + trashed: { + $or: [{ $exists: false }, { $eq: false }] + } + }, + fields: ['_id', 'trashed', 'dir_id', 'name', 'path', 'type', 'mime'], + indexedFields: ['_id'], + limit: 1000 + } + return { selector, options } +} + export { buildDriveQuery, buildRecentQuery, diff --git a/src/drive/web/modules/services/components/SuggestionProvider.jsx b/src/drive/web/modules/services/components/SuggestionProvider.jsx index abfccb3873..eaa507faa3 100644 --- a/src/drive/web/modules/services/components/SuggestionProvider.jsx +++ b/src/drive/web/modules/services/components/SuggestionProvider.jsx @@ -1,15 +1,16 @@ -/* global cozy */ import React from 'react' import FuzzyPathSearch from '../FuzzyPathSearch' import { withClient } from 'cozy-client' import { TYPE_DIRECTORY, makeNormalizedFile } from './helpers' import { getIconUrl } from './iconContext' +import { DOCTYPE_FILES } from 'drive/lib/doctypes' +import { prepareSuggestionQuery } from '../../queries' class SuggestionProvider extends React.Component { componentDidMount() { const { intent } = this.props - this.hasIndexedFiles = false + this.hasIndexFilesBeenLaunched = false // re-attach the message listener for the intent to receive the suggestion requests window.addEventListener('message', event => { @@ -22,8 +23,25 @@ class SuggestionProvider extends React.Component { }) } + /** + * Provide Suggestions to calling Intent + * + * This method called when intent provide query will indexFiles once + * to fill FuzzyPathSearch. Then will re-post message to the intent + * with updated search results containing `files` as `suggestions` + * for SearchBar need. + * + * ⚠️ For note file, we don't provide url to open, but onSelect method + * to be called on click. Less API calls expected. But a note will be opened + * slower. See helpers.js + * + * @param query - Query to find file + * @param id + * @param intent - Intent calling + * @returns {Promise} nothing + */ async provideSuggestions(query, id, intent) { - if (!this.hasIndexedFiles) { + if (!this.hasIndexFilesBeenLaunched) { await this.indexFiles() } @@ -38,7 +56,7 @@ class SuggestionProvider extends React.Component { title: result.name, subtitle: result.path, term: result.name, - onSelect: 'open:' + result.url, + onSelect: result.onSelect || 'open:' + result.url, icon: result.icon })) }, @@ -46,44 +64,42 @@ class SuggestionProvider extends React.Component { ) } - // fetches pretty much all the files and preloads FuzzyPathSearch + /** + * Fetches all files without trashed and preloads FuzzyPathSearch + * + * Using _find route (from findAll) improves performance: + * - using partial index to reduce amount of data fetched + * - removing trashed data directly + * + * Also, this method: + * - set first the `hasIndexFilesBeenLaunched` to prevent multiple calls + * - removes orphan file + * - normalize file to match expectation + * - preloads FuzzyPathSearch + * + * @returns {Promise} nothing + */ async indexFiles() { const { client } = this.props - // TODO: fix me - // eslint-disable-next-line no-async-promise-executor - return new Promise(async resolve => { - const resp = await cozy.client.fetchJSON( - 'GET', - `/data/io.cozy.files/_all_docs?include_docs=true` - ) - const files = resp.rows - // TODO: fix me - // eslint-disable-next-line no-prototype-builtins - .filter(row => !row.doc.hasOwnProperty('views')) - .map(row => ({ id: row.id, ...row.doc })) + this.hasIndexFilesBeenLaunched = true - const folders = files.filter(file => file.type === TYPE_DIRECTORY) + const { selector, options } = prepareSuggestionQuery() + const files = await client + .collection(DOCTYPE_FILES) + .findAll(selector, options) - const notInTrash = file => - !file.trashed && !/^\/\.cozy_trash/.test(file.path) - const notOrphans = file => - folders.find(folder => folder._id === file.dir_id) !== undefined + const folders = files.filter(file => file.type === TYPE_DIRECTORY) - const normalizedFilesPrevious = files - .filter(notInTrash) - .filter(notOrphans) + const notOrphans = file => + folders.find(folder => folder._id === file.dir_id) !== undefined - const normalizedFiles = await Promise.all( - normalizedFilesPrevious.map( - async file => - await makeNormalizedFile(client, folders, file, getIconUrl) - ) - ) + const normalizedFilesPrevious = files.filter(notOrphans) - this.fuzzyPathSearch = new FuzzyPathSearch(normalizedFiles) - this.hasIndexedFiles = true - resolve() - }) + const normalizedFiles = normalizedFilesPrevious.map(file => + makeNormalizedFile(client, folders, file, getIconUrl) + ) + + this.fuzzyPathSearch = new FuzzyPathSearch(normalizedFiles) } render() { diff --git a/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx new file mode 100644 index 0000000000..fe4f405890 --- /dev/null +++ b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx @@ -0,0 +1,109 @@ +import React from 'react' +import { render, waitFor } from '@testing-library/react' +import SuggestionProvider from './SuggestionProvider' +import { dummyFile, dummyNote } from 'test/dummies/dummyFile' + +const parentFolder = dummyFile({ _id: 'id-file' }) +const folder = dummyFile({ dir_id: 'id-file' }) +const note = dummyNote({ + dir_id: 'id-file', + name: 'name.cozy-note' +}) +const mockFindAll = jest.fn().mockReturnValue([parentFolder, folder, note]) +const mockClient = { + collection: jest.fn().mockReturnValue({ findAll: mockFindAll }) +} +const mockIntentAttributesClient = 'intent-attributes-client' + +jest.mock('cozy-client', () => ({ + ...jest.requireActual('cozy-client'), + withClient: Component => () => { + const intent = { + _id: 'id_intent', + attributes: { client: mockIntentAttributesClient } + } + return + } +})) +jest.mock('./iconContext', () => ({ getIconUrl: () => 'iconUrl' })) + +describe('SuggestionProvider', () => { + let events = {} + let event + + beforeEach(() => { + window.addEventListener = jest.fn((event, callback) => { + events[event] = callback + }) + window.parent.postMessage = jest.fn() + event = { + origin: mockIntentAttributesClient, + data: { query: 'name', id: 'id' } + } + }) + + it('should query all files to display fuzzy suggestion', () => { + // Given + render() + + // When + events.message(event) + + // Then + expect(mockClient.collection).toHaveBeenCalledWith('io.cozy.files') + expect(mockFindAll).toHaveBeenCalledWith( + { + _id: { + $gt: null + } + }, + { + fields: ['_id', 'trashed', 'dir_id', 'name', 'path', 'type', 'mime'], + indexedFields: ['_id'], + limit: 1000, + partialFilter: { + _id: { $ne: 'io.cozy.files.trash-dir' }, + path: { $or: [{ $exists: false }, { $regex: '^(?!/.cozy_trash)' }] }, + trashed: { $or: [{ $exists: false }, { $eq: false }] } + } + } + ) + }) + + it('should provide onSelect with open url when file is not a note + and function when it is a note', async () => { + // Given + render() + + // When + events.message(event) + + // Then + await waitFor(() => { + expect(window.parent.postMessage).toHaveBeenCalledWith( + { + id: 'id', + suggestions: [ + { + icon: 'iconUrl', + id: 'id-file', + onSelect: 'open:http://localhost/#/folder/id-file', + subtitle: '/path', + term: 'name', + title: 'name' + }, + { + icon: 'iconUrl', + id: 'id-file', + onSelect: expect.any(Function), + subtitle: '/path', + term: 'name.cozy-note', + title: 'name.cozy-note' + } + ], + type: 'intent-id_intent:data' + }, + 'intent-attributes-client' + ) + }) + }) +}) diff --git a/src/drive/web/modules/services/components/helpers.js b/src/drive/web/modules/services/components/helpers.js index a9e35a45a8..a15de3b70c 100644 --- a/src/drive/web/modules/services/components/helpers.js +++ b/src/drive/web/modules/services/components/helpers.js @@ -2,12 +2,25 @@ import { models } from 'cozy-client' export const TYPE_DIRECTORY = 'directory' -export const makeNormalizedFile = async (client, folders, file, getIconUrl) => { +/** + * Normalize file for Front usage in component inside + * + * To reduce API call, the fetching of Note URL has been delayed + * inside an onSelect function called only if provided to + * see https://github.com/cozy/cozy-drive/pull/2663#discussion_r938671963 + * + * @param client - cozy client instance + * @param folders - all the folders returned by API + * @param file - file to normalize + * @param getIconUrl - method to get icon url + * @returns {{path: (*|string), name, icon, id, url: string, onSelect: (function(): Promise)}} file with + */ +export const makeNormalizedFile = (client, folders, file, getIconUrl) => { const isDir = file.type === TYPE_DIRECTORY const dirId = isDir ? file._id : file.dir_id const urlToFolder = `${window.location.origin}/#/folder/${dirId}` - let path, url + let path, url, onSelect if (isDir) { path = file.path url = urlToFolder @@ -15,7 +28,7 @@ export const makeNormalizedFile = async (client, folders, file, getIconUrl) => { const parentDir = folders.find(folder => folder._id === file.dir_id) path = parentDir && parentDir.path ? parentDir.path : '' if (models.file.isNote(file)) { - url = await models.note.fetchURL(client, file) + onSelect = () => models.note.fetchURL(client, file) } else { url = `${urlToFolder}/file/${file._id}` } @@ -26,6 +39,7 @@ export const makeNormalizedFile = async (client, folders, file, getIconUrl) => { name: file.name, path, url, + onSelect, icon: getIconUrl(file) } } diff --git a/src/drive/web/modules/services/components/helpers.spec.js b/src/drive/web/modules/services/components/helpers.spec.js index 57244d2ee2..84af90814d 100644 --- a/src/drive/web/modules/services/components/helpers.spec.js +++ b/src/drive/web/modules/services/components/helpers.spec.js @@ -19,7 +19,7 @@ const noteFileProps = { } describe('makeNormalizedFile', () => { - it('should return correct values for a directory', async () => { + it('should return correct values for a directory', () => { const folders = [] const file = { _id: 'fileId', @@ -28,12 +28,7 @@ describe('makeNormalizedFile', () => { name: 'fileName' } - const normalizedFile = await makeNormalizedFile( - client, - folders, - file, - getIconUrl - ) + const normalizedFile = makeNormalizedFile(client, folders, file, getIconUrl) expect(normalizedFile).toMatchObject({ id: 'fileId', @@ -43,7 +38,7 @@ describe('makeNormalizedFile', () => { }) }) - it('should return correct values for a file', async () => { + it('should return correct values for a file', () => { const folders = [{ _id: 'folderId', path: 'folderPath' }] const file = { _id: 'fileId', @@ -52,12 +47,7 @@ describe('makeNormalizedFile', () => { name: 'fileName' } - const normalizedFile = await makeNormalizedFile( - client, - folders, - file, - getIconUrl - ) + const normalizedFile = makeNormalizedFile(client, folders, file, getIconUrl) expect(normalizedFile).toMatchObject({ id: 'fileId', @@ -67,7 +57,7 @@ describe('makeNormalizedFile', () => { }) }) - it('should return correct values for a note', async () => { + it('should return correct values for a note with on Select function - better for performance', () => { const folders = [{ _id: 'folderId', path: 'folderPath' }] const file = { _id: 'fileId', @@ -77,18 +67,13 @@ describe('makeNormalizedFile', () => { ...noteFileProps } - const normalizedFile = await makeNormalizedFile( - client, - folders, - file, - getIconUrl - ) + const normalizedFile = makeNormalizedFile(client, folders, file, getIconUrl) expect(normalizedFile).toMatchObject({ id: 'fileId', name: 'note.cozy-note', path: 'folderPath', - url: 'noteUrl' + onSelect: expect.any(Function) }) }) }) diff --git a/test/dummies/dummyFile.js b/test/dummies/dummyFile.js new file mode 100644 index 0000000000..bc5ed8bdf0 --- /dev/null +++ b/test/dummies/dummyFile.js @@ -0,0 +1,33 @@ +/** + * Create a dummy file, with overridden value of given param + * + * @param file + * @returns {*&{path: string, name: string, icon: string, id: string, _id: string, dir_id: string, type: string}} a dummy file + */ +export const dummyFile = file => ({ + name: 'name', + id: 'id-file', + _id: 'id-file', + icon: 'icon', + path: '/path', + type: 'directory', + ...file +}) + +/** + + * + * @param note + * @returns {*&{path: string, name: string, icon: string, id: string, _id: string, dir_id: string, type: string, metadata: object}} a dummy note + */ +export const dummyNote = note => ({ + ...dummyFile(), + type: 'file', + metadata: { + content: '', + schema: '', + title: '', + version: '' + }, + ...note +}) From 8d4abc39cc3794cbe6d8c5a8969195349748cfe6 Mon Sep 17 00:00:00 2001 From: Cozy Pierre Date: Fri, 12 Aug 2022 12:12:51 +0200 Subject: [PATCH 4/9] chore(bundlemon): Upgrade maxSize of qualification migration --- .bundlemonrc | 2 +- test/dummies/dummyFile.js | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.bundlemonrc b/.bundlemonrc index f70a416dcb..12f05200cb 100644 --- a/.bundlemonrc +++ b/.bundlemonrc @@ -32,7 +32,7 @@ }, { "path": "services/qualificationMigration/drive.js", - "maxSize": "242 KB" + "maxSize": "244 KB" }, { "path": "vendors/drive...min.css", diff --git a/test/dummies/dummyFile.js b/test/dummies/dummyFile.js index bc5ed8bdf0..0352cbd0a1 100644 --- a/test/dummies/dummyFile.js +++ b/test/dummies/dummyFile.js @@ -1,13 +1,17 @@ +// eslint-disable-next-line no-unused-vars +const { IOCozyFile } = require('cozy-client/dist/types') + /** * Create a dummy file, with overridden value of given param * - * @param file - * @returns {*&{path: string, name: string, icon: string, id: string, _id: string, dir_id: string, type: string}} a dummy file + * @param {?IOCozyFile} [file={}] - optional file with value to keep + * @returns {IOCozyFile} a dummy file */ export const dummyFile = file => ({ + _id: 'id-file', + _type: 'doctype-file', name: 'name', id: 'id-file', - _id: 'id-file', icon: 'icon', path: '/path', type: 'directory', @@ -15,10 +19,10 @@ export const dummyFile = file => ({ }) /** - + * Create a dummy note, with overridden value of given param * - * @param note - * @returns {*&{path: string, name: string, icon: string, id: string, _id: string, dir_id: string, type: string, metadata: object}} a dummy note + * @param {?IOCozyFile} [note={}] + * @returns {IOCozyFile} a dummy note */ export const dummyNote = note => ({ ...dummyFile(), From 298411da00db2571ed44f823f4ecbf7e19f737e7 Mon Sep 17 00:00:00 2001 From: Cozy Pierre Date: Wed, 17 Aug 2022 18:22:59 +0200 Subject: [PATCH 5/9] fix(search): use find method where args are for find --- package.json | 6 +-- src/drive/web/modules/queries.js | 42 ++++++++----------- .../components/SuggestionProvider.jsx | 6 +-- .../components/SuggestionProvider.spec.jsx | 25 ++++------- yarn.lock | 28 ++++++------- 5 files changed, 45 insertions(+), 62 deletions(-) diff --git a/package.json b/package.json index e812259b3c..0e40e56227 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "cozy-authentication": "2.8.3", "cozy-bar": "7.20.0", "cozy-ci": "0.4.1", - "cozy-client": "^32.7.0", + "cozy-client": "^32.7.3", "cozy-client-js": "0.19.0", "cozy-device-helper": "^2.1.0", "cozy-doctypes": "1.82.2", @@ -125,12 +125,12 @@ "cozy-intent": "^1.17.1", "cozy-keys-lib": "4.1.9", "cozy-logger": "1.9.0", - "cozy-pouch-link": "^32.7.0", + "cozy-pouch-link": "^32.7.3", "cozy-realtime": "3.14.4", "cozy-scanner": "2.0.2", "cozy-scripts": "^6.3.8", "cozy-sharing": "4.1.5", - "cozy-stack-client": "^32.7.0", + "cozy-stack-client": "^32.7.3", "cozy-ui": "^68.4.0", "date-fns": "1.30.1", "diacritics": "1.3.0", diff --git a/src/drive/web/modules/queries.js b/src/drive/web/modules/queries.js index 1efe3af6b7..f25e7ac854 100644 --- a/src/drive/web/modules/queries.js +++ b/src/drive/web/modules/queries.js @@ -326,35 +326,27 @@ export const buildEncryptionByIdQuery = id => ({ }) /** - * Provide selector and options to fetch files + * Provide options to fetch files * - * @returns {{options: {MangoQueryOptions}, selector: object}} A minimalist file list + * @returns {MangoQueryOptions} A minimalist file list */ -export const prepareSuggestionQuery = () => { - const selector = { +export const prepareSuggestionQuery = () => ({ + partialFilter: { _id: { - $gt: null - } - } - const options = { - partialFilter: { - _id: { - $ne: TRASH_DIR_ID - }, - path: { - // this predicate is necessary until the trashed attribute is more reliable - $or: [{ $exists: false }, { $regex: '^(?!/.cozy_trash)' }] - }, - trashed: { - $or: [{ $exists: false }, { $eq: false }] - } + $ne: TRASH_DIR_ID }, - fields: ['_id', 'trashed', 'dir_id', 'name', 'path', 'type', 'mime'], - indexedFields: ['_id'], - limit: 1000 - } - return { selector, options } -} + path: { + // this predicate is necessary until the trashed attribute is more reliable + $or: [{ $exists: false }, { $regex: '^(?!/.cozy_trash)' }] + }, + trashed: { + $or: [{ $exists: false }, { $eq: false }] + } + }, + fields: ['_id', 'trashed', 'dir_id', 'name', 'path', 'type', 'mime'], + indexedFields: ['_id'], + limit: 1000 +}) export { buildDriveQuery, diff --git a/src/drive/web/modules/services/components/SuggestionProvider.jsx b/src/drive/web/modules/services/components/SuggestionProvider.jsx index eaa507faa3..a03a51c704 100644 --- a/src/drive/web/modules/services/components/SuggestionProvider.jsx +++ b/src/drive/web/modules/services/components/SuggestionProvider.jsx @@ -83,10 +83,8 @@ class SuggestionProvider extends React.Component { const { client } = this.props this.hasIndexFilesBeenLaunched = true - const { selector, options } = prepareSuggestionQuery() - const files = await client - .collection(DOCTYPE_FILES) - .findAll(selector, options) + const options = prepareSuggestionQuery() + const files = await client.collection(DOCTYPE_FILES).findAll(null, options) const folders = files.filter(file => file.type === TYPE_DIRECTORY) diff --git a/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx index fe4f405890..770e14a3e5 100644 --- a/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx +++ b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx @@ -51,23 +51,16 @@ describe('SuggestionProvider', () => { // Then expect(mockClient.collection).toHaveBeenCalledWith('io.cozy.files') - expect(mockFindAll).toHaveBeenCalledWith( - { - _id: { - $gt: null - } - }, - { - fields: ['_id', 'trashed', 'dir_id', 'name', 'path', 'type', 'mime'], - indexedFields: ['_id'], - limit: 1000, - partialFilter: { - _id: { $ne: 'io.cozy.files.trash-dir' }, - path: { $or: [{ $exists: false }, { $regex: '^(?!/.cozy_trash)' }] }, - trashed: { $or: [{ $exists: false }, { $eq: false }] } - } + expect(mockFindAll).toHaveBeenCalledWith(null, { + fields: ['_id', 'trashed', 'dir_id', 'name', 'path', 'type', 'mime'], + indexedFields: ['_id'], + limit: 1000, + partialFilter: { + _id: { $ne: 'io.cozy.files.trash-dir' }, + path: { $or: [{ $exists: false }, { $regex: '^(?!/.cozy_trash)' }] }, + trashed: { $or: [{ $exists: false }, { $eq: false }] } } - ) + }) }) it('should provide onSelect with open url when file is not a note + and function when it is a note', async () => { diff --git a/yarn.lock b/yarn.lock index 186d009b68..f43ebf938f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5974,16 +5974,16 @@ cozy-client@^27.14.4: sift "^6.0.0" url-search-params-polyfill "^8.0.0" -cozy-client@^32.7.0: - version "32.7.0" - resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-32.7.0.tgz#8b997d9d9f704e5699fdd5da51b7470cd6eafb1f" - integrity sha512-91L3mf2WIWhjM2von4bTTMIspoP4405QxF+MT4hYS1viWnoADbKsDhCu2s3ZTOxca9ri3AJrzjxtYdUoyXAnYA== +cozy-client@^32.7.3: + version "32.7.3" + resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-32.7.3.tgz#8048e899124852c2dab66cd627b238e61e08a476" + integrity sha512-7em+xdzdbOeUKrb7X8aVlOITYkilqsv5y1xvPijIUAY9oPfGVnOsDByTlrtxel9VDRjdyhTWV/TFosyFsF6YlQ== dependencies: "@cozy/minilog" "1.0.0" "@types/jest" "^26.0.20" "@types/lodash" "^4.14.170" btoa "^1.2.1" - cozy-stack-client "^32.7.0" + cozy-stack-client "^32.7.3" json-stable-stringify "^1.0.1" lodash "^4.17.13" microee "^0.0.6" @@ -6128,12 +6128,12 @@ cozy-logger@^1.3.0, cozy-logger@^1.6.0, cozy-logger@^1.7.0: chalk "^2.4.2" json-stringify-safe "5.0.1" -cozy-pouch-link@^32.7.0: - version "32.7.0" - resolved "https://registry.yarnpkg.com/cozy-pouch-link/-/cozy-pouch-link-32.7.0.tgz#7766cde69783a98502f8ee75b642708b23195bb6" - integrity sha512-Kxr7VZpr6VXenqXmtggZYdwtgmy5VcYtIy+wmDX23WH8IFobLottoR4L/v53Diqai4l1jeuAZCvJV+2VwPzOCw== +cozy-pouch-link@^32.7.3: + version "32.7.3" + resolved "https://registry.yarnpkg.com/cozy-pouch-link/-/cozy-pouch-link-32.7.3.tgz#3658fe42115d6c9f95d71cf9cdfc17cdc29d87f4" + integrity sha512-xb3HMn7ON+vSFz0wzxJEg5wgE0TsdISwfuy9CjplAGvaFHnCiCGa2xf7yTX8TF0Z8PSppBRJSYqoNfOfCPDOZA== dependencies: - cozy-client "^32.7.0" + cozy-client "^32.7.3" pouchdb-browser "^7.2.2" pouchdb-find "^7.2.2" @@ -6252,10 +6252,10 @@ cozy-stack-client@^27.21.0: mime "^2.4.0" qs "^6.7.0" -cozy-stack-client@^32.7.0: - version "32.7.0" - resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-32.7.0.tgz#7990c54427a56436b2685750c9d4665fecb6edd4" - integrity sha512-UxAooLfgKVYdoyCvG/Qrx5h0niRBmIiFA8mDKnWUkZMMaOHs3s5X3DqYqmF3ki+tKlhMO4l9eugsbdwoKItK3w== +cozy-stack-client@^32.7.3: + version "32.7.3" + resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-32.7.3.tgz#f2b46e8e31d17bb27467d189e5956f004d2fbcdf" + integrity sha512-TakiZnPIZ4idQmTfyyDc2MkEEVcfOAPbQNj7/BhtYFX+2p1ocNfHA0EAWF2fd/ijfcxOgj3i5lxRjDbilxy9PQ== dependencies: detect-node "^2.0.4" mime "^2.4.0" From ba47d2eb6a15069f96b54d852fdea0fc93c73206 Mon Sep 17 00:00:00 2001 From: Cozy Pierre Date: Thu, 18 Aug 2022 10:52:20 +0200 Subject: [PATCH 6/9] fix(search): note needs metadata to be considered as note --- src/drive/web/modules/queries.js | 11 ++++++++++- .../services/components/SuggestionProvider.spec.jsx | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/drive/web/modules/queries.js b/src/drive/web/modules/queries.js index f25e7ac854..c624da6120 100644 --- a/src/drive/web/modules/queries.js +++ b/src/drive/web/modules/queries.js @@ -343,7 +343,16 @@ export const prepareSuggestionQuery = () => ({ $or: [{ $exists: false }, { $eq: false }] } }, - fields: ['_id', 'trashed', 'dir_id', 'name', 'path', 'type', 'mime'], + fields: [ + '_id', + 'trashed', + 'dir_id', + 'name', + 'path', + 'type', + 'mime', + 'metadata' + ], indexedFields: ['_id'], limit: 1000 }) diff --git a/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx index 770e14a3e5..c09d70239f 100644 --- a/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx +++ b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx @@ -52,7 +52,16 @@ describe('SuggestionProvider', () => { // Then expect(mockClient.collection).toHaveBeenCalledWith('io.cozy.files') expect(mockFindAll).toHaveBeenCalledWith(null, { - fields: ['_id', 'trashed', 'dir_id', 'name', 'path', 'type', 'mime'], + fields: [ + '_id', + 'trashed', + 'dir_id', + 'name', + 'path', + 'type', + 'mime', + 'metadata' + ], indexedFields: ['_id'], limit: 1000, partialFilter: { From 4dcbc83554a9896f876aaa6a1bed5a21ae5d3a50 Mon Sep 17 00:00:00 2001 From: Cozy Pierre Date: Thu, 18 Aug 2022 11:43:21 +0200 Subject: [PATCH 7/9] fix(search): notes function can not be postMessage as a function --- .../modules/services/components/SuggestionProvider.spec.jsx | 2 +- src/drive/web/modules/services/components/helpers.js | 2 +- src/drive/web/modules/services/components/helpers.spec.js | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx index c09d70239f..e67c661cea 100644 --- a/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx +++ b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx @@ -96,7 +96,7 @@ describe('SuggestionProvider', () => { { icon: 'iconUrl', id: 'id-file', - onSelect: expect.any(Function), + onSelect: 'id_note:id-file', subtitle: '/path', term: 'name.cozy-note', title: 'name.cozy-note' diff --git a/src/drive/web/modules/services/components/helpers.js b/src/drive/web/modules/services/components/helpers.js index a15de3b70c..0ed8e3fe86 100644 --- a/src/drive/web/modules/services/components/helpers.js +++ b/src/drive/web/modules/services/components/helpers.js @@ -28,7 +28,7 @@ export const makeNormalizedFile = (client, folders, file, getIconUrl) => { const parentDir = folders.find(folder => folder._id === file.dir_id) path = parentDir && parentDir.path ? parentDir.path : '' if (models.file.isNote(file)) { - onSelect = () => models.note.fetchURL(client, file) + onSelect = `id_note:${file.id}` } else { url = `${urlToFolder}/file/${file._id}` } diff --git a/src/drive/web/modules/services/components/helpers.spec.js b/src/drive/web/modules/services/components/helpers.spec.js index 84af90814d..093141cc71 100644 --- a/src/drive/web/modules/services/components/helpers.spec.js +++ b/src/drive/web/modules/services/components/helpers.spec.js @@ -61,6 +61,7 @@ describe('makeNormalizedFile', () => { const folders = [{ _id: 'folderId', path: 'folderPath' }] const file = { _id: 'fileId', + id: 'noteId', dir_id: 'folderId', type: 'file', name: 'fileName', @@ -73,7 +74,7 @@ describe('makeNormalizedFile', () => { id: 'fileId', name: 'note.cozy-note', path: 'folderPath', - onSelect: expect.any(Function) + onSelect: 'id_note:noteId' }) }) }) From db978748dff0dbbaf99de53423ec5ca713dff057 Mon Sep 17 00:00:00 2001 From: Cozy Pierre Date: Mon, 22 Aug 2022 12:03:48 +0200 Subject: [PATCH 8/9] fix(search): isNote should not check all metadata, missing while fetching we don't fetch all metadata param of file, because this field may make requests much bigger that's why we need to create a specific method to fix this problem --- src/drive/web/modules/queries.js | 3 ++- .../components/SuggestionProvider.spec.jsx | 3 ++- .../modules/services/components/helpers.js | 25 ++++++++++++++++--- .../services/components/helpers.spec.js | 20 +++++++++++++++ .../services/components/iconContext.js | 5 ++-- 5 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/drive/web/modules/queries.js b/src/drive/web/modules/queries.js index c624da6120..0185f2c334 100644 --- a/src/drive/web/modules/queries.js +++ b/src/drive/web/modules/queries.js @@ -351,7 +351,8 @@ export const prepareSuggestionQuery = () => ({ 'path', 'type', 'mime', - 'metadata' + 'metadata.title', + 'metadata.version' ], indexedFields: ['_id'], limit: 1000 diff --git a/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx index e67c661cea..d35f67076b 100644 --- a/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx +++ b/src/drive/web/modules/services/components/SuggestionProvider.spec.jsx @@ -60,7 +60,8 @@ describe('SuggestionProvider', () => { 'path', 'type', 'mime', - 'metadata' + 'metadata.title', + 'metadata.version' ], indexedFields: ['_id'], limit: 1000, diff --git a/src/drive/web/modules/services/components/helpers.js b/src/drive/web/modules/services/components/helpers.js index 0ed8e3fe86..84c053c8fc 100644 --- a/src/drive/web/modules/services/components/helpers.js +++ b/src/drive/web/modules/services/components/helpers.js @@ -1,6 +1,25 @@ -import { models } from 'cozy-client' - export const TYPE_DIRECTORY = 'directory' +const FILE_TYPE = 'file' + +/** + * Is file param a correct note + * + * Inspired by https://github.com/cozy/cozy-client/blob/b7ffdd97d017bbd52226e0b61099da3090d8253f/packages/cozy-client/src/models/file.js#L52 + * but don't check metadata (not provided while fetching Suggestions) + * + * @param {IOCozyFile} file io.cozy.files + * @returns {boolean} + */ +export const isNote = file => { + if ( + file && + file.name && + file.name.endsWith('.cozy-note') && + file.type === FILE_TYPE + ) + return true + return false +} /** * Normalize file for Front usage in component inside @@ -27,7 +46,7 @@ export const makeNormalizedFile = (client, folders, file, getIconUrl) => { } else { const parentDir = folders.find(folder => folder._id === file.dir_id) path = parentDir && parentDir.path ? parentDir.path : '' - if (models.file.isNote(file)) { + if (isNote(file)) { onSelect = `id_note:${file.id}` } else { url = `${urlToFolder}/file/${file._id}` diff --git a/src/drive/web/modules/services/components/helpers.spec.js b/src/drive/web/modules/services/components/helpers.spec.js index 093141cc71..5e15b27c9c 100644 --- a/src/drive/web/modules/services/components/helpers.spec.js +++ b/src/drive/web/modules/services/components/helpers.spec.js @@ -77,4 +77,24 @@ describe('makeNormalizedFile', () => { onSelect: 'id_note:noteId' }) }) + + it('should return correct values for a note without metadata', () => { + const folders = [{ _id: 'folderId', path: 'folderPath' }] + const file = { + _id: 'fileId', + id: 'noteId', + dir_id: 'folderId', + type: 'file', + name: 'note.cozy-note' + } + + const normalizedFile = makeNormalizedFile(client, folders, file, getIconUrl) + + expect(normalizedFile).toMatchObject({ + id: 'fileId', + name: 'note.cozy-note', + path: 'folderPath', + onSelect: 'id_note:noteId' + }) + }) }) diff --git a/src/drive/web/modules/services/components/iconContext.js b/src/drive/web/modules/services/components/iconContext.js index 0f2fc50f34..4d91fca506 100644 --- a/src/drive/web/modules/services/components/iconContext.js +++ b/src/drive/web/modules/services/components/iconContext.js @@ -1,5 +1,4 @@ -import { TYPE_DIRECTORY } from './helpers' -import { models } from 'cozy-client' +import { isNote, TYPE_DIRECTORY } from './helpers' import { isEncryptedFolder } from 'drive/lib/encryption' import { getFileMimetype } from 'drive/lib/getFileMimetype' @@ -23,7 +22,7 @@ export function getIconUrl(file) { keyIcon = 'folder' } } else { - keyIcon = models.file.isNote(file) + keyIcon = isNote(file) ? 'note' : getFileMimetype(icons)(file.mime, file.name) || 'files' } From 1cd1efcbd579167a16f573fee6c157aad3decdd3 Mon Sep 17 00:00:00 2001 From: Cozy Pierre Date: Tue, 23 Aug 2022 14:23:27 +0200 Subject: [PATCH 9/9] fixup: with cozy-bar upgrade --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0e40e56227..0f2fa7bb50 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "classnames": "2.3.1", "copy-text-to-clipboard": "1.0.4", "cozy-authentication": "2.8.3", - "cozy-bar": "7.20.0", + "cozy-bar": "7.20.1", "cozy-ci": "0.4.1", "cozy-client": "^32.7.3", "cozy-client-js": "0.19.0", diff --git a/yarn.lock b/yarn.lock index f43ebf938f..1720203bf8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5895,10 +5895,10 @@ cozy-authentication@2.8.3: snarkdown "1.2.2" url-polyfill "1.1.7" -cozy-bar@7.20.0: - version "7.20.0" - resolved "https://registry.yarnpkg.com/cozy-bar/-/cozy-bar-7.20.0.tgz#b16d0fcacd29ad762e1423ea6e7059fb022cee5f" - integrity sha512-+hkczI7A4+PKB3vFMUgS6BWAsGV2b6BY/N/nkGCezpKOlGtb5An87aX9JPaUcK0IoBfdBP06nOV9gW/nWgFsaw== +cozy-bar@7.20.1: + version "7.20.1" + resolved "https://registry.yarnpkg.com/cozy-bar/-/cozy-bar-7.20.1.tgz#9ae1f112c2e9f5a5c8369f1ceea686d9f63c77bb" + integrity sha512-Aa9R9G8lCjCscOLeX8MaG/PB1LXpvflaBUtG/LFpBOYW9gfNVP7YM2YNQKcN7hKKhhGjY5/52sU1K9HOb+ke1g== dependencies: "@cozy/minilog" "^1.0.0" cozy-client "^27.14.4"