From e3698c147f2173abd0272d06d2217b4ed0b0c015 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Tue, 24 Sep 2024 17:30:31 +0200 Subject: [PATCH 1/7] feat: Upgrade cozy-device-helper `cozy-device-helper` has been upgraded to `3.1.0` in order to retrieve the Offline mode support Related PR: cozy/cozy-libs#2562 --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a845f3da..72e68e33 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "classnames": "2.5.1", "cozy-bar": "^16.0.1", "cozy-client": "^53.1.0", - "cozy-device-helper": "^3.0.0", + "cozy-device-helper": "^3.1.0", "cozy-devtools": "^1.2.1", "cozy-doctypes": "^1.90.0", "cozy-flags": "^3.2.2", diff --git a/yarn.lock b/yarn.lock index 3e2a0a63..699a2db4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5343,7 +5343,7 @@ cozy-device-helper@^3.0.0: dependencies: lodash "^4.17.19" -cozy-device-helper@^3.7.1: +cozy-device-helper@^3.1.0, cozy-device-helper@^3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/cozy-device-helper/-/cozy-device-helper-3.7.1.tgz#59f11ab3ab92335525a767e78f983b07eeaf4eea" integrity sha512-D0zkEFynUrICNhQixyyYGhRHTwgJL+pf7XtmTwjKePIn2pNHKw5V64IhGg9uLYf6tI9uivkUKvZvFYuKzEvlqA== @@ -11447,9 +11447,9 @@ msgpack5@^4.0.2: readable-stream "^2.3.6" safe-buffer "^5.1.2" -"mui-bottom-sheet@git+https://github.com/cozy/mui-bottom-sheet.git#v1.0.9": +"mui-bottom-sheet@https://github.com/cozy/mui-bottom-sheet.git#v1.0.9": version "1.0.8" - resolved "git+https://github.com/cozy/mui-bottom-sheet.git#3dc4c2a245ab39079bc2f73546bccf80847be14c" + resolved "https://github.com/cozy/mui-bottom-sheet.git#3dc4c2a245ab39079bc2f73546bccf80847be14c" dependencies: "@juggle/resize-observer" "^3.1.3" jest-environment-jsdom-sixteen "^1.0.3" From dfc267cfb35204e0bd64dc5fc6610e64a0a0c148 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Wed, 19 Jun 2024 17:04:31 +0200 Subject: [PATCH 2/7] feat: Handle offline mode in Flagship app We want mespapiers to be compatible with the new Flagship app's Offline mode When hosted in a Flagship app's WebView we now want to use FlagshipLink instead of StackLink in cozy-client This link will allow to redirect all queries to the Flagship app that will handle data access when offline but also when online Related PR: cozy/cozy-client#1507 Related PR: cozy/cozy-flagship-app#1239 --- src/components/AppProviders.jsx | 73 +++++++++---------- src/components/AppRouter.jsx | 33 ++++++++- .../Scan/ScanActions/ScanDesktopActions.jsx | 2 +- src/targets/browser/makeClient.js | 17 ++++- src/targets/browser/setupApp.jsx | 8 +- 5 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/components/AppProviders.jsx b/src/components/AppProviders.jsx index 69d71112..8ff4d7b0 100644 --- a/src/components/AppProviders.jsx +++ b/src/components/AppProviders.jsx @@ -14,7 +14,6 @@ import { launchMetadataMigrationJob } from 'src/helpers/migration/metadata' import { BarProvider } from 'cozy-bar' import { CozyProvider } from 'cozy-client' -import { WebviewIntentProvider } from 'cozy-intent' import AlertProvider from 'cozy-ui/transpiled/react/providers/Alert' import { BreakpointsProvider } from 'cozy-ui/transpiled/react/providers/Breakpoints' import CozyTheme from 'cozy-ui/transpiled/react/providers/CozyTheme' @@ -45,43 +44,41 @@ export const AppProviders = ({ client, lang, polyglot, children }) => { return ( - - - - - - - - - - - - - - - - - - {children} - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + {children} + + + + + + + + + + + + + + + + ) } diff --git a/src/components/AppRouter.jsx b/src/components/AppRouter.jsx index ef5a5792..25d595b9 100644 --- a/src/components/AppRouter.jsx +++ b/src/components/AppRouter.jsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import { Navigate, Outlet, @@ -24,6 +24,10 @@ import InformationEdit from 'src/components/Views/InformationEdit' import MultiselectView from 'src/components/Views/MultiselectView' import ConditionnalPapersList from 'src/components/Views/PapersList' import PlaceholdersSelector from 'src/components/Views/PlaceholdersSelector' +import { makeClient } from 'src/targets/browser/makeClient' + +import { isFlagshipApp } from 'cozy-device-helper' +import { useWebviewIntent, WebviewIntentProvider } from 'cozy-intent' const fileViewerRoutes = props => [ { @@ -165,7 +169,32 @@ const makeRoutes = props => [ ] export const AppRouter = props => { - const router = createHashRouter(makeRoutes(props)) + return ( + + + + ) +} + +export const AppSubRouter = props => { + const webviewIntent = useWebviewIntent() + const [client, setClient] = useState(undefined) + + useEffect(() => { + if (isFlagshipApp() && !webviewIntent) return + + const client = makeClient(webviewIntent) + + setClient(client) + }, [webviewIntent]) + + if (!client) { + return null + } + + const propsWithClient = { ...props, client } + + const router = createHashRouter(makeRoutes(propsWithClient)) return } diff --git a/src/components/ModelSteps/Scan/ScanActions/ScanDesktopActions.jsx b/src/components/ModelSteps/Scan/ScanActions/ScanDesktopActions.jsx index 9fabc05a..4a91a51a 100644 --- a/src/components/ModelSteps/Scan/ScanActions/ScanDesktopActions.jsx +++ b/src/components/ModelSteps/Scan/ScanActions/ScanDesktopActions.jsx @@ -38,7 +38,7 @@ const ScanDesktopActions = ({ onOpenFilePickerModal, onChangeFile }) => { const showAlert = flag('mespapiers.aa-suggestion.disabled') ? false : isLoadedSettings - ? settingsData[0].showScanDesktopActionsAlert ?? true + ? settingsData[0]?.showScanDesktopActionsAlert ?? true : true const handleKeyDown = ({ key }) => { diff --git a/src/targets/browser/makeClient.js b/src/targets/browser/makeClient.js index 6fe83e85..a5dbbe6d 100644 --- a/src/targets/browser/makeClient.js +++ b/src/targets/browser/makeClient.js @@ -1,7 +1,10 @@ import schema from 'src/doctypes' -import CozyClient from 'cozy-client' +import CozyClient, { FlagshipLink } from 'cozy-client' +import { isFlagshipApp, isFlagshipOfflineSupported } from 'cozy-device-helper' +import flag from 'cozy-flags' import { Intents } from 'cozy-interapp' +import { RealtimePlugin } from 'cozy-realtime' import manifest from '../../../manifest.webapp' @@ -9,12 +12,14 @@ import manifest from '../../../manifest.webapp' * Make and returns cozy client instance * @returns {import('cozy-client/types/CozyClient').default} cozy client instance */ -export const makeClient = () => { +export const makeClient = intent => { const root = document.querySelector('[role=application]') const data = JSON.parse(root.dataset.cozy) const protocol = window.location.protocol const cozyUrl = `${protocol}//${data.domain}` + const shouldUseFlagshipLink = isFlagshipApp() && isFlagshipOfflineSupported() + const client = new CozyClient({ uri: cozyUrl, token: data.token, @@ -23,11 +28,17 @@ export const makeClient = () => { version: manifest.version }, schema, - store: true + store: true, + links: shouldUseFlagshipLink + ? new FlagshipLink({ webviewIntent: intent }) + : null }) const intents = new Intents({ client }) client.intents = intents + client.registerPlugin(RealtimePlugin) + client.registerPlugin(flag.plugin) + return client } diff --git a/src/targets/browser/setupApp.jsx b/src/targets/browser/setupApp.jsx index d86bf86a..62f08f7e 100644 --- a/src/targets/browser/setupApp.jsx +++ b/src/targets/browser/setupApp.jsx @@ -2,10 +2,7 @@ import { CaptureConsole } from '@sentry/integrations' import * as Sentry from '@sentry/react' import memoize from 'lodash/memoize' import { createRoot } from 'react-dom/client' -import { makeClient } from 'src/targets/browser/makeClient' -import flag from 'cozy-flags' -import { RealtimePlugin } from 'cozy-realtime' import { initTranslation } from 'cozy-ui/transpiled/react/providers/I18n' import manifest from '../../../manifest.webapp' @@ -22,9 +19,6 @@ const setupApp = memoize(() => { const locale = JSON.parse(container.dataset.cozy)?.locale const lang = getDataOrDefault(locale, 'en') const polyglot = initTranslation(lang, lang => require(`locales/${lang}`)) - const client = makeClient() - client.registerPlugin(RealtimePlugin) - client.registerPlugin(flag.plugin) Sentry.init({ dsn: 'https://1b0c26c4c1474da4b7fb5fa9d1e57869@errors.cozycloud.cc/63', @@ -39,7 +33,7 @@ const setupApp = memoize(() => { ignoreErrors: [/^Warning: /] }) - return { root, client, lang, polyglot } + return { root, lang, polyglot } }) export default setupApp From 9d0969e9b172db72d1fad9c966a1f3c2da695dbf Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Mon, 26 Aug 2024 18:28:03 +0200 Subject: [PATCH 3/7] fix: Make queries compatible with Offline mode Previous query was not compatible with CozyPouchLink --- src/queries/index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/queries/index.js b/src/queries/index.js index ba875c39..54a007bb 100644 --- a/src/queries/index.js +++ b/src/queries/index.js @@ -108,16 +108,17 @@ export const buildFilesQueryByLabel = label => ({ definition: () => Q(FILES_DOCTYPE) .where({ - 'metadata.qualification': { - label: label - } + created_at: { + $gt: null + }, + 'metadata.qualification.label': label }) .partialIndex({ type: 'file', trashed: false, 'cozyMetadata.createdByApp': { $exists: true } }) - .indexFields(['created_at', 'metadata.qualification']) + .indexFields(['created_at', 'metadata.qualification.label']) .sortBy([{ created_at: 'desc' }]), options: { as: `${FILES_DOCTYPE}/${label}`, From 0a3707fe4ab716fb9a72fdff4ca5c718b6e5be66 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Wed, 31 Jul 2024 18:23:18 +0200 Subject: [PATCH 4/7] feat: Download files offline In cozy/cozy-client#1518 we implemented a new `downloadFile()` that allow to download files as before in a browser, but will download files through cozy-intent when hosted in the Flagship app This commit will replace the old way to download files with the new one using `downloadFile()` --- src/components/Actions/Items/download.jsx | 5 +++-- src/components/Actions/handleFileDownloading.jsx | 16 ++++++++++++---- src/components/Actions/utils.js | 13 ++++--------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/components/Actions/Items/download.jsx b/src/components/Actions/Items/download.jsx index e326d386..4312d9f6 100644 --- a/src/components/Actions/Items/download.jsx +++ b/src/components/Actions/Items/download.jsx @@ -34,7 +34,7 @@ export const download = ({ label, icon, disabled: docs => docs.length === 0, - action: async (docs, { client }) => { + action: async (docs, { client, webviewIntent }) => { const fromMultiSelection = allMultiSelection.length > 0 const normalizedDocs = allMultiSelection.length > 0 @@ -48,7 +48,8 @@ export const download = ({ showAlert, t, pushModal, - popModal + popModal, + webviewIntent }) isMultiSelectionActive && navigate('..') }, diff --git a/src/components/Actions/handleFileDownloading.jsx b/src/components/Actions/handleFileDownloading.jsx index c9cc237d..52488592 100644 --- a/src/components/Actions/handleFileDownloading.jsx +++ b/src/components/Actions/handleFileDownloading.jsx @@ -13,6 +13,7 @@ import { is2SidedFile } from 'src/helpers/is2SidedFile' * @param {Function} params.showAlert - Function to show an alert * @param {Function} params.t - Translation function * @param {boolean} [params.fromMultiSelection] - Whether the action is from a multi-selection + * @param {WebviewService | undefined} [params.webviewIntent] - WebviewIntent used to call methods on FlagshipApp (when hosted in a WebView) */ export const handleFileDownloading = async ({ client, @@ -21,7 +22,8 @@ export const handleFileDownloading = async ({ pushModal, popModal, t, - fromMultiSelection + fromMultiSelection, + webviewIntent }) => { if ( filesWithPage.length === 1 && @@ -37,18 +39,24 @@ export const handleFileDownloading = async ({ textAction={t('action.download')} onClick={selectedChoice => { const selected = onPickSelectedPage(selectedChoice, file) - downloadFiles({ client, t, filesWithPage: selected, showAlert }) + downloadFiles({ + client, + t, + filesWithPage: selected, + showAlert, + webviewIntent + }) }} onClose={popModal} /> ) } else { - downloadFiles({ client, t, filesWithPage, showAlert }) + downloadFiles({ client, t, filesWithPage, showAlert, webviewIntent }) } return } if (filesWithPage.length > 0) { - downloadFiles({ client, t, filesWithPage, showAlert }) + downloadFiles({ client, t, filesWithPage, showAlert, webviewIntent }) } } diff --git a/src/components/Actions/utils.js b/src/components/Actions/utils.js index 1b87bec0..59ac9d8c 100644 --- a/src/components/Actions/utils.js +++ b/src/components/Actions/utils.js @@ -8,7 +8,7 @@ import { handleConflictFilename } from 'src/helpers/handleConflictFilename' import { isReferencedBy } from 'cozy-client' import { getDisplayName } from 'cozy-client/dist/models/contact' -import { splitFilename } from 'cozy-client/dist/models/file' +import { downloadFile, splitFilename } from 'cozy-client/dist/models/file' import { makeSharingLink } from 'cozy-client/dist/models/sharing' export const isAnyFileReferencedBy = (files, doctype) => { @@ -200,20 +200,15 @@ export const downloadFiles = async ({ client, filesWithPage, showAlert, - t + t, + webviewIntent }) => { try { const fileCollection = client.collection(FILES_DOCTYPE) if (filesWithPage.length === 1) { const { file, page } = filesWithPage[0] if (filesWithPage[0].page === null) { - const filename = file.name - const downloadURL = await fileCollection.getDownloadLinkById( - file.id, - filename - ) - - return fileCollection.forceFileDownload(`${downloadURL}?Dl=1`, filename) + return await downloadFile({ client, file, webviewIntent }) } else { const filename = makeFilenameWithPage({ file, page, t }) const bin = await getPdfPage({ From 394480ad94dc8edc453225a04ea618719adbd569 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Thu, 12 Sep 2024 18:14:31 +0200 Subject: [PATCH 5/7] feat: Declare offline compatibility in manifest.webapp --- manifest.webapp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/manifest.webapp b/manifest.webapp index c636ede2..b6df5bf1 100644 --- a/manifest.webapp +++ b/manifest.webapp @@ -138,5 +138,6 @@ "max_number_of_files": 1, "max_size_per_file_in_MB": 10, "route_to_upload": "/#/paper/create?fromFlagshipUpload=true" - } + }, + "offline_support": true } From fe0815f6dfba22604c5a1b1c88802ad8dd3188ce Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Mon, 23 Sep 2024 18:54:44 +0200 Subject: [PATCH 6/7] feat: Rename FlagshipLink to WebFlagshipLink Related PR: cozy/cozy-client#1536 --- src/targets/browser/makeClient.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/targets/browser/makeClient.js b/src/targets/browser/makeClient.js index a5dbbe6d..ca2e21d6 100644 --- a/src/targets/browser/makeClient.js +++ b/src/targets/browser/makeClient.js @@ -1,6 +1,6 @@ import schema from 'src/doctypes' -import CozyClient, { FlagshipLink } from 'cozy-client' +import CozyClient, { WebFlagshipLink } from 'cozy-client' import { isFlagshipApp, isFlagshipOfflineSupported } from 'cozy-device-helper' import flag from 'cozy-flags' import { Intents } from 'cozy-interapp' @@ -18,7 +18,8 @@ export const makeClient = intent => { const protocol = window.location.protocol const cozyUrl = `${protocol}//${data.domain}` - const shouldUseFlagshipLink = isFlagshipApp() && isFlagshipOfflineSupported() + const shouldUseWebFlagshipLink = + isFlagshipApp() && isFlagshipOfflineSupported() const client = new CozyClient({ uri: cozyUrl, @@ -29,8 +30,8 @@ export const makeClient = intent => { }, schema, store: true, - links: shouldUseFlagshipLink - ? new FlagshipLink({ webviewIntent: intent }) + links: shouldUseWebFlagshipLink + ? new WebFlagshipLink({ webviewIntent: intent }) : null }) From 1b0f407fd3ebec7738ad3426f9d558f2a78a4c6d Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Wed, 25 Sep 2024 13:49:49 +0200 Subject: [PATCH 7/7] fix: Make HasManyBills class compatible with offline When offline, the PouchDB result does not contain a `referenced_by` attribute if no relationship exists on the document. So we want to optional chain this attribute to prevent any exception thrown Related Commit: cozy/cozy-ui@e3eeb6ea15cb240ab2798bd812ce6fb104acba79 --- src/doctypes/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doctypes/index.js b/src/doctypes/index.js index 2e3b0041..378525b4 100644 --- a/src/doctypes/index.js +++ b/src/doctypes/index.js @@ -4,7 +4,7 @@ import { QueryDefinition, HasMany } from 'cozy-client' class HasManyBills extends HasMany { get data() { - const refs = this.target.relationships.referenced_by.data + const refs = this.target.relationships.referenced_by?.data return refs ? refs .map(ref => {