From 9f9fbb9edb56535a9345705b57d1b5eb9eed4b57 Mon Sep 17 00:00:00 2001 From: JF-Cozy Date: Thu, 24 Oct 2024 13:58:00 +0200 Subject: [PATCH 1/3] feat(hooks): Add useClientErrors from cozy-client and remove it from there --- package.json | 5 +- react/hooks/useClientErrors.jsx | 140 ++++++++++ react/hooks/useClientErrors.spec.jsx | 102 +++++++ test/jestsetup.js | 4 +- yarn.lock | 396 ++------------------------- 5 files changed, 264 insertions(+), 383 deletions(-) create mode 100644 react/hooks/useClientErrors.jsx create mode 100644 react/hooks/useClientErrors.spec.jsx diff --git a/package.json b/package.json index 1a689daff0..113dc5fb51 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,8 @@ "svgo": "2.8.0", "svgstore-cli": "1.3.2", "url-loader": "1.1.2", - "webpack": "4.39.3" + "webpack": "4.39.3", + "whatwg-fetch": "3.5.0" }, "dependencies": { "@babel/runtime": "^7.3.4", @@ -210,4 +211,4 @@ "browserslist": [ "extends browserslist-config-cozy" ] -} \ No newline at end of file +} diff --git a/react/hooks/useClientErrors.jsx b/react/hooks/useClientErrors.jsx new file mode 100644 index 0000000000..05325ff39a --- /dev/null +++ b/react/hooks/useClientErrors.jsx @@ -0,0 +1,140 @@ +import filter from 'lodash/filter' +import React, { useCallback, useState, useEffect } from 'react' + +import { useClient } from 'cozy-client' +import { FetchError } from 'cozy-stack-client' + +import QuotaAlert from '../deprecated/QuotaAlert' + +/** + * Rendering functions for client fetch errors by status code + * + * @private + * @type {object} + */ +const byHttpStatus = { + 413: QuotaError // +} + +/** + * Display for a quota error from the client + * + * @see QuotaAlert + * @private + * @param {object} props - Props + * @param {Function} props.dismiss - remove the error from the stack to display + * @returns {React.ReactElement} + */ +function QuotaError({ dismiss }) { + return +} + +/** + * Returns the handler for an error + * + * @param {import("../types").ClientError} error - The error + * @returns {Function|null} React Component + */ +function getErrorComponent(error) { + if (error instanceof Response || error instanceof FetchError) { + const status = error.status || '' + return byHttpStatus[status] || null + } + return null +} + +/** + * Renders a stack of errors + * + * @private + * @see ClientErrors + * @param {import("../types").ClientError[]} errorStack - array of errors/exceptions + * @param {Function} setErrorStack - mutates the array of errors + * @returns {Array} React rendering + */ +function renderErrors(errorStack, setErrorStack) { + const errors = errorStack.map((error, key) => { + const Component = getErrorComponent(error) + if (Component) { + const dismiss = () => + setErrorStack(stack => filter(stack, e => e !== error)) + return + } else { + return null + } + }) + return errors +} + +/** + * Manages the client errors and allows to display them + * + * Returns a `ClientErrors` React component that takes care + * of how to display cozy-client errors (probably displaying a modal) + * + * Only Quota Errors are managed for now. + * + * @example + * ``` + * const App = () => { + * const { ClientErrors } = useClientErrors() + * + * return + *

My app

+ * + *
+ * } + * ``` + * + * @param {object} [props] - Props + * @param {boolean} [props.handleExceptions] - should cozy-client directly handle errors before forwarding them to the caller? + * @returns {{ClientErrors: Function}} React component + */ +export default function useClientErrors({ handleExceptions = true } = {}) { + const client = useClient() + const [errorStack, setErrorStack] = useState([]) + + /** + * Handle client errors, add them to the error stack + * + * @param {import("../types").ClientError} error - + * @returns {boolean} true if the error was manager, false otherwise + */ + const handleError = useCallback( + error => { + // `isErrorManaged` is there to avoid the same error to be added twice + // once the error has been added once, the `isErrorManaged`is set to true + // and any future push is ignored + if (error.isErrorManaged) return false + + const isManageable = !!getErrorComponent(error) + if (isManageable) { + error.isErrorManaged = true + setErrorStack(stack => stack.concat(error)) + return true + } else { + error.isErrorManaged = false + return false + } + }, + [setErrorStack] + ) + + useEffect(() => { + if (handleExceptions) { + client.on('error', handleError) + return () => client.removeListener('error', handleError) + } else { + return undefined + } + }, [client, handleError, handleExceptions]) + + // @ts-ignore + const ClientErrors = useCallback( + () => renderErrors(errorStack, setErrorStack), + [errorStack, setErrorStack] + ) + // @ts-ignore + ClientErrors.displayName = 'ClientErrors' + return { ClientErrors } +} diff --git a/react/hooks/useClientErrors.spec.jsx b/react/hooks/useClientErrors.spec.jsx new file mode 100644 index 0000000000..77fb5246ac --- /dev/null +++ b/react/hooks/useClientErrors.spec.jsx @@ -0,0 +1,102 @@ +import { renderHook, act } from '@testing-library/react-hooks' +import { shallow } from 'enzyme' +import React from 'react' + +import { CozyProvider } from 'cozy-client' +import { FetchError } from 'cozy-stack-client' + +import useClientErrors from './useClientErrors' + +function createCozyClient() { + return { + on: jest.fn(), + removeListener: jest.fn() + } +} + +function createWrapper(client = createCozyClient()) { + function Wrapper({ children }) { + return {children} + } + return Wrapper +} + +function renderWrappedHook(client) { + const wrapper = createWrapper(client) + return renderHook(() => useClientErrors(), { wrapper }) +} + +function wrappedShallow(tree, client) { + return shallow(tree, { wrappingComponent: createWrapper(client) }) +} + +describe('useClientErrors', () => { + it('registers an `error` handler in client', done => { + const client = createCozyClient() + client.on.mockImplementation(name => name === 'error' && done()) + renderWrappedHook(client) + }) + + describe('renderErrors', () => { + it('returns a function', () => { + const { result } = renderWrappedHook() + const { ClientErrors } = result.current + expect(ClientErrors).toBeInstanceOf(Function) + }) + + it('displays nothing by default', () => { + const { result } = renderWrappedHook() + const { ClientErrors } = result.current + const node = wrappedShallow() + expect(node).toHaveLength(0) + }) + + describe('for quota errors', () => { + const findQuotaAlert = node => { + return node.at(0).dive() + } + const setup = async () => { + const client = createCozyClient() + const response = new Response(null, { + status: 413, + statusText: 'Quota exceeded' + }) + const error = new FetchError( + response, + `${response.status} ${response.statusText}` + ) + + const { result, waitForNextUpdate } = renderWrappedHook(client) + const nextUpdate = waitForNextUpdate() + + act(() => { + const handler = client.on.mock.calls[0][1] + handler(error) + }) + + await nextUpdate + const { ClientErrors } = result.current + const node = wrappedShallow(, client) + return { node, result, client } + } + + it('displays a a QuotaAlert', async () => { + const { node } = await setup() + expect(node).toHaveLength(1) + expect(findQuotaAlert(node).type().name).toEqual('QuotaAlert') + }) + + it('can be dismissed', async () => { + const { node, result, client } = await setup() + const quotaAlert = findQuotaAlert(node) + const onClose = quotaAlert.props().onClose + act(() => onClose()) + + // re-render ClientErrors returned by the hook + const { ClientErrors } = result.current + const updatedNode = wrappedShallow(, client) + expect(updatedNode.at(0).length).toBe(0) + }) + }) + }) +}) diff --git a/test/jestsetup.js b/test/jestsetup.js index c50a4f29e4..c34ca5d390 100644 --- a/test/jestsetup.js +++ b/test/jestsetup.js @@ -1,9 +1,11 @@ import '@testing-library/jest-dom/extend-expect' import { configure, mount, shallow } from 'enzyme' import Adapter from 'enzyme-adapter-react-16' +import fetch from 'whatwg-fetch' configure({ adapter: new Adapter() }) +global.fetch = fetch global.mount = mount global.shallow = shallow @@ -17,7 +19,7 @@ const isDeprecatedLifecycleWarning = (msg, componentName) => { } const ignoreOnConditions = (originalWarn, ignoreConditions) => { - return function(...args) { + return function (...args) { const msg = args[0] if (ignoreConditions.some(condition => condition(msg))) { return diff --git a/yarn.lock b/yarn.lock index 60653c3d26..5ad217bcdf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2311,20 +2311,6 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.4.4.tgz#11d5db19bd178936ec89cd84519c4de439574398" integrity sha512-1oO6+dN5kdIA3sKPZhRGJTfGVP4SWV6KqlMOwry4J3HfyD68sl/3KmG7DeYUzvN+RbhXDnv/D8vNNB8168tAMg== -"@puppeteer/browsers@2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.3.0.tgz#791ea7d80450fea24eb19fb1d70c367ad4e08cae" - integrity sha512-ioXoq9gPxkss4MYhD+SFaU9p1IHFUX0ILAWFPyjGaBdjLsYAlZw6j1iLA0N/m12uVHLFDfSYNF7EQccjinIMDA== - dependencies: - debug "^4.3.5" - extract-zip "^2.0.1" - progress "^2.0.3" - proxy-agent "^6.4.0" - semver "^7.6.3" - tar-fs "^3.0.6" - unbzip2-stream "^1.4.3" - yargs "^17.7.2" - "@react-spring/animated@9.0.0-rc.3": version "9.0.0-rc.3" resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.0.0-rc.3.tgz#e792cb76aacecfc78db2be6020ac11ce96503eb5" @@ -2762,11 +2748,6 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== -"@tootallnate/quickjs-emscripten@^0.23.0": - version "0.23.0" - resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" - integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== - "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" @@ -3108,13 +3089,6 @@ dependencies: "@types/yargs-parser" "*" -"@types/yauzl@^2.9.1": - version "2.10.3" - resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999" - integrity sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q== - dependencies: - "@types/node" "*" - "@typescript-eslint/eslint-plugin@5.54.0": version "5.54.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz#2c821ad81b2c786d142279a8292090f77d1881f4" @@ -3511,13 +3485,6 @@ agent-base@6, agent-base@^6.0.2: dependencies: debug "4" -agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" - integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== - dependencies: - debug "^4.3.4" - agentkeepalive@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717" @@ -4061,18 +4028,18 @@ ast-types@0.14.1: dependencies: tslib "^2.0.1" -ast-types@^0.13.4, ast-types@~0.13.2: +ast-types@^0.7.2: + version "0.7.8" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.7.8.tgz#902d2e0d60d071bdcd46dc115e1809ed11c138a9" + integrity sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk= + +ast-types@~0.13.2: version "0.13.4" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== dependencies: tslib "^2.0.1" -ast-types@^0.7.2: - version "0.7.8" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.7.8.tgz#902d2e0d60d071bdcd46dc115e1809ed11c138a9" - integrity sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk= - astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" @@ -4378,39 +4345,6 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -bare-events@^2.0.0, bare-events@^2.2.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.4.2.tgz#3140cca7a0e11d49b3edc5041ab560659fd8e1f8" - integrity sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q== - -bare-fs@^2.1.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-2.3.1.tgz#cdbd63dac7a552dfb2b87d18c822298d1efd213d" - integrity sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA== - dependencies: - bare-events "^2.0.0" - bare-path "^2.0.0" - bare-stream "^2.0.0" - -bare-os@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-2.4.0.tgz#5de5e3ba7704f459c9656629edca7cc736e06608" - integrity sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg== - -bare-path@^2.0.0, bare-path@^2.1.0: - version "2.1.3" - resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-2.1.3.tgz#594104c829ef660e43b5589ec8daef7df6cedb3e" - integrity sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA== - dependencies: - bare-os "^2.1.0" - -bare-stream@^2.0.0: - version "2.1.3" - resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.1.3.tgz#070b69919963a437cc9e20554ede079ce0a129b2" - integrity sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ== - dependencies: - streamx "^2.18.0" - base64-js@^1.0.2: version "1.3.0" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" @@ -4444,11 +4378,6 @@ basic-auth@^1.0.3: resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" integrity sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ= -basic-ftp@^5.0.2: - version "5.0.5" - resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.0.5.tgz#14a474f5fffecca1f4f406f1c26b18f800225ac0" - integrity sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg== - batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" @@ -4783,11 +4712,6 @@ buble@0.19.8: os-homedir "^2.0.0" regexpu-core "^4.5.4" -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== - buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -4812,7 +4736,7 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.2.1, buffer@^5.5.0: +buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -5381,15 +5305,6 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromium-bidi@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.6.3.tgz#363fe1ca6b9c6122b9f1b2a47f9449ecf712f755" - integrity sha512-qXlsCmpCZJAnoTYI83Iu6EdYQpMYdVkCfq08KDh2pmlVqK5t5IA9mGs4/LwCwp4fqisSOMXZxP3HIh8w8aRn0A== - dependencies: - mitt "3.0.1" - urlpattern-polyfill "10.0.0" - zod "3.23.8" - ci-info@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" @@ -5585,15 +5500,6 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - clone-deep@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6" @@ -6832,11 +6738,6 @@ dashify@^2.0.0: resolved "https://registry.yarnpkg.com/dashify/-/dashify-2.0.0.tgz#fff270ca2868ca427fee571de35691d6e437a648" integrity sha512-hpA5C/YrPjucXypHPPc0oJ1l9Hf6wWbiOL7Ik42cxnsUOhWiCB/fylKbKqqJalW9FgkNQCw16YO8uW9Hs0Iy1A== -data-uri-to-buffer@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz#8a58bb67384b261a38ef18bea1810cb01badd28b" - integrity sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw== - data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -6919,13 +6820,6 @@ debug@^3.1.1, debug@^3.2.5, debug@^3.2.6, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.3.5, debug@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" - integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== - dependencies: - ms "2.1.2" - debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -7070,15 +6964,6 @@ defined@^1.0.0: resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= -degenerator@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-5.0.1.tgz#9403bf297c6dad9a1ece409b37db27954f91f2f5" - integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ== - dependencies: - ast-types "^0.13.4" - escodegen "^2.1.0" - esprima "^4.0.1" - del@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" @@ -7182,11 +7067,6 @@ detect-port-alt@1.1.6: address "^1.0.1" debug "^2.6.0" -devtools-protocol@0.0.1312386: - version "0.0.1312386" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz#5ab824d6f1669ec6c6eb0fba047e73601d969052" - integrity sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA== - dezalgo@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" @@ -7952,17 +7832,6 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -escodegen@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" - integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionalDependencies: - source-map "~0.6.1" - eslint-config-cozy-app@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/eslint-config-cozy-app/-/eslint-config-cozy-app-2.0.0.tgz#2b8ee3f4ee695d1f8503e76018b771bfdfc0d629" @@ -8601,17 +8470,6 @@ extglob@^2.0.2, extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" - integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== - dependencies: - debug "^4.1.1" - get-stream "^5.1.0" - yauzl "^2.10.0" - optionalDependencies: - "@types/yauzl" "^2.9.1" - extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -8632,7 +8490,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== -fast-fifo@^1.1.0, fast-fifo@^1.2.0, fast-fifo@^1.3.2: +fast-fifo@^1.1.0, fast-fifo@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== @@ -8738,13 +8596,6 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== - dependencies: - pend "~1.2.0" - figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" @@ -9118,15 +8969,6 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^11.2.0: - version "11.2.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" - integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - fs-extra@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -9378,7 +9220,7 @@ get-stream@^4.0.0: dependencies: pump "^3.0.0" -get-stream@^5.0.0, get-stream@^5.1.0: +get-stream@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== @@ -9412,16 +9254,6 @@ get-symbol-description@^1.0.2: es-errors "^1.3.0" get-intrinsic "^1.2.4" -get-uri@^6.0.1: - version "6.0.3" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.3.tgz#0d26697bc13cf91092e519aa63aa60ee5b6f385a" - integrity sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw== - dependencies: - basic-ftp "^5.0.2" - data-uri-to-buffer "^6.0.2" - debug "^4.3.4" - fs-extra "^11.2.0" - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -10247,14 +10079,6 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1: - version "7.0.2" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" - integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== - dependencies: - agent-base "^7.1.0" - debug "^4.3.4" - http-proxy-middleware@0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" @@ -10331,14 +10155,6 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.3, https-proxy-agent@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" - integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== - dependencies: - agent-base "^7.0.2" - debug "4" - human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -10679,14 +10495,6 @@ invert-kv@^2.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== -ip-address@^9.0.5: - version "9.0.5" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" - integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== - dependencies: - jsbn "1.1.0" - sprintf-js "^1.1.3" - ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -11976,11 +11784,6 @@ js-yaml@~3.7.0: argparse "^1.0.7" esprima "^2.6.0" -jsbn@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" - integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== - jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -13026,11 +12829,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@^7.14.1: - version "7.18.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" - integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== - lru-cache@^7.3.1, lru-cache@^7.5.1, lru-cache@^7.7.1: version "7.7.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.7.1.tgz#03d2846b1ad2dcc7931a9340b8711d9798fcb0c6" @@ -13712,11 +13510,6 @@ mitt@1.1.2: resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.1.2.tgz#380e61480d6a615b660f07abb60d51e0a4e4bed6" integrity sha1-OA5hSA1qYVtmDwertg1R4KTkvtY= -mitt@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" - integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== - mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" @@ -13952,11 +13745,6 @@ nerf-dart@^1.0.0: resolved "https://registry.yarnpkg.com/nerf-dart/-/nerf-dart-1.0.0.tgz#e6dab7febf5ad816ea81cf5c629c5a0ebde72c1a" integrity sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo= -netmask@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" - integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== - nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -15098,28 +14886,6 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pac-proxy-agent@^7.0.1: - version "7.0.2" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz#0fb02496bd9fb8ae7eb11cfd98386daaac442f58" - integrity sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg== - dependencies: - "@tootallnate/quickjs-emscripten" "^0.23.0" - agent-base "^7.0.2" - debug "^4.3.4" - get-uri "^6.0.1" - http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.5" - pac-resolver "^7.0.1" - socks-proxy-agent "^8.0.4" - -pac-resolver@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.1.tgz#54675558ea368b64d210fd9c92a640b5f3b8abb6" - integrity sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg== - dependencies: - degenerator "^5.0.0" - netmask "^2.0.2" - package-json@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" @@ -15411,11 +15177,6 @@ pdfjs-dist@2.12.313: resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-2.12.313.tgz#62f2273737bb956267ae2e02cdfaddcb1099819c" integrity sha512-1x6iXO4Qnv6Eb+YFdN5JdUzt4pAkxSp3aLAYPX93eQCyg/m7QFzXVWJHJVtoW48CI8HCXju4dSkhQZwoheL5mA== -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -16386,7 +16147,7 @@ process@~0.5.1: resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8= -progress@^2.0.0, progress@^2.0.3: +progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -16474,20 +16235,6 @@ proxy-addr@~2.0.5: forwarded "~0.1.2" ipaddr.js "1.9.0" -proxy-agent@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.4.0.tgz#b4e2dd51dee2b377748aef8d45604c2d7608652d" - integrity sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ== - dependencies: - agent-base "^7.0.2" - debug "^4.3.4" - http-proxy-agent "^7.0.1" - https-proxy-agent "^7.0.3" - lru-cache "^7.14.1" - pac-proxy-agent "^7.0.1" - proxy-from-env "^1.1.0" - socks-proxy-agent "^8.0.2" - proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -16577,17 +16324,6 @@ pupa@^3.1.0: dependencies: escape-goat "^4.0.0" -puppeteer-core@22.15.0: - version "22.15.0" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-22.15.0.tgz#c76926cce5dbc177572797a9dacc325c313fa91a" - integrity sha512-cHArnywCiAAVXa3t4GGL2vttNxh7GqXtIYGym99egkNJ3oG//wL9LkvO4WE8W1TJe95t1F1ocu9X4xWaGsOKOA== - dependencies: - "@puppeteer/browsers" "2.3.0" - chromium-bidi "0.6.3" - debug "^4.3.6" - devtools-protocol "0.0.1312386" - ws "^8.18.0" - q-i@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/q-i/-/q-i-2.0.1.tgz#fec7e3f0e713f3467358bb5ac80bcc4c115187d6" @@ -18539,11 +18275,6 @@ semver@^7.5.4: dependencies: lru-cache "^6.0.0" -semver@^7.6.3: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -18935,15 +18666,6 @@ socks-proxy-agent@^6.1.1: debug "^4.3.1" socks "^2.6.1" -socks-proxy-agent@^8.0.2, socks-proxy-agent@^8.0.4: - version "8.0.4" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz#9071dca17af95f483300316f4b063578fa0db08c" - integrity sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw== - dependencies: - agent-base "^7.1.1" - debug "^4.3.4" - socks "^2.8.3" - socks@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" @@ -18952,14 +18674,6 @@ socks@^2.6.1: ip "^1.1.5" smart-buffer "^4.2.0" -socks@^2.8.3: - version "2.8.3" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" - integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== - dependencies: - ip-address "^9.0.5" - smart-buffer "^4.2.0" - sort-keys@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" @@ -19125,11 +18839,6 @@ split@^1.0.0: dependencies: through "2" -sprintf-js@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" - integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -19276,17 +18985,6 @@ streamx@^2.15.0: fast-fifo "^1.1.0" queue-tick "^1.0.1" -streamx@^2.18.0: - version "2.18.0" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.18.0.tgz#5bc1a51eb412a667ebfdcd4e6cf6a6fc65721ac7" - integrity sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ== - dependencies: - fast-fifo "^1.3.2" - queue-tick "^1.0.1" - text-decoder "^1.1.0" - optionalDependencies: - bare-events "^2.2.0" - strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" @@ -19921,17 +19619,6 @@ tar-fs@^3.0.4: pump "^3.0.0" tar-stream "^3.1.5" -tar-fs@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.6.tgz#eaccd3a67d5672f09ca8e8f9c3d2b89fa173f217" - integrity sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w== - dependencies: - pump "^3.0.0" - tar-stream "^3.1.5" - optionalDependencies: - bare-fs "^2.1.1" - bare-path "^2.1.0" - tar-stream@^2.1.4: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" @@ -20072,13 +19759,6 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" -text-decoder@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.1.1.tgz#5df9c224cebac4a7977720b9f083f9efa1aefde8" - integrity sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA== - dependencies: - b4a "^1.6.4" - text-extensions@^1.0.0: version "1.9.0" resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" @@ -20109,7 +19789,7 @@ through2@^4.0.0: dependencies: readable-stream "3" -through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8: +through@2, "through@>=2.2.7 <3", through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -20572,14 +20252,6 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -unbzip2-stream@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - undefsafe@^2.0.2: version "2.0.5" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" @@ -21052,11 +20724,6 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" -urlpattern-polyfill@10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz#f0a03a97bfb03cdf33553e5e79a2aadd22cac8ec" - integrity sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg== - use-callback-ref@^1.2.3: version "1.2.4" resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.4.tgz#d86d1577bfd0b955b6e04aaf5971025f406bea3c" @@ -21483,6 +21150,11 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" +whatwg-fetch@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.5.0.tgz#605a2cd0a7146e5db141e29d1c62ab84c0c4c868" + integrity sha512-jXkLtsR42xhXg7akoDKvKWE40eJeI+2KZqcp2h3NsOrRnDvtWX36KcKl30dy+hxECivdk2BVUHVNrPtoMBUx6A== + whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" @@ -21726,11 +21398,6 @@ ws@^7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== -ws@^8.18.0: - version "8.18.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" - integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== - x-is-string@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" @@ -21833,11 +21500,6 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.7: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" @@ -21928,19 +21590,6 @@ yargs@^16.1.0, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.7.2: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - yargs@^3.32.0: version "3.32.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" @@ -21954,14 +21603,6 @@ yargs@^3.32.0: window-size "^0.1.4" y18n "^3.2.0" -yauzl@^2.10.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - yup@^0.32.11: version "0.32.11" resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5" @@ -21974,8 +21615,3 @@ yup@^0.32.11: nanoclone "^0.2.1" property-expr "^2.0.4" toposort "^2.0.2" - -zod@3.23.8: - version "3.23.8" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" - integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== From 9471b033f0da55db0634cdffc0e7ef4719ac35f1 Mon Sep 17 00:00:00 2001 From: JF-Cozy Date: Thu, 24 Oct 2024 14:16:09 +0200 Subject: [PATCH 2/3] feat(providers): Add Encrypted from cozy-viewer and remove it from there --- react/providers/Encrypted/index.jsx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 react/providers/Encrypted/index.jsx diff --git a/react/providers/Encrypted/index.jsx b/react/providers/Encrypted/index.jsx new file mode 100644 index 0000000000..568077a2c6 --- /dev/null +++ b/react/providers/Encrypted/index.jsx @@ -0,0 +1,25 @@ +import React, { useContext } from 'react' + +export const EncryptedContext = React.createContext() + +export const useEncrypted = () => { + const context = useContext(EncryptedContext) + + if (!context) { + throw new Error('useEncrypted must be used within a EncryptedProvider') + } + return context +} + +const EncryptedProvider = ({ url, children }) => { + const contextValue = { + url + } + return ( + + {children} + + ) +} + +export default React.memo(EncryptedProvider) From ff4a74680b8a656a99da21063e5670851038d9b3 Mon Sep 17 00:00:00 2001 From: JF-Cozy Date: Thu, 24 Oct 2024 14:17:55 +0200 Subject: [PATCH 3/3] feat: Remove Viewer BREAKING CHANGE: if you want to use the Viewer, you must import components from `cozy-viewer`. So replace `import Something from 'cozy-ui/transpiled/react/Viewer/...'` by `import Something from 'cozy-viewer/...'` --- docs/styleguide.config.js | 3 +- react/FileImageLoader/Readme.md | 69 +++- react/FileImageLoader/index.jsx | 6 +- react/FileImageLoader/index.spec.jsx | 2 +- react/Viewer/Footer/BottomSheetContent.jsx | 29 -- react/Viewer/Footer/DownloadButton.jsx | 67 ---- react/Viewer/Footer/FooterActionButtons.jsx | 22 -- .../Footer/FooterActionButtons.spec.jsx | 30 -- react/Viewer/Footer/FooterContent.jsx | 99 ----- react/Viewer/Footer/ForwardButton.jsx | 95 ----- react/Viewer/Footer/ForwardButton.spec.jsx | 87 ----- .../Viewer/Footer/ForwardOrDownloadButton.jsx | 24 -- react/Viewer/Footer/Sharing.jsx | 60 --- react/Viewer/Footer/helpers.js | 107 ------ react/Viewer/Footer/helpers.spec.js | 77 ---- react/Viewer/NoViewer/DownloadButton.jsx | 28 -- react/Viewer/NoViewer/FileIcon.jsx | 46 --- react/Viewer/NoViewer/NoViewer.jsx | 29 -- react/Viewer/NoViewer/NoViewer.spec.jsx | 44 --- .../__snapshots__/NoViewer.spec.jsx.snap | 82 ---- react/Viewer/NoViewer/index.jsx | 1 - react/Viewer/Panel/ActionMenuDesktop.jsx | 66 ---- react/Viewer/Panel/ActionMenuMobile.jsx | 74 ---- react/Viewer/Panel/ActionMenuWrapper.jsx | 104 ------ react/Viewer/Panel/Certifications.jsx | 62 --- react/Viewer/Panel/PanelContent.jsx | 49 --- react/Viewer/Panel/Qualification.jsx | 114 ------ .../Panel/QualificationListItemContact.jsx | 85 ----- .../Panel/QualificationListItemDate.jsx | 77 ---- .../QualificationListItemInformation.jsx | 68 ---- .../QualificationListItemInformation.spec.jsx | 73 ---- .../Panel/QualificationListItemOther.jsx | 61 --- .../Panel/QualificationListItemText.jsx | 30 -- react/Viewer/Panel/getPanelBlocks.jsx | 56 --- react/Viewer/Panel/getPanelBlocks.spec.jsx | 79 ---- react/Viewer/Panel/styles.styl | 13 - react/Viewer/Readme.md | 352 ------------------ react/Viewer/Viewer.jsx | 134 ------- react/Viewer/ViewerContainer.jsx | 169 --------- react/Viewer/ViewerExposer.js | 3 - react/Viewer/ViewerInformationsWrapper.jsx | 69 ---- .../Viewer/ViewerInformationsWrapper.spec.jsx | 63 ---- .../Viewer/ViewerWithCustomPanelAndFooter.jsx | 55 --- react/Viewer/ViewersByFile/AudioViewer.jsx | 21 -- .../Viewer/ViewersByFile/AudioViewer.spec.jsx | 39 -- .../Viewer/ViewersByFile/BlankPaperViewer.jsx | 46 --- react/Viewer/ViewersByFile/ImageViewer.jsx | 330 ---------------- .../Viewer/ViewersByFile/ImageViewer.spec.jsx | 70 ---- .../Viewer/ViewersByFile/NoNetworkViewer.jsx | 17 - .../Viewer/ViewersByFile/OnlyOfficeViewer.jsx | 28 -- react/Viewer/ViewersByFile/PdfJsViewer.jsx | 210 ----------- .../Viewer/ViewersByFile/PdfJsViewer.spec.jsx | 160 -------- .../Viewer/ViewersByFile/PdfMobileViewer.jsx | 106 ------ .../ViewersByFile/PdfMobileViewer.spec.jsx | 76 ---- react/Viewer/ViewersByFile/ShortcutViewer.jsx | 38 -- .../ViewersByFile/ShortcutViewer.spec.jsx | 32 -- react/Viewer/ViewersByFile/TextViewer.jsx | 126 ------- .../Viewer/ViewersByFile/TextViewer.spec.jsx | 118 ------ react/Viewer/ViewersByFile/VideoViewer.jsx | 13 - .../Viewer/ViewersByFile/VideoViewer.spec.jsx | 39 -- .../__snapshots__/AudioViewer.spec.jsx.snap | 43 --- .../ShortcutViewer.spec.jsx.snap | 57 --- .../__snapshots__/TextViewer.spec.jsx.snap | 100 ----- .../__snapshots__/VideoViewer.spec.jsx.snap | 19 - react/Viewer/ViewersByFile/styles.styl | 87 ----- react/Viewer/assets/IlluGenericNewPage.svg | 10 - react/Viewer/components/ExpirationAlert.jsx | 86 ----- .../components/ExpirationAnnotation.jsx | 40 -- react/Viewer/components/Footer.jsx | 13 - react/Viewer/components/InformationPanel.jsx | 26 -- react/Viewer/components/Navigation.jsx | 39 -- react/Viewer/components/PdfToolbarButton.jsx | 26 -- react/Viewer/components/PrintButton.jsx | 90 ----- react/Viewer/components/Toolbar.jsx | 111 ------ react/Viewer/components/ToolbarButtons.jsx | 11 - react/Viewer/components/ToolbarFilePath.jsx | 61 --- react/Viewer/components/ViewerByFile.jsx | 112 ------ react/Viewer/components/ViewerByFile.spec.jsx | 100 ----- react/Viewer/components/ViewerControls.jsx | 190 ---------- .../Viewer/components/ViewerControls.spec.jsx | 54 --- react/Viewer/components/ViewerSpinner.jsx | 17 - react/Viewer/components/styles.styl | 93 ----- react/Viewer/docs/DemoProvider.jsx | 90 ----- react/Viewer/helpers.js | 131 ------- react/Viewer/helpers.spec.js | 136 ------- react/Viewer/hoc/withFileUrl.jsx | 93 ----- react/Viewer/hoc/withViewerLocales.jsx | 4 - .../Viewer/hooks/useReferencedContactName.jsx | 26 -- react/Viewer/index.jsx | 12 - react/Viewer/locales/en.json | 66 ---- react/Viewer/locales/fr.json | 66 ---- react/Viewer/locales/index.js | 4 - react/Viewer/proptypes.js | 12 - react/Viewer/providers/ActionMenuProvider.jsx | 35 -- react/Viewer/providers/EncryptedProvider.jsx | 25 -- react/Viewer/queries.js | 20 - react/Viewer/styles.styl | 22 -- react/Viewer/vars.styl | 6 - react/index.js | 1 - 99 files changed, 71 insertions(+), 6395 deletions(-) delete mode 100644 react/Viewer/Footer/BottomSheetContent.jsx delete mode 100644 react/Viewer/Footer/DownloadButton.jsx delete mode 100644 react/Viewer/Footer/FooterActionButtons.jsx delete mode 100644 react/Viewer/Footer/FooterActionButtons.spec.jsx delete mode 100644 react/Viewer/Footer/FooterContent.jsx delete mode 100644 react/Viewer/Footer/ForwardButton.jsx delete mode 100644 react/Viewer/Footer/ForwardButton.spec.jsx delete mode 100644 react/Viewer/Footer/ForwardOrDownloadButton.jsx delete mode 100644 react/Viewer/Footer/Sharing.jsx delete mode 100644 react/Viewer/Footer/helpers.js delete mode 100644 react/Viewer/Footer/helpers.spec.js delete mode 100644 react/Viewer/NoViewer/DownloadButton.jsx delete mode 100644 react/Viewer/NoViewer/FileIcon.jsx delete mode 100644 react/Viewer/NoViewer/NoViewer.jsx delete mode 100644 react/Viewer/NoViewer/NoViewer.spec.jsx delete mode 100644 react/Viewer/NoViewer/__snapshots__/NoViewer.spec.jsx.snap delete mode 100644 react/Viewer/NoViewer/index.jsx delete mode 100644 react/Viewer/Panel/ActionMenuDesktop.jsx delete mode 100644 react/Viewer/Panel/ActionMenuMobile.jsx delete mode 100644 react/Viewer/Panel/ActionMenuWrapper.jsx delete mode 100644 react/Viewer/Panel/Certifications.jsx delete mode 100644 react/Viewer/Panel/PanelContent.jsx delete mode 100644 react/Viewer/Panel/Qualification.jsx delete mode 100644 react/Viewer/Panel/QualificationListItemContact.jsx delete mode 100644 react/Viewer/Panel/QualificationListItemDate.jsx delete mode 100644 react/Viewer/Panel/QualificationListItemInformation.jsx delete mode 100644 react/Viewer/Panel/QualificationListItemInformation.spec.jsx delete mode 100644 react/Viewer/Panel/QualificationListItemOther.jsx delete mode 100644 react/Viewer/Panel/QualificationListItemText.jsx delete mode 100644 react/Viewer/Panel/getPanelBlocks.jsx delete mode 100644 react/Viewer/Panel/getPanelBlocks.spec.jsx delete mode 100644 react/Viewer/Panel/styles.styl delete mode 100644 react/Viewer/Readme.md delete mode 100644 react/Viewer/Viewer.jsx delete mode 100644 react/Viewer/ViewerContainer.jsx delete mode 100644 react/Viewer/ViewerExposer.js delete mode 100644 react/Viewer/ViewerInformationsWrapper.jsx delete mode 100644 react/Viewer/ViewerInformationsWrapper.spec.jsx delete mode 100644 react/Viewer/ViewerWithCustomPanelAndFooter.jsx delete mode 100644 react/Viewer/ViewersByFile/AudioViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/AudioViewer.spec.jsx delete mode 100644 react/Viewer/ViewersByFile/BlankPaperViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/ImageViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/ImageViewer.spec.jsx delete mode 100644 react/Viewer/ViewersByFile/NoNetworkViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/OnlyOfficeViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/PdfJsViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/PdfJsViewer.spec.jsx delete mode 100644 react/Viewer/ViewersByFile/PdfMobileViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/PdfMobileViewer.spec.jsx delete mode 100644 react/Viewer/ViewersByFile/ShortcutViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/ShortcutViewer.spec.jsx delete mode 100644 react/Viewer/ViewersByFile/TextViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/TextViewer.spec.jsx delete mode 100644 react/Viewer/ViewersByFile/VideoViewer.jsx delete mode 100644 react/Viewer/ViewersByFile/VideoViewer.spec.jsx delete mode 100644 react/Viewer/ViewersByFile/__snapshots__/AudioViewer.spec.jsx.snap delete mode 100644 react/Viewer/ViewersByFile/__snapshots__/ShortcutViewer.spec.jsx.snap delete mode 100644 react/Viewer/ViewersByFile/__snapshots__/TextViewer.spec.jsx.snap delete mode 100644 react/Viewer/ViewersByFile/__snapshots__/VideoViewer.spec.jsx.snap delete mode 100644 react/Viewer/ViewersByFile/styles.styl delete mode 100644 react/Viewer/assets/IlluGenericNewPage.svg delete mode 100644 react/Viewer/components/ExpirationAlert.jsx delete mode 100644 react/Viewer/components/ExpirationAnnotation.jsx delete mode 100644 react/Viewer/components/Footer.jsx delete mode 100644 react/Viewer/components/InformationPanel.jsx delete mode 100644 react/Viewer/components/Navigation.jsx delete mode 100644 react/Viewer/components/PdfToolbarButton.jsx delete mode 100644 react/Viewer/components/PrintButton.jsx delete mode 100644 react/Viewer/components/Toolbar.jsx delete mode 100644 react/Viewer/components/ToolbarButtons.jsx delete mode 100644 react/Viewer/components/ToolbarFilePath.jsx delete mode 100644 react/Viewer/components/ViewerByFile.jsx delete mode 100644 react/Viewer/components/ViewerByFile.spec.jsx delete mode 100644 react/Viewer/components/ViewerControls.jsx delete mode 100644 react/Viewer/components/ViewerControls.spec.jsx delete mode 100644 react/Viewer/components/ViewerSpinner.jsx delete mode 100644 react/Viewer/components/styles.styl delete mode 100644 react/Viewer/docs/DemoProvider.jsx delete mode 100644 react/Viewer/helpers.js delete mode 100644 react/Viewer/helpers.spec.js delete mode 100644 react/Viewer/hoc/withFileUrl.jsx delete mode 100644 react/Viewer/hoc/withViewerLocales.jsx delete mode 100644 react/Viewer/hooks/useReferencedContactName.jsx delete mode 100644 react/Viewer/index.jsx delete mode 100644 react/Viewer/locales/en.json delete mode 100644 react/Viewer/locales/fr.json delete mode 100644 react/Viewer/locales/index.js delete mode 100644 react/Viewer/proptypes.js delete mode 100644 react/Viewer/providers/ActionMenuProvider.jsx delete mode 100644 react/Viewer/providers/EncryptedProvider.jsx delete mode 100644 react/Viewer/queries.js delete mode 100644 react/Viewer/styles.styl delete mode 100644 react/Viewer/vars.styl diff --git a/docs/styleguide.config.js b/docs/styleguide.config.js index eb5958852c..4aeb258b7a 100644 --- a/docs/styleguide.config.js +++ b/docs/styleguide.config.js @@ -95,8 +95,7 @@ module.exports = { '../react/SquareAppIcon', '../react/QualificationGrid', '../react/QualificationItem', - '../react/UploadQueue', - '../react/Viewer' + '../react/UploadQueue' ] }, { diff --git a/react/FileImageLoader/Readme.md b/react/FileImageLoader/Readme.md index 552c0b4a33..9a7d202cd0 100644 --- a/react/FileImageLoader/Readme.md +++ b/react/FileImageLoader/Readme.md @@ -3,14 +3,77 @@ A component to get the image in `links` prop of a file, according to its class (could be `image` or `pdf`). ```jsx -import DemoProvider from 'cozy-ui/transpiled/react/Viewer/docs/DemoProvider' - +import DemoProvider from 'cozy-ui/transpiled/react/providers/DemoProvider' import FileImageLoader from 'cozy-ui/transpiled/react/FileImageLoader' import Icon from 'cozy-ui/transpiled/react/Icon' import FileDuotoneIcon from "cozy-ui/transpiled/react/Icons/FileDuotone" import BankIcon from "cozy-ui/transpiled/react/Icons/Bank" import CloudWallpaper from 'cozy-ui/docs/cloud-wallpaper.jpg' +const demoTextFileResponse = { + text: () => new Promise(resolve => resolve('Hello World !')) +} + +const demoFilesByClass = { + pdf: 'https://raw.githubusercontent.com/rospdf/pdf-php/2ccf7591fc2f18e63342ebfedad7997b08c34ed2/readme.pdf', + audio: 'https://viewerdemo.cozycloud.cc/Z.mp3', + video: 'https://viewerdemo.cozycloud.cc/Nextcloud.mp4', + text: 'https://viewerdemo.cozycloud.cc/notes.md' +} + +const mockClient = { + plugins: { + realtime: { + subscribe: () => {}, + unsubscribe: () => {}, + unsubscribeAll: () => {} + } + }, + on: () => {}, + collection: () => ({ + getDownloadLinkById: id => + new Promise(resolve => resolve(demoFilesByClass[id])), + download: () => + alert( + "This is a demo, there's no actual Cozy to download the file from ¯\\_(ツ)_/¯" + ), + get: () => + new Promise(resolve => + resolve({ + data: { + links: { + large: CloudWallpaper + } + } + }) + ) + }), + getStackClient: () => ({ + uri: '', + fetch: () => new Promise(resolve => resolve(demoTextFileResponse)) + }), + getClient: () => mockClient, + store: { + getState: () => {}, + subscribe: () => {}, + unsubscribe: () => {} + }, + getQueryFromState: queryName => { + if (queryName === 'io.cozy.files/parent_folder') { + return { + data: { + _id: 'parent_id', + path: '/Parent' + } + } + } + }, + query: () => ({ + data: [{ attributes: { slug: 'mespapiers' }, links: { related: '' } }] + }), + getInstanceOptions: () => ({ app: { slug: 'mespapiers' }, subdomain: 'flat' }) +} + const file = { _id: 'image', class: 'image', @@ -31,7 +94,7 @@ const FallbackComp = () => { ; - + ({ ...jest.requireActual('./checkImageSource'), diff --git a/react/Viewer/Footer/BottomSheetContent.jsx b/react/Viewer/Footer/BottomSheetContent.jsx deleted file mode 100644 index 545f180016..0000000000 --- a/react/Viewer/Footer/BottomSheetContent.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import PropTypes from 'prop-types' -import React from 'react' - -import { BottomSheetItem } from '../../BottomSheet' -import getPanelBlocks, { getPanelBlocksSpecs } from '../Panel/getPanelBlocks' - -const BottomSheetContent = ({ file, isPublic }) => { - const panelBlocks = getPanelBlocks({ - panelBlocksSpecs: getPanelBlocksSpecs(isPublic), - file - }) - - return panelBlocks.map((PanelBlock, index) => ( - - - - )) -} - -BottomSheetContent.propTypes = { - file: PropTypes.object.isRequired, - isPublic: PropTypes.bool -} - -export default BottomSheetContent diff --git a/react/Viewer/Footer/DownloadButton.jsx b/react/Viewer/Footer/DownloadButton.jsx deleted file mode 100644 index 2dd9c1a72f..0000000000 --- a/react/Viewer/Footer/DownloadButton.jsx +++ /dev/null @@ -1,67 +0,0 @@ -import PropTypes from 'prop-types' -import React from 'react' - -import { useClient } from 'cozy-client' - -import Button from '../../Buttons' -import Icon from '../../Icon' -import IconButton from '../../IconButton' -import DownloadIcon from '../../Icons/Download' -import Alerter from '../../deprecated/Alerter' -import { useI18n } from '../../providers/I18n' - -const DownloadButton = ({ file, variant }) => { - const client = useClient() - const { t } = useI18n() - - const icon = - const label = t('Viewer.download') - - const handleClick = async () => { - try { - await client.collection('io.cozy.files').download(file) - } catch (error) { - Alerter.info('Viewer.error.generic') - } - } - - if (variant === 'iconButton') { - return ( - - {icon} - - ) - } - - if (variant === 'buttonIcon') { - return ( - - - -`; - -exports[`NoViewer should render the viewer with specific extra content 1`] = ` -
-
- - - - - - -

- notSupported.xyz -

-
- with specific extra content -
-
-
-`; diff --git a/react/Viewer/NoViewer/index.jsx b/react/Viewer/NoViewer/index.jsx deleted file mode 100644 index 2d5892c351..0000000000 --- a/react/Viewer/NoViewer/index.jsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from './NoViewer' diff --git a/react/Viewer/Panel/ActionMenuDesktop.jsx b/react/Viewer/Panel/ActionMenuDesktop.jsx deleted file mode 100644 index 0400c3b9ee..0000000000 --- a/react/Viewer/Panel/ActionMenuDesktop.jsx +++ /dev/null @@ -1,66 +0,0 @@ -import PropTypes from 'prop-types' -import React, { forwardRef } from 'react' - -import styles from './styles.styl' -import AppLinker from '../../AppLinker' -import Icon from '../../Icon' -import Copy from '../../Icons/Copy' -import Edit from '../../Icons/Rename' -import Typography from '../../Typography' -import ActionMenu, { ActionMenuItem } from '../../deprecated/ActionMenu' -import { useI18n } from '../../providers/I18n' - -const ActionMenuDesktop = forwardRef( - ({ onClose, isEditable, actions, appLink, appSlug }, ref) => { - const { handleCopy, handleEdit } = actions - const { t } = useI18n() - - return ( - - {isEditable && ( - - {({ onClick, href }) => { - return ( - handleEdit(onClick)}> - } - > - - {t(`Viewer.panel.qualification.actions.edit`)} - - - - ) - }} - - )} - } - > - - {t(`Viewer.panel.qualification.actions.copy`)} - - - - ) - } -) -ActionMenuDesktop.displayName = 'ActionMenuDesktop' - -ActionMenuDesktop.propTypes = { - onClose: PropTypes.func, - isEditable: PropTypes.bool, - actions: PropTypes.shape({ - handleCopy: PropTypes.func, - handleEdit: PropTypes.func - }), - appLink: PropTypes.string, - appSlug: PropTypes.string -} - -export default ActionMenuDesktop diff --git a/react/Viewer/Panel/ActionMenuMobile.jsx b/react/Viewer/Panel/ActionMenuMobile.jsx deleted file mode 100644 index 29bce2a8e1..0000000000 --- a/react/Viewer/Panel/ActionMenuMobile.jsx +++ /dev/null @@ -1,74 +0,0 @@ -import PropTypes from 'prop-types' -import React from 'react' - -import AppLinker from '../../AppLinker' -import BottomSheet, { BottomSheetItem } from '../../BottomSheet' -import Icon from '../../Icon' -import Copy from '../../Icons/Copy' -import Edit from '../../Icons/Rename' -import List from '../../List' -import ListItem from '../../ListItem' -import ListItemIcon from '../../ListItemIcon' -import ListItemText from '../../ListItemText' -import { useI18n } from '../../providers/I18n' - -const ActionMenuMobile = ({ - onClose, - isEditable, - actions, - appLink, - appSlug -}) => { - const { t } = useI18n() - const { handleCopy, handleEdit } = actions - - return ( - - - - {isEditable && ( - - {({ onClick, href }) => { - return ( - handleEdit(onClick)} - > - - - - - - ) - }} - - )} - - - - - - - - - - ) -} - -ActionMenuMobile.propTypes = { - onClose: PropTypes.func, - isEditable: PropTypes.bool, - actions: PropTypes.shape({ - handleCopy: PropTypes.func, - handleEdit: PropTypes.func - }), - appLink: PropTypes.string -} - -export default ActionMenuMobile diff --git a/react/Viewer/Panel/ActionMenuWrapper.jsx b/react/Viewer/Panel/ActionMenuWrapper.jsx deleted file mode 100644 index bfcf02de2d..0000000000 --- a/react/Viewer/Panel/ActionMenuWrapper.jsx +++ /dev/null @@ -1,104 +0,0 @@ -import PropTypes from 'prop-types' -import React, { forwardRef } from 'react' - -import { useAppLinkWithStoreFallback, useClient } from 'cozy-client' - -import ActionMenuDesktop from './ActionMenuDesktop' -import ActionMenuMobile from './ActionMenuMobile' -import { useAlert } from '../../providers/Alert' -import useBreakpoints from '../../providers/Breakpoints' -import { useI18n } from '../../providers/I18n' -import { - buildEditAttributePath, - isEditableAttribute, - getCurrentModel -} from '../helpers' -import useActionMenuContext from '../providers/ActionMenuProvider' - -const mespapiersAppSlug = 'mespapiers' - -const ActionMenuWrapper = forwardRef(({ onClose, file, optionFile }, ref) => { - const { name, value } = optionFile - const editPathByModelProps = useActionMenuContext() - const { isMobile } = useBreakpoints() - const { t } = useI18n() - const { showAlert } = useAlert() - const client = useClient() - - const currentModel = getCurrentModel(name) - const editPath = buildEditAttributePath( - editPathByModelProps, - currentModel, - optionFile.name - ) - - const { fetchStatus, url } = useAppLinkWithStoreFallback( - mespapiersAppSlug, - client, - editPath - ) - const isAppLinkLoaded = fetchStatus === 'loaded' - const isEditable = Boolean(editPath) && isEditableAttribute(name, file) - - const handleCopy = async () => { - try { - await navigator.clipboard.writeText(value) - showAlert({ - message: t(`Viewer.snackbar.copiedToClipboard.success`), - severity: 'success', - variant: 'filled', - icon: false - }) - } catch (error) { - showAlert({ - message: t(`Viewer.snackbar.copiedToClipboard.error`), - severity: 'error', - variant: 'filled', - icon: false - }) - } - onClose() - } - - const handleEdit = cb => { - if (isAppLinkLoaded) { - onClose() - cb && cb() - } - } - - if (isMobile) { - return ( - - ) - } - - return ( - - ) -}) -ActionMenuWrapper.displayName = 'ActionMenuWrapper' - -ActionMenuWrapper.propTypes = { - onClose: PropTypes.func, - file: PropTypes.object, - optionFile: PropTypes.shape({ - name: PropTypes.string, - value: PropTypes.string - }) -} - -export default ActionMenuWrapper diff --git a/react/Viewer/Panel/Certifications.jsx b/react/Viewer/Panel/Certifications.jsx deleted file mode 100644 index 089ccc55b5..0000000000 --- a/react/Viewer/Panel/Certifications.jsx +++ /dev/null @@ -1,62 +0,0 @@ -import has from 'lodash/has' -import PropTypes from 'prop-types' -import React from 'react' - -import Icon, { iconPropType } from '../../Icon' -import CarbonCopyIcon from '../../Icons/CarbonCopy' -import SafeIcon from '../../Icons/Safe' -import Typography from '../../Typography' -import { Media, Img, Bd } from '../../deprecated/Media' -import { withViewerLocales } from '../hoc/withViewerLocales' - -const Certification = ({ icon, title, caption }) => { - return ( -
- - - - - - {title} - - - {caption} -
- ) -} - -Certification.propTypes = { - icon: iconPropType.isRequired, - title: PropTypes.string.isRequired, - caption: PropTypes.string.isRequired -} - -const Certifications = ({ file, t }) => { - const hasCarbonCopy = has(file, 'metadata.carbonCopy') - const hasElectronicSafe = has(file, 'metadata.electronicSafe') - - return ( - <> - {hasCarbonCopy && ( - - )} - {hasElectronicSafe && ( - - )} - - ) -} - -Certifications.propTypes = { - file: PropTypes.object.isRequired -} - -export default withViewerLocales(Certifications) diff --git a/react/Viewer/Panel/PanelContent.jsx b/react/Viewer/Panel/PanelContent.jsx deleted file mode 100644 index f91c66b17d..0000000000 --- a/react/Viewer/Panel/PanelContent.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import cx from 'classnames' -import PropTypes from 'prop-types' -import React from 'react' - -import getPanelBlocks, { getPanelBlocksSpecs } from './getPanelBlocks' -import Paper from '../../Paper' -import Stack from '../../Stack' -import Typography from '../../Typography' -import { withViewerLocales } from '../hoc/withViewerLocales' - -const PanelContent = ({ file, isPublic, t }) => { - const panelBlocks = getPanelBlocks({ - panelBlocksSpecs: getPanelBlocksSpecs(isPublic), - file - }) - - return ( - - - {t('Viewer.panel.title')} - - {panelBlocks.map((PanelBlock, index) => ( - - - - - - ))} - - ) -} - -PanelContent.propTypes = { - file: PropTypes.object.isRequired, - isPublic: PropTypes.bool -} - -export default withViewerLocales(PanelContent) diff --git a/react/Viewer/Panel/Qualification.jsx b/react/Viewer/Panel/Qualification.jsx deleted file mode 100644 index 0a49b719b9..0000000000 --- a/react/Viewer/Panel/Qualification.jsx +++ /dev/null @@ -1,114 +0,0 @@ -import PropTypes from 'prop-types' -import React, { useRef, useState, createRef, useMemo, useEffect } from 'react' - -import { - isExpiringSoon, - formatMetadataQualification, - KNOWN_BILLS_ATTRIBUTES_NAMES, - getMetadataQualificationType -} from 'cozy-client/dist/models/paper' - -import ActionMenuWrapper from './ActionMenuWrapper' -import QualificationListItemContact from './QualificationListItemContact' -import QualificationListItemDate from './QualificationListItemDate' -import QualificationListItemInformation from './QualificationListItemInformation' -import QualificationListItemOther from './QualificationListItemOther' -import List from '../../List' -import ExpirationAlert from '../components/ExpirationAlert' -import { withViewerLocales } from '../hoc/withViewerLocales' - -const ComponentFromMetadataQualificationType = { - contact: QualificationListItemContact, - date: QualificationListItemDate, - information: QualificationListItemInformation, - other: QualificationListItemOther, - bills: QualificationListItemInformation -} - -const isExpirationAlertHidden = file => { - return file?.metadata?.hideExpirationAlert ?? false -} - -const Qualification = ({ file }) => { - const { metadata = {} } = file - const actionBtnRef = useRef([]) - const [optionFile, setOptionFile] = useState({ - id: '', - name: '', - value: '' - }) - - const hideActionsMenu = () => { - setOptionFile({ id: '', name: '', value: '' }) - } - - const toggleActionsMenu = (id, name, value) => { - setOptionFile(prev => { - if (prev.value) return { id: '', name: '', value: '' } - return { id, name, value } - }) - } - - const formattedMetadataQualification = useMemo(() => { - const relatedBills = file.bills?.data?.[0] - - if (relatedBills) { - const formattedBillsMetadata = KNOWN_BILLS_ATTRIBUTES_NAMES.map( - attrName => ({ name: attrName, value: relatedBills[attrName] }) - ) - - return formatMetadataQualification(metadata).concat( - formattedBillsMetadata - ) - } - - return formatMetadataQualification(metadata) - }, [metadata, file.bills?.data]) - - useEffect(() => { - actionBtnRef.current = formattedMetadataQualification.map( - (_, idx) => actionBtnRef.current[idx] ?? createRef() - ) - }, [formattedMetadataQualification]) - - return ( - <> - {isExpiringSoon(file) && !isExpirationAlertHidden(file) && ( - - )} - - {formattedMetadataQualification.map((meta, idx) => { - const { name } = meta - const metadataQualificationType = getMetadataQualificationType(name) - const QualificationListItemComp = - ComponentFromMetadataQualificationType[metadataQualificationType] - - return ( - toggleActionsMenu(idx, name, val)} - /> - ) - })} - - {optionFile.name && ( - - )} - - - ) -} - -Qualification.propTypes = { - file: PropTypes.object.isRequired -} - -export default withViewerLocales(Qualification) diff --git a/react/Viewer/Panel/QualificationListItemContact.jsx b/react/Viewer/Panel/QualificationListItemContact.jsx deleted file mode 100644 index 92a5fa119f..0000000000 --- a/react/Viewer/Panel/QualificationListItemContact.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import PropTypes from 'prop-types' -import React, { useRef, useState } from 'react' - -import { - getTranslatedNameForContact, - formatContactValue -} from 'cozy-client/dist/models/paper' - -import ActionMenuWrapper from './ActionMenuWrapper' -import QualificationListItemText from './QualificationListItemText' -import Icon from '../../Icon' -import IconButton from '../../IconButton' -import Dots from '../../Icons/Dots' -import ListItem from '../../ListItem' -import ListItemSecondaryAction from '../../ListItemSecondaryAction' -import Spinner from '../../Spinner' -import { useI18n } from '../../providers/I18n' -import useReferencedContactName from '../hooks/useReferencedContactName' - -const QualificationListItemContact = ({ file }) => { - const { lang } = useI18n() - const actionBtnRef = useRef() - const [optionFile, setOptionFile] = useState({ - name: '', - value: '' - }) - - const hideActionsMenu = () => setOptionFile({ name: '', value: '' }) - const toggleActionsMenu = (name, value) => - setOptionFile(prev => { - if (prev.value) return { name: '', value: '' } - return { name, value } - }) - - const { contacts, isLoadingContacts } = useReferencedContactName(file) - - if (isLoadingContacts) { - return ( - - - - ) - } - - const formattedTitle = getTranslatedNameForContact({ lang }) - const formattedValue = formatContactValue(contacts) - - if (!isLoadingContacts && !formattedValue) { - return null - } - - return ( - <> - - - - toggleActionsMenu('contact', formattedValue)} - > - - - - - - {optionFile.value && ( - - )} - - ) -} - -QualificationListItemContact.propTypes = { - file: PropTypes.object.isRequired -} - -export default QualificationListItemContact diff --git a/react/Viewer/Panel/QualificationListItemDate.jsx b/react/Viewer/Panel/QualificationListItemDate.jsx deleted file mode 100644 index e5ec9c8eb2..0000000000 --- a/react/Viewer/Panel/QualificationListItemDate.jsx +++ /dev/null @@ -1,77 +0,0 @@ -import PropTypes from 'prop-types' -import React, { forwardRef } from 'react' - -import { - isExpired, - isExpiringSoon, - getTranslatedNameForDateMetadata, - formatDateMetadataValue -} from 'cozy-client/dist/models/paper' - -import QualificationListItemText from './QualificationListItemText' -import Icon from '../../Icon' -import IconButton from '../../IconButton' -import Dots from '../../Icons/Dots' -import ListItem from '../../ListItem' -import ListItemSecondaryAction from '../../ListItemSecondaryAction' -import Typography from '../../Typography' -import { useI18n } from '../../providers/I18n' -import ExpirationAnnotation from '../components/ExpirationAnnotation' - -const QualificationListItemDate = forwardRef( - ({ file, formattedMetadataQualification, toggleActionsMenu }, ref) => { - const { f, lang } = useI18n() - const { name, value } = formattedMetadataQualification - const formattedTitle = getTranslatedNameForDateMetadata(name, { lang }) - const formattedDate = formatDateMetadataValue(value, { - f, - lang - }) - const isExpirationDate = name === 'expirationDate' - - return ( - - - - {formattedDate} - - {isExpirationDate && (isExpired(file) || isExpiringSoon(file)) && ( - <> - - {' · '} - - - - )} - - } - disabled={!value} - /> - - toggleActionsMenu(formattedDate)} - > - - - - - ) - } -) - -QualificationListItemDate.displayName = 'QualificationListItemDate' - -QualificationListItemDate.propTypes = { - file: PropTypes.object.isRequired, - formattedMetadataQualification: PropTypes.shape({ - name: PropTypes.string, - value: PropTypes.string - }).isRequired, - toggleActionsMenu: PropTypes.func.isRequired -} - -export default QualificationListItemDate diff --git a/react/Viewer/Panel/QualificationListItemInformation.jsx b/react/Viewer/Panel/QualificationListItemInformation.jsx deleted file mode 100644 index 8832cf877f..0000000000 --- a/react/Viewer/Panel/QualificationListItemInformation.jsx +++ /dev/null @@ -1,68 +0,0 @@ -import PropTypes from 'prop-types' -import React, { forwardRef } from 'react' - -import { - getTranslatedNameForInformationMetadata, - formatInformationMetadataValue -} from 'cozy-client/dist/models/paper' - -import QualificationListItemText from './QualificationListItemText' -import Icon from '../../Icon' -import IconButton from '../../IconButton' -import Dots from '../../Icons/Dots' -import ListItem from '../../ListItem' -import ListItemSecondaryAction from '../../ListItemSecondaryAction' -import MidEllipsis from '../../MidEllipsis' -import { useI18n } from '../../providers/I18n' - -const QualificationListItemInformation = forwardRef( - ({ formattedMetadataQualification, file, toggleActionsMenu }, ref) => { - const { lang } = useI18n() - const { name, value } = formattedMetadataQualification - const qualificationLabel = file.metadata.qualification.label - - const formattedTitle = getTranslatedNameForInformationMetadata(name, { - lang, - qualificationLabel - }) - const formattedValue = formatInformationMetadataValue(value, { - lang, - name, - qualificationLabel - }) - - const titleComponent = - formattedTitle === name ? : formattedTitle - - return ( - - - - toggleActionsMenu(value)} - data-testid="toggleActionsMenuBtn" - > - - - - - ) - } -) - -QualificationListItemInformation.displayName = 'QualificationListItemNumber' - -QualificationListItemInformation.propTypes = { - formattedMetadataQualification: PropTypes.shape({ - name: PropTypes.string, - value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - }).isRequired, - toggleActionsMenu: PropTypes.func.isRequired -} - -export default QualificationListItemInformation diff --git a/react/Viewer/Panel/QualificationListItemInformation.spec.jsx b/react/Viewer/Panel/QualificationListItemInformation.spec.jsx deleted file mode 100644 index e865644b24..0000000000 --- a/react/Viewer/Panel/QualificationListItemInformation.spec.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import { fireEvent, render } from '@testing-library/react' -import React from 'react' - -import QualificationListItemInformation from './QualificationListItemInformation' - -jest.mock('../../providers/I18n', () => ({ - useI18n: jest.fn(() => ({ t: x => x })) -})) - -const setup = ({ - formattedMetadataQualification = {}, - toggleActionsMenu = jest.fn() -} = {}) => { - return render( - - ) -} - -describe('QualificationListItemInformation', () => { - describe('formattedMetadataQualification', () => { - it('should display default text if value is falsy', () => { - const formattedMetadataQualification = { name: 'country', value: '' } - const { getByText } = setup({ formattedMetadataQualification }) - - expect(getByText('No information')) - }) - // eslint-disable-next-line jest/no-focused-tests - it.only('should display current value if it is truthy', () => { - const formattedMetadataQualification = { - name: 'country', - value: 'Italie' - } - const { queryByText } = setup({ - formattedMetadataQualification - }) - - expect(queryByText('No information')).toBeNull() - expect(queryByText('Italie')).toBeInTheDocument() - }) - it('should display current value if it number type', () => { - const formattedMetadataQualification = { name: 'country', value: 0 } - const { queryByText } = setup({ - formattedMetadataQualification - }) - - expect(queryByText('No information')).toBeNull() - expect(queryByText('0')).toBeInTheDocument() - }) - }) - describe('toggleActionsMenu', () => { - it('should call toggleActionsMenu with current value on click it', () => { - const formattedMetadataQualification = { - name: 'country', - value: 'Italie' - } - const toggleActionsMenu = jest.fn() - const { getByTestId } = setup({ - toggleActionsMenu, - formattedMetadataQualification - }) - const toggleActionsMenuBtn = getByTestId('toggleActionsMenuBtn') - fireEvent.click(toggleActionsMenuBtn) - - expect(toggleActionsMenu).toBeCalledWith('Italie') - }) - }) -}) diff --git a/react/Viewer/Panel/QualificationListItemOther.jsx b/react/Viewer/Panel/QualificationListItemOther.jsx deleted file mode 100644 index 90e4d68b7d..0000000000 --- a/react/Viewer/Panel/QualificationListItemOther.jsx +++ /dev/null @@ -1,61 +0,0 @@ -import PropTypes from 'prop-types' -import React, { forwardRef } from 'react' - -import { - getTranslatedNameForOtherMetadata, - formatOtherMetadataValue -} from 'cozy-client/dist/models/paper' - -import QualificationListItemText from './QualificationListItemText' -import Icon from '../../Icon' -import IconButton from '../../IconButton' -import Dots from '../../Icons/Dots' -import ListItem from '../../ListItem' -import ListItemSecondaryAction from '../../ListItemSecondaryAction' -import MidEllipsis from '../../MidEllipsis' -import { useI18n } from '../../providers/I18n' - -const QualificationListItemOther = forwardRef( - ({ formattedMetadataQualification, toggleActionsMenu }, ref) => { - const { lang } = useI18n() - const { name, value } = formattedMetadataQualification - - if (!value) return null - - const formattedTitle = getTranslatedNameForOtherMetadata(name, { - lang - }) - const formattedValue = formatOtherMetadataValue(value, { - lang, - name - }) - - return ( - - } - /> - - toggleActionsMenu(formattedValue)} - > - - - - - ) - } -) -QualificationListItemOther.displayName = 'QualificationListItemOther' - -QualificationListItemOther.propTypes = { - formattedMetadataQualification: PropTypes.shape({ - name: PropTypes.string, - value: PropTypes.string - }).isRequired, - toggleActionsMenu: PropTypes.func.isRequired -} - -export default QualificationListItemOther diff --git a/react/Viewer/Panel/QualificationListItemText.jsx b/react/Viewer/Panel/QualificationListItemText.jsx deleted file mode 100644 index ff2b585a06..0000000000 --- a/react/Viewer/Panel/QualificationListItemText.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import PropTypes from 'prop-types' -import React from 'react' - -import ListItemText from '../../ListItemText' -import Typography from '../../Typography' - -const QualificationListItemText = ({ primary, secondary, disabled }) => { - return ( - {primary}} - secondary={ - - {secondary} - - } - /> - ) -} - -QualificationListItemText.propTypes = { - primary: PropTypes.string.isRequired, - secondary: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired -} - -export default QualificationListItemText diff --git a/react/Viewer/Panel/getPanelBlocks.jsx b/react/Viewer/Panel/getPanelBlocks.jsx deleted file mode 100644 index fa2a25f79d..0000000000 --- a/react/Viewer/Panel/getPanelBlocks.jsx +++ /dev/null @@ -1,56 +0,0 @@ -import { models } from 'cozy-client' -import KonnectorBlock from 'cozy-harvest-lib/dist/components/KonnectorBlock' - -import Certifications from './Certifications' -import Qualification from './Qualification' - -const { isFromKonnector, hasQualifications, hasCertifications } = models.file - -/** - * @typedef {Object} PanelBlockSpec - * @property {Function} condition - Function that returns true if the block should be displayed - * @property {React.Component} component - Component to display - */ - -/** - * @typedef {Object.} PanelBlocksSpecs - */ - -/** - * Returns the specs of the blocks to display in the panel - * @param {boolean} isPublic - Whether the panel is displayed in public view - * @returns {PanelBlocksSpecs} - */ -export const getPanelBlocksSpecs = (isPublic = false) => ({ - qualifications: { - condition: hasQualifications, - component: Qualification - }, - konnector: { - condition: file => isFromKonnector(file) && !isPublic, - component: KonnectorBlock - }, - certifications: { - condition: hasCertifications, - component: Certifications - } -}) - -/** - * Returns the blocks to display in the panel - * @param {Object} options - * @param {PanelBlocksSpecs} options.panelBlocksSpecs - Specs of the blocks to display in the panel - * @param {import('cozy-client/types/types').FileDocument} options.file - File object - * @returns {Array.} - */ -const getPanelBlocks = ({ panelBlocksSpecs, file }) => { - const panelBlocks = [] - - Object.values(panelBlocksSpecs).forEach(panelBlock => { - panelBlock.condition(file) && panelBlocks.push(panelBlock.component) - }) - - return panelBlocks -} - -export default getPanelBlocks diff --git a/react/Viewer/Panel/getPanelBlocks.spec.jsx b/react/Viewer/Panel/getPanelBlocks.spec.jsx deleted file mode 100644 index c758e60248..0000000000 --- a/react/Viewer/Panel/getPanelBlocks.spec.jsx +++ /dev/null @@ -1,79 +0,0 @@ -import getPanelBlocks, { getPanelBlocksSpecs } from './getPanelBlocks' - -jest.mock('cozy-harvest-lib/dist/components/KonnectorBlock', () => jest.fn()) -const block1Component = jest.fn() -const block2Component = jest.fn() - -describe('getPanelBlocks', () => { - it('should return only blocks with truthy condition', () => { - // with two truthy component - expect( - getPanelBlocks({ - panelBlocksSpecs: { - block1: { - condition: () => true, - component: block1Component - }, - block2: { - condition: () => true, - component: block2Component - } - } - }) - ).toMatchObject([block1Component, block2Component]) - - // with one truthy component - expect( - getPanelBlocks({ - panelBlocksSpecs: { - block1: { - condition: () => false, - component: block1Component - }, - block2: { - condition: () => true, - component: block2Component - } - } - }) - ).toMatchObject([block2Component]) - - // with no truthy component - expect( - getPanelBlocks({ - panelBlocksSpecs: { - block1: { - condition: () => false, - component: block1Component - }, - block2: { - condition: () => false, - component: block2Component - } - } - }) - ).toMatchObject([]) - - // with no specs - expect(getPanelBlocks({ panelBlocksSpecs: {} })).toMatchObject([]) - }) -}) - -describe('getPanelBlocksSpecs', () => { - it('should return the specs of the blocks to display in the panel', () => { - expect(getPanelBlocksSpecs()).toEqual({ - qualifications: { - condition: expect.any(Function), - component: expect.anything() - }, - konnector: { - condition: expect.any(Function), - component: expect.anything() - }, - certifications: { - condition: expect.any(Function), - component: expect.anything() - } - }) - }) -}) diff --git a/react/Viewer/Panel/styles.styl b/react/Viewer/Panel/styles.styl deleted file mode 100644 index 02bf565af0..0000000000 --- a/react/Viewer/Panel/styles.styl +++ /dev/null @@ -1,13 +0,0 @@ -.ActionMenuDesktop-ActionMenu - a - padding 0 !important // Waiting for the migration of the ActionMenu on the Viewer - .ActionMenuDesktop-ActionMenu-link-disabled - > div - cursor default - &:hover - background-color initial - > div - svg - fill var(--disabledTextColor) - p - color var(--disabledTextColor) diff --git a/react/Viewer/Readme.md b/react/Viewer/Readme.md deleted file mode 100644 index 3070fb366b..0000000000 --- a/react/Viewer/Readme.md +++ /dev/null @@ -1,352 +0,0 @@ -The `Viewer` component can be used to display the content of various file types. - -Once rendered, the `Viewer` will take up all the available space in it's container (using `position: absolute`). - -The `Viewer` can display an **information panel** to show additional information about the current file (e.g. whether a file is certified). - -### ⚠️ Requirement - -* You must have [WebviewIntent Provider](https://github.com/cozy/cozy-libs/blob/b1ad6f5933b463878f641d9fbb63eddd4c45b0d0/packages/cozy-intent/src/view/components/WebviewIntentProvider.tsx#L89) & [CozySharing Provider](https://github.com/cozy/cozy-libs/tree/master/packages/cozy-sharing) -* In order to download and display the files, it will need a `cozy-client` instance in the React context. -* To have the panels, the app need to have [cozy-harvest-lib](https://github.com/cozy/cozy-libs/tree/master/packages/cozy-harvest-lib) installed - -### Props - -* **files** : `` – One or more `io.cozy.files` to display -* **currentIndex** : `` – Index of the file to show -* **currentURL** : `` – Optionnal URL of the file -* **className** : `` – CSS classes -* **showNavigation** : `` – Whether to show left and right arrows to navigate between files -* **renderFallbackExtraContent** : `` – A render prop that is called when a file can't be displayed -* **disablePanel** : `` – Show/Hide the panel containing more information about the file only on Desktop -* **disableFooter** : `` – Show/Hide the panel containing more information about the file only on Phone & Tablet devices -* **disableModal** : `` – To avoid wrapping the Viewer with a Modal component (wrapper of Viewer) -* **editPathByModelProps** : `` – Edit path by model properties - * **information** : `` – URL used to edit the file when editing a `information` type metadata (text, date) - * **page** : `` – URL used to edit the file when editing a `page` type metadata (side of the document) -* **onChangeRequest** : `` - Called with (nextFile, nextIndex) when the user requests to navigate to another file -* **onCloseRequest** : `` - Called when the user wants to leave the Viewer -* **isPublic**: `` - Whether the viewer is used in a public page or not -* **componentsProps** : `` – Props passed to components with the same name - * **modalProps** : `` – Props passed to Modal component - * **OnlyOfficeViewer** : `` – Used to open an Only Office file - * **isEnabled** : `` – Whether Only Office is enabled on the server - * **opener** : `` – To open the Only Office file - * **toolbarProps** : `` – Toolbar properties - * **toolbarRef** : `` – React reference of the toolbar node - * **showToolbar** : `` – Whether to show the toolbar or not. Note that the built-in close button is in the toolbar - * **showClose** : `` – Whether to show close button in toolbar - * **showFilePath** : `` – Whether to show file path below his name - -### Demo - -```jsx -import cx from 'classnames' -import { makeStyles } from 'cozy-ui/transpiled/react/styles' -import Variants from 'cozy-ui/docs/components/Variants' -import Card from 'cozy-ui/transpiled/react/Card' -import Checkbox from 'cozy-ui/transpiled/react/Checkbox' -import Viewer, { ToolbarButtons, FooterActionButtons, ForwardOrDownloadButton } from 'cozy-ui/transpiled/react/Viewer' -import Stack from 'cozy-ui/transpiled/react/Stack' -import Paper from 'cozy-ui/transpiled/react/Paper' -import Typography from 'cozy-ui/transpiled/react/Typography' -import { Media, Img, Bd } from 'cozy-ui/transpiled/react/deprecated/Media' -import Icon from 'cozy-ui/transpiled/react/Icon' -import CarbonCopyIcon from 'cozy-ui/transpiled/react/Icons/CarbonCopy' -// The DemoProvider inserts a fake cozy-client in the React context. -import DemoProvider from './docs/DemoProvider' -import Button from 'cozy-ui/transpiled/react/Buttons' -import DownloadIcon from 'cozy-ui/transpiled/react/Icons/Download' -import ShareIcon from 'cozy-ui/transpiled/react/Icons/Share' -import { isValidForPanel } from 'cozy-ui/transpiled/react/Viewer/helpers' -import getPanelBlocks, { panelBlocksSpecs } from 'cozy-ui/transpiled/react/Viewer/Panel/getPanelBlocks' -import Sprite from 'cozy-ui/transpiled/react/Icon/Sprite' -import IconButton from 'cozy-ui/transpiled/react/IconButton' - -// We provide a collection of (fake) io.cozy.files to be rendered -const files = [ - { - _id: 'audio', - class: 'audio', - type: 'file', - name: 'Sample.mp3', - mime: 'audio/mp3', - dir_id: 'parent_folder' - }, - { - _id: 'slide', - class: 'slide', - type: 'file', - name: 'Slide.pptx', - mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - dir_id: 'parent_folder' - }, - { - _id: 'pdf', - class: 'pdf', - type: 'file', - name: 'My vehicle registration.pdf', - mime: 'application/pdf', - bills: { data: [{ amount: '500' }] }, - metadata: { - carbonCopy: true, - AObtentionDate: null, - BObtentionDate: "2022-02-09T09:05:38.000Z", - CObtentionDate: null, - DObtentionDate: null, - datetime: "2022-09-23T07:50:22.000Z", - datetimeLabel: "BObtentionDate", - expirationDate: new Date(Date.now() + 10 * 24 * 60 * 60 * 1000).toISOString(), - noticePeriod: "90", - number: "", - page: "front", - qualification: { - label: "driver_license", - purpose: "attestation", - sourceCategory: "gov", - sourceSubCategory: "transport", - subjects: ["permit", "driving"] - } - }, - dir_id: 'parent_folder' - }, - { - _id: 'text', - class: 'text', - type: 'file', - name: 'LoremipsumdolorsitametconsecteturadipiscingelitSednonrisusSuspendisselectustortordignissimsitametadipiscingnecultriciesseddolorCraselementumultricesdiamMaecenasligulamassavariusasempercongueeuismodnonmiProinporttitororcinecnonummymolestieenimesteleifendminonfermentumdiamnislsitameteratDuissemperDuisarcumassascelerisquevitaeconsequatinpretiumaenimPellentesquecongueUtinrisusvolutpatliberopharetratemporCrasvestibulumbibendumauguePraesentegestasleoinpedePraesentblanditodioeuenimPellentesquesedduiutaugueblanditsodalesVestibulumanteipsumprimisinfaucibusorciluctusetultricesposuerecubiliaCuraeAliquamnibhMaurisacmaurissedpedepellentesquefermentumMaecenasadipiscingantenondiamsodaleshendrerit.txt', - mime: 'text/plain', - metadata: { - datetime: "2022-01-01T12:00:00.000Z", - datetimeLabel: "datetime", - qualification: { - label: 'tax_notice' - } - } - }, - { - _id: 'text', - class: 'text', - type: 'file', - name: 'encrypted-example.txt', - mime: 'text/plain', - encrypted: true - }, - { - _id: 'image', - class: 'image', - type: 'file', - name: 'Demo.jpg', - mime: 'image/jpg', - metadata: { - carbonCopy: true, - electronicSafe: true, - referencedDate: new Date(Date.now() - 357 * 24 * 60 * 60 * 1000).toISOString(), - datetimeLabel: "referencedDate", - qualification: { - label: 'personal_sporting_licence' - } - } - }, - { - _id: 'none', - class: 'unknown', - type: 'file', - name: 'Unsupported file type', - mime: '???/???' - }, - { - _id: 'none', - class: 'unknown', - type: 'file', - name: 'Unsupported file type', - mime: '???/???', - metadata: { - carbonCopy: true, - AObtentionDate: null, - BObtentionDate: "2022-02-09T09:05:38.000Z", - CObtentionDate: null, - DObtentionDate: null, - datetime: "2022-09-23T07:50:22.000Z", - datetimeLabel: "BObtentionDate", - number: "", - page: "front", - qualification: { - label: "driver_license", - purpose: "attestation", - sourceCategory: "gov", - sourceSubCategory: "transport", - subjects: ["permit", "driving"] - } - } - } -] - -const ShareButtonFake = () => { - return ( -