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 } 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/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({ 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/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 => { 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}`, diff --git a/src/targets/browser/makeClient.js b/src/targets/browser/makeClient.js index 6fe83e85..ca2e21d6 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, { WebFlagshipLink } 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,15 @@ 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 shouldUseWebFlagshipLink = + isFlagshipApp() && isFlagshipOfflineSupported() + const client = new CozyClient({ uri: cozyUrl, token: data.token, @@ -23,11 +29,17 @@ export const makeClient = () => { version: manifest.version }, schema, - store: true + store: true, + links: shouldUseWebFlagshipLink + ? new WebFlagshipLink({ 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 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"