cozy-ui 111.21.0 → 112.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/package.json +3 -2
- package/react/FileImageLoader/Readme.md +66 -3
- package/react/FileImageLoader/index.jsx +3 -3
- package/react/FileImageLoader/index.spec.jsx +1 -1
- package/react/hooks/useClientErrors.jsx +140 -0
- package/react/hooks/useClientErrors.spec.jsx +102 -0
- package/react/index.js +0 -1
- package/transpiled/react/FileImageLoader/index.js +3 -3
- package/transpiled/react/hooks/useClientErrors.js +167 -0
- package/transpiled/react/index.js +0 -1
- package/transpiled/react/stylesheet.css +1 -1
- package/react/Viewer/Footer/BottomSheetContent.jsx +0 -29
- package/react/Viewer/Footer/DownloadButton.jsx +0 -67
- package/react/Viewer/Footer/FooterActionButtons.jsx +0 -22
- package/react/Viewer/Footer/FooterActionButtons.spec.jsx +0 -30
- package/react/Viewer/Footer/FooterContent.jsx +0 -99
- package/react/Viewer/Footer/ForwardButton.jsx +0 -95
- package/react/Viewer/Footer/ForwardButton.spec.jsx +0 -87
- package/react/Viewer/Footer/ForwardOrDownloadButton.jsx +0 -24
- package/react/Viewer/Footer/Sharing.jsx +0 -60
- package/react/Viewer/Footer/helpers.js +0 -107
- package/react/Viewer/Footer/helpers.spec.js +0 -77
- package/react/Viewer/NoViewer/DownloadButton.jsx +0 -28
- package/react/Viewer/NoViewer/FileIcon.jsx +0 -46
- package/react/Viewer/NoViewer/NoViewer.jsx +0 -29
- package/react/Viewer/NoViewer/NoViewer.spec.jsx +0 -44
- package/react/Viewer/NoViewer/__snapshots__/NoViewer.spec.jsx.snap +0 -82
- package/react/Viewer/NoViewer/index.jsx +0 -1
- package/react/Viewer/Panel/ActionMenuDesktop.jsx +0 -66
- package/react/Viewer/Panel/ActionMenuMobile.jsx +0 -74
- package/react/Viewer/Panel/ActionMenuWrapper.jsx +0 -104
- package/react/Viewer/Panel/Certifications.jsx +0 -62
- package/react/Viewer/Panel/PanelContent.jsx +0 -49
- package/react/Viewer/Panel/Qualification.jsx +0 -114
- package/react/Viewer/Panel/QualificationListItemContact.jsx +0 -85
- package/react/Viewer/Panel/QualificationListItemDate.jsx +0 -77
- package/react/Viewer/Panel/QualificationListItemInformation.jsx +0 -68
- package/react/Viewer/Panel/QualificationListItemInformation.spec.jsx +0 -73
- package/react/Viewer/Panel/QualificationListItemOther.jsx +0 -61
- package/react/Viewer/Panel/QualificationListItemText.jsx +0 -30
- package/react/Viewer/Panel/getPanelBlocks.jsx +0 -56
- package/react/Viewer/Panel/getPanelBlocks.spec.jsx +0 -79
- package/react/Viewer/Panel/styles.styl +0 -13
- package/react/Viewer/Readme.md +0 -352
- package/react/Viewer/Viewer.jsx +0 -134
- package/react/Viewer/ViewerContainer.jsx +0 -169
- package/react/Viewer/ViewerExposer.js +0 -3
- package/react/Viewer/ViewerInformationsWrapper.jsx +0 -69
- package/react/Viewer/ViewerInformationsWrapper.spec.jsx +0 -63
- package/react/Viewer/ViewerWithCustomPanelAndFooter.jsx +0 -55
- package/react/Viewer/ViewersByFile/AudioViewer.jsx +0 -21
- package/react/Viewer/ViewersByFile/AudioViewer.spec.jsx +0 -39
- package/react/Viewer/ViewersByFile/BlankPaperViewer.jsx +0 -46
- package/react/Viewer/ViewersByFile/ImageViewer.jsx +0 -330
- package/react/Viewer/ViewersByFile/ImageViewer.spec.jsx +0 -70
- package/react/Viewer/ViewersByFile/NoNetworkViewer.jsx +0 -17
- package/react/Viewer/ViewersByFile/OnlyOfficeViewer.jsx +0 -28
- package/react/Viewer/ViewersByFile/PdfJsViewer.jsx +0 -210
- package/react/Viewer/ViewersByFile/PdfJsViewer.spec.jsx +0 -160
- package/react/Viewer/ViewersByFile/PdfMobileViewer.jsx +0 -106
- package/react/Viewer/ViewersByFile/PdfMobileViewer.spec.jsx +0 -76
- package/react/Viewer/ViewersByFile/ShortcutViewer.jsx +0 -38
- package/react/Viewer/ViewersByFile/ShortcutViewer.spec.jsx +0 -32
- package/react/Viewer/ViewersByFile/TextViewer.jsx +0 -126
- package/react/Viewer/ViewersByFile/TextViewer.spec.jsx +0 -118
- package/react/Viewer/ViewersByFile/VideoViewer.jsx +0 -13
- package/react/Viewer/ViewersByFile/VideoViewer.spec.jsx +0 -39
- package/react/Viewer/ViewersByFile/__snapshots__/AudioViewer.spec.jsx.snap +0 -43
- package/react/Viewer/ViewersByFile/__snapshots__/ShortcutViewer.spec.jsx.snap +0 -57
- package/react/Viewer/ViewersByFile/__snapshots__/TextViewer.spec.jsx.snap +0 -100
- package/react/Viewer/ViewersByFile/__snapshots__/VideoViewer.spec.jsx.snap +0 -19
- package/react/Viewer/ViewersByFile/styles.styl +0 -87
- package/react/Viewer/assets/IlluGenericNewPage.svg +0 -10
- package/react/Viewer/components/ExpirationAlert.jsx +0 -86
- package/react/Viewer/components/ExpirationAnnotation.jsx +0 -40
- package/react/Viewer/components/Footer.jsx +0 -13
- package/react/Viewer/components/InformationPanel.jsx +0 -26
- package/react/Viewer/components/Navigation.jsx +0 -39
- package/react/Viewer/components/PdfToolbarButton.jsx +0 -26
- package/react/Viewer/components/PrintButton.jsx +0 -90
- package/react/Viewer/components/Toolbar.jsx +0 -111
- package/react/Viewer/components/ToolbarButtons.jsx +0 -11
- package/react/Viewer/components/ToolbarFilePath.jsx +0 -61
- package/react/Viewer/components/ViewerByFile.jsx +0 -112
- package/react/Viewer/components/ViewerByFile.spec.jsx +0 -100
- package/react/Viewer/components/ViewerControls.jsx +0 -190
- package/react/Viewer/components/ViewerControls.spec.jsx +0 -54
- package/react/Viewer/components/ViewerSpinner.jsx +0 -17
- package/react/Viewer/components/styles.styl +0 -93
- package/react/Viewer/helpers.js +0 -131
- package/react/Viewer/helpers.spec.js +0 -136
- package/react/Viewer/hoc/withFileUrl.jsx +0 -93
- package/react/Viewer/hoc/withViewerLocales.jsx +0 -4
- package/react/Viewer/hooks/useReferencedContactName.jsx +0 -26
- package/react/Viewer/index.jsx +0 -12
- package/react/Viewer/locales/en.json +0 -66
- package/react/Viewer/locales/fr.json +0 -66
- package/react/Viewer/locales/index.js +0 -4
- package/react/Viewer/proptypes.js +0 -12
- package/react/Viewer/providers/ActionMenuProvider.jsx +0 -35
- package/react/Viewer/queries.js +0 -20
- package/react/Viewer/styles.styl +0 -22
- package/react/Viewer/vars.styl +0 -6
- package/transpiled/react/Viewer/Footer/BottomSheetContent.js +0 -28
- package/transpiled/react/Viewer/Footer/DownloadButton.js +0 -91
- package/transpiled/react/Viewer/Footer/FooterActionButtons.js +0 -21
- package/transpiled/react/Viewer/Footer/FooterContent.js +0 -98
- package/transpiled/react/Viewer/Footer/ForwardButton.js +0 -143
- package/transpiled/react/Viewer/Footer/ForwardOrDownloadButton.js +0 -25
- package/transpiled/react/Viewer/Footer/Sharing.js +0 -57
- package/transpiled/react/Viewer/Footer/helpers.js +0 -151
- package/transpiled/react/Viewer/NoViewer/DownloadButton.js +0 -34
- package/transpiled/react/Viewer/NoViewer/FileIcon.js +0 -57
- package/transpiled/react/Viewer/NoViewer/NoViewer.js +0 -49
- package/transpiled/react/Viewer/NoViewer/index.js +0 -1
- package/transpiled/react/Viewer/Panel/ActionMenuDesktop.js +0 -68
- package/transpiled/react/Viewer/Panel/ActionMenuMobile.js +0 -70
- package/transpiled/react/Viewer/Panel/ActionMenuWrapper.js +0 -129
- package/transpiled/react/Viewer/Panel/Certifications.js +0 -56
- package/transpiled/react/Viewer/Panel/PanelContent.js +0 -48
- package/transpiled/react/Viewer/Panel/Qualification.js +0 -119
- package/transpiled/react/Viewer/Panel/QualificationListItemContact.js +0 -96
- package/transpiled/react/Viewer/Panel/QualificationListItemDate.js +0 -64
- package/transpiled/react/Viewer/Panel/QualificationListItemInformation.js +0 -59
- package/transpiled/react/Viewer/Panel/QualificationListItemOther.js +0 -53
- package/transpiled/react/Viewer/Panel/QualificationListItemText.js +0 -29
- package/transpiled/react/Viewer/Panel/getPanelBlocks.js +0 -62
- package/transpiled/react/Viewer/Viewer.js +0 -172
- package/transpiled/react/Viewer/ViewerContainer.js +0 -189
- package/transpiled/react/Viewer/ViewerExposer.js +0 -2
- package/transpiled/react/Viewer/ViewerInformationsWrapper.js +0 -49
- package/transpiled/react/Viewer/ViewerWithCustomPanelAndFooter.js +0 -56
- package/transpiled/react/Viewer/ViewersByFile/AudioViewer.js +0 -41
- package/transpiled/react/Viewer/ViewersByFile/BlankPaperViewer.js +0 -74
- package/transpiled/react/Viewer/ViewersByFile/ImageViewer.js +0 -367
- package/transpiled/react/Viewer/ViewersByFile/NoNetworkViewer.js +0 -38
- package/transpiled/react/Viewer/ViewersByFile/OnlyOfficeViewer.js +0 -29
- package/transpiled/react/Viewer/ViewersByFile/PdfJsViewer.js +0 -254
- package/transpiled/react/Viewer/ViewersByFile/PdfMobileViewer.js +0 -153
- package/transpiled/react/Viewer/ViewersByFile/ShortcutViewer.js +0 -42
- package/transpiled/react/Viewer/ViewersByFile/TextViewer.js +0 -219
- package/transpiled/react/Viewer/ViewersByFile/VideoViewer.js +0 -33
- package/transpiled/react/Viewer/assets/IlluGenericNewPage.svg +0 -10
- package/transpiled/react/Viewer/components/ExpirationAlert.js +0 -100
- package/transpiled/react/Viewer/components/ExpirationAnnotation.js +0 -41
- package/transpiled/react/Viewer/components/Footer.js +0 -29
- package/transpiled/react/Viewer/components/InformationPanel.js +0 -23
- package/transpiled/react/Viewer/components/Navigation.js +0 -47
- package/transpiled/react/Viewer/components/PdfToolbarButton.js +0 -28
- package/transpiled/react/Viewer/components/PrintButton.js +0 -137
- package/transpiled/react/Viewer/components/Toolbar.js +0 -115
- package/transpiled/react/Viewer/components/ToolbarButtons.js +0 -9
- package/transpiled/react/Viewer/components/ToolbarFilePath.js +0 -71
- package/transpiled/react/Viewer/components/ViewerByFile.js +0 -105
- package/transpiled/react/Viewer/components/ViewerControls.js +0 -226
- package/transpiled/react/Viewer/components/ViewerSpinner.js +0 -17
- package/transpiled/react/Viewer/helpers.js +0 -147
- package/transpiled/react/Viewer/hoc/withFileUrl.js +0 -207
- package/transpiled/react/Viewer/hoc/withViewerLocales.js +0 -3
- package/transpiled/react/Viewer/hooks/useReferencedContactName.js +0 -32
- package/transpiled/react/Viewer/index.js +0 -11
- package/transpiled/react/Viewer/locales/index.js +0 -136
- package/transpiled/react/Viewer/proptypes.js +0 -14
- package/transpiled/react/Viewer/providers/ActionMenuProvider.js +0 -34
- package/transpiled/react/Viewer/queries.js +0 -26
- /package/react/{Viewer/providers/EncryptedProvider.jsx → providers/Encrypted/index.jsx} +0 -0
- /package/transpiled/react/{Viewer/providers/EncryptedProvider.js → providers/Encrypted/index.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [112.0.0](https://github.com/cozy/cozy-ui/compare/v111.21.0...v112.0.0) (2024-10-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **hooks:** Add useClientErrors from cozy-client ([deb505e](https://github.com/cozy/cozy-ui/commit/deb505e))
|
|
7
|
+
* **providers:** Add Encrypted from cozy-viewer ([612cff6](https://github.com/cozy/cozy-ui/commit/612cff6))
|
|
8
|
+
* Remove Viewer ([7d2b7ef](https://github.com/cozy/cozy-ui/commit/7d2b7ef))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### BREAKING CHANGES
|
|
12
|
+
|
|
13
|
+
* 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/...'`
|
|
14
|
+
|
|
1
15
|
# [111.21.0](https://github.com/cozy/cozy-ui/compare/v111.20.0...v111.21.0) (2024-10-21)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "112.0.0",
|
|
4
4
|
"description": "Cozy apps UI SDK",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -158,7 +158,8 @@
|
|
|
158
158
|
"svgo": "2.8.0",
|
|
159
159
|
"svgstore-cli": "1.3.2",
|
|
160
160
|
"url-loader": "1.1.2",
|
|
161
|
-
"webpack": "4.39.3"
|
|
161
|
+
"webpack": "4.39.3",
|
|
162
|
+
"whatwg-fetch": "3.5.0"
|
|
162
163
|
},
|
|
163
164
|
"dependencies": {
|
|
164
165
|
"@babel/runtime": "^7.3.4",
|
|
@@ -3,14 +3,77 @@
|
|
|
3
3
|
A component to get the image in `links` prop of a file, according to its class (could be `image` or `pdf`).
|
|
4
4
|
|
|
5
5
|
```jsx
|
|
6
|
-
import DemoProvider from 'cozy-ui/transpiled/react/
|
|
7
|
-
|
|
6
|
+
import DemoProvider from 'cozy-ui/transpiled/react/providers/DemoProvider'
|
|
8
7
|
import FileImageLoader from 'cozy-ui/transpiled/react/FileImageLoader'
|
|
9
8
|
import Icon from 'cozy-ui/transpiled/react/Icon'
|
|
10
9
|
import FileDuotoneIcon from "cozy-ui/transpiled/react/Icons/FileDuotone"
|
|
11
10
|
import BankIcon from "cozy-ui/transpiled/react/Icons/Bank"
|
|
12
11
|
import CloudWallpaper from 'cozy-ui/docs/cloud-wallpaper.jpg'
|
|
13
12
|
|
|
13
|
+
const demoTextFileResponse = {
|
|
14
|
+
text: () => new Promise(resolve => resolve('Hello World !'))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const demoFilesByClass = {
|
|
18
|
+
pdf: 'https://raw.githubusercontent.com/rospdf/pdf-php/2ccf7591fc2f18e63342ebfedad7997b08c34ed2/readme.pdf',
|
|
19
|
+
audio: 'https://viewerdemo.cozycloud.cc/Z.mp3',
|
|
20
|
+
video: 'https://viewerdemo.cozycloud.cc/Nextcloud.mp4',
|
|
21
|
+
text: 'https://viewerdemo.cozycloud.cc/notes.md'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const mockClient = {
|
|
25
|
+
plugins: {
|
|
26
|
+
realtime: {
|
|
27
|
+
subscribe: () => {},
|
|
28
|
+
unsubscribe: () => {},
|
|
29
|
+
unsubscribeAll: () => {}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
on: () => {},
|
|
33
|
+
collection: () => ({
|
|
34
|
+
getDownloadLinkById: id =>
|
|
35
|
+
new Promise(resolve => resolve(demoFilesByClass[id])),
|
|
36
|
+
download: () =>
|
|
37
|
+
alert(
|
|
38
|
+
"This is a demo, there's no actual Cozy to download the file from ¯\\_(ツ)_/¯"
|
|
39
|
+
),
|
|
40
|
+
get: () =>
|
|
41
|
+
new Promise(resolve =>
|
|
42
|
+
resolve({
|
|
43
|
+
data: {
|
|
44
|
+
links: {
|
|
45
|
+
large: CloudWallpaper
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
)
|
|
50
|
+
}),
|
|
51
|
+
getStackClient: () => ({
|
|
52
|
+
uri: '',
|
|
53
|
+
fetch: () => new Promise(resolve => resolve(demoTextFileResponse))
|
|
54
|
+
}),
|
|
55
|
+
getClient: () => mockClient,
|
|
56
|
+
store: {
|
|
57
|
+
getState: () => {},
|
|
58
|
+
subscribe: () => {},
|
|
59
|
+
unsubscribe: () => {}
|
|
60
|
+
},
|
|
61
|
+
getQueryFromState: queryName => {
|
|
62
|
+
if (queryName === 'io.cozy.files/parent_folder') {
|
|
63
|
+
return {
|
|
64
|
+
data: {
|
|
65
|
+
_id: 'parent_id',
|
|
66
|
+
path: '/Parent'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
query: () => ({
|
|
72
|
+
data: [{ attributes: { slug: 'mespapiers' }, links: { related: '' } }]
|
|
73
|
+
}),
|
|
74
|
+
getInstanceOptions: () => ({ app: { slug: 'mespapiers' }, subdomain: 'flat' })
|
|
75
|
+
}
|
|
76
|
+
|
|
14
77
|
const file = {
|
|
15
78
|
_id: 'image',
|
|
16
79
|
class: 'image',
|
|
@@ -31,7 +94,7 @@ const FallbackComp = () => {
|
|
|
31
94
|
|
|
32
95
|
;
|
|
33
96
|
|
|
34
|
-
<DemoProvider>
|
|
97
|
+
<DemoProvider client={mockClient}>
|
|
35
98
|
<FileImageLoader
|
|
36
99
|
file={file}
|
|
37
100
|
linkType="large"
|
|
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types'
|
|
|
2
2
|
import { Component } from 'react'
|
|
3
3
|
|
|
4
4
|
import { withClient } from 'cozy-client'
|
|
5
|
+
import { isEncrypted } from 'cozy-client/dist/models/file'
|
|
5
6
|
import logger from 'cozy-logger'
|
|
6
7
|
|
|
7
8
|
const PENDING = 'PENDING'
|
|
@@ -12,8 +13,7 @@ const FAILED = 'FAILED'
|
|
|
12
13
|
const GET_LINK = 'GET_LINK'
|
|
13
14
|
|
|
14
15
|
import { checkImageSource } from './checkImageSource'
|
|
15
|
-
import {
|
|
16
|
-
import { EncryptedContext } from '../Viewer/providers/EncryptedProvider'
|
|
16
|
+
import { EncryptedContext } from '../providers/Encrypted'
|
|
17
17
|
|
|
18
18
|
export class FileImageLoader extends Component {
|
|
19
19
|
state = {
|
|
@@ -60,7 +60,7 @@ export class FileImageLoader extends Component {
|
|
|
60
60
|
|
|
61
61
|
loadNextSrc(lastError = null) {
|
|
62
62
|
const { file } = this.props
|
|
63
|
-
if (
|
|
63
|
+
if (isEncrypted(file)) {
|
|
64
64
|
// No link available for encrypted files
|
|
65
65
|
return
|
|
66
66
|
}
|
|
@@ -6,7 +6,7 @@ import logger from 'cozy-logger'
|
|
|
6
6
|
|
|
7
7
|
import { FileImageLoader } from '.'
|
|
8
8
|
import { checkImageSource } from './checkImageSource'
|
|
9
|
-
import EncryptedProvider from '../
|
|
9
|
+
import EncryptedProvider from '../providers/Encrypted'
|
|
10
10
|
|
|
11
11
|
jest.mock('./checkImageSource', () => ({
|
|
12
12
|
...jest.requireActual('./checkImageSource'),
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import filter from 'lodash/filter'
|
|
2
|
+
import React, { useCallback, useState, useEffect } from 'react'
|
|
3
|
+
|
|
4
|
+
import { useClient } from 'cozy-client'
|
|
5
|
+
import { FetchError } from 'cozy-stack-client'
|
|
6
|
+
|
|
7
|
+
import QuotaAlert from '../deprecated/QuotaAlert'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Rendering functions for client fetch errors by status code
|
|
11
|
+
*
|
|
12
|
+
* @private
|
|
13
|
+
* @type {object}
|
|
14
|
+
*/
|
|
15
|
+
const byHttpStatus = {
|
|
16
|
+
413: QuotaError // <QuotaError />
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Display for a quota error from the client
|
|
21
|
+
*
|
|
22
|
+
* @see QuotaAlert
|
|
23
|
+
* @private
|
|
24
|
+
* @param {object} props - Props
|
|
25
|
+
* @param {Function} props.dismiss - remove the error from the stack to display
|
|
26
|
+
* @returns {React.ReactElement}
|
|
27
|
+
*/
|
|
28
|
+
function QuotaError({ dismiss }) {
|
|
29
|
+
return <QuotaAlert onClose={dismiss} />
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns the handler for an error
|
|
34
|
+
*
|
|
35
|
+
* @param {import("../types").ClientError} error - The error
|
|
36
|
+
* @returns {Function|null} React Component
|
|
37
|
+
*/
|
|
38
|
+
function getErrorComponent(error) {
|
|
39
|
+
if (error instanceof Response || error instanceof FetchError) {
|
|
40
|
+
const status = error.status || ''
|
|
41
|
+
return byHttpStatus[status] || null
|
|
42
|
+
}
|
|
43
|
+
return null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Renders a stack of errors
|
|
48
|
+
*
|
|
49
|
+
* @private
|
|
50
|
+
* @see ClientErrors
|
|
51
|
+
* @param {import("../types").ClientError[]} errorStack - array of errors/exceptions
|
|
52
|
+
* @param {Function} setErrorStack - mutates the array of errors
|
|
53
|
+
* @returns {Array<React.ReactElement>} React rendering
|
|
54
|
+
*/
|
|
55
|
+
function renderErrors(errorStack, setErrorStack) {
|
|
56
|
+
const errors = errorStack.map((error, key) => {
|
|
57
|
+
const Component = getErrorComponent(error)
|
|
58
|
+
if (Component) {
|
|
59
|
+
const dismiss = () =>
|
|
60
|
+
setErrorStack(stack => filter(stack, e => e !== error))
|
|
61
|
+
return <Component key={key} error={error} dismiss={dismiss} />
|
|
62
|
+
} else {
|
|
63
|
+
return null
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
return errors
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Manages the client errors and allows to display them
|
|
71
|
+
*
|
|
72
|
+
* Returns a `ClientErrors` React component that takes care
|
|
73
|
+
* of how to display cozy-client errors (probably displaying a modal)
|
|
74
|
+
*
|
|
75
|
+
* Only Quota Errors are managed for now.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```
|
|
79
|
+
* const App = () => {
|
|
80
|
+
* const { ClientErrors } = useClientErrors()
|
|
81
|
+
*
|
|
82
|
+
* return <Layout>
|
|
83
|
+
* <h1>My app</h1>
|
|
84
|
+
* <ClientErrors />
|
|
85
|
+
* </Layout>
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @param {object} [props] - Props
|
|
90
|
+
* @param {boolean} [props.handleExceptions] - should cozy-client directly handle errors before forwarding them to the caller?
|
|
91
|
+
* @returns {{ClientErrors: Function}} React component
|
|
92
|
+
*/
|
|
93
|
+
export default function useClientErrors({ handleExceptions = true } = {}) {
|
|
94
|
+
const client = useClient()
|
|
95
|
+
const [errorStack, setErrorStack] = useState([])
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Handle client errors, add them to the error stack
|
|
99
|
+
*
|
|
100
|
+
* @param {import("../types").ClientError} error -
|
|
101
|
+
* @returns {boolean} true if the error was manager, false otherwise
|
|
102
|
+
*/
|
|
103
|
+
const handleError = useCallback(
|
|
104
|
+
error => {
|
|
105
|
+
// `isErrorManaged` is there to avoid the same error to be added twice
|
|
106
|
+
// once the error has been added once, the `isErrorManaged`is set to true
|
|
107
|
+
// and any future push is ignored
|
|
108
|
+
if (error.isErrorManaged) return false
|
|
109
|
+
|
|
110
|
+
const isManageable = !!getErrorComponent(error)
|
|
111
|
+
if (isManageable) {
|
|
112
|
+
error.isErrorManaged = true
|
|
113
|
+
setErrorStack(stack => stack.concat(error))
|
|
114
|
+
return true
|
|
115
|
+
} else {
|
|
116
|
+
error.isErrorManaged = false
|
|
117
|
+
return false
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
[setErrorStack]
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (handleExceptions) {
|
|
125
|
+
client.on('error', handleError)
|
|
126
|
+
return () => client.removeListener('error', handleError)
|
|
127
|
+
} else {
|
|
128
|
+
return undefined
|
|
129
|
+
}
|
|
130
|
+
}, [client, handleError, handleExceptions])
|
|
131
|
+
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
const ClientErrors = useCallback(
|
|
134
|
+
() => renderErrors(errorStack, setErrorStack),
|
|
135
|
+
[errorStack, setErrorStack]
|
|
136
|
+
)
|
|
137
|
+
// @ts-ignore
|
|
138
|
+
ClientErrors.displayName = 'ClientErrors'
|
|
139
|
+
return { ClientErrors }
|
|
140
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { renderHook, act } from '@testing-library/react-hooks'
|
|
2
|
+
import { shallow } from 'enzyme'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
import { CozyProvider } from 'cozy-client'
|
|
6
|
+
import { FetchError } from 'cozy-stack-client'
|
|
7
|
+
|
|
8
|
+
import useClientErrors from './useClientErrors'
|
|
9
|
+
|
|
10
|
+
function createCozyClient() {
|
|
11
|
+
return {
|
|
12
|
+
on: jest.fn(),
|
|
13
|
+
removeListener: jest.fn()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createWrapper(client = createCozyClient()) {
|
|
18
|
+
function Wrapper({ children }) {
|
|
19
|
+
return <CozyProvider client={client}>{children}</CozyProvider>
|
|
20
|
+
}
|
|
21
|
+
return Wrapper
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function renderWrappedHook(client) {
|
|
25
|
+
const wrapper = createWrapper(client)
|
|
26
|
+
return renderHook(() => useClientErrors(), { wrapper })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function wrappedShallow(tree, client) {
|
|
30
|
+
return shallow(tree, { wrappingComponent: createWrapper(client) })
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('useClientErrors', () => {
|
|
34
|
+
it('registers an `error` handler in client', done => {
|
|
35
|
+
const client = createCozyClient()
|
|
36
|
+
client.on.mockImplementation(name => name === 'error' && done())
|
|
37
|
+
renderWrappedHook(client)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('renderErrors', () => {
|
|
41
|
+
it('returns a function', () => {
|
|
42
|
+
const { result } = renderWrappedHook()
|
|
43
|
+
const { ClientErrors } = result.current
|
|
44
|
+
expect(ClientErrors).toBeInstanceOf(Function)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('displays nothing by default', () => {
|
|
48
|
+
const { result } = renderWrappedHook()
|
|
49
|
+
const { ClientErrors } = result.current
|
|
50
|
+
const node = wrappedShallow(<ClientErrors />)
|
|
51
|
+
expect(node).toHaveLength(0)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe('for quota errors', () => {
|
|
55
|
+
const findQuotaAlert = node => {
|
|
56
|
+
return node.at(0).dive()
|
|
57
|
+
}
|
|
58
|
+
const setup = async () => {
|
|
59
|
+
const client = createCozyClient()
|
|
60
|
+
const response = new Response(null, {
|
|
61
|
+
status: 413,
|
|
62
|
+
statusText: 'Quota exceeded'
|
|
63
|
+
})
|
|
64
|
+
const error = new FetchError(
|
|
65
|
+
response,
|
|
66
|
+
`${response.status} ${response.statusText}`
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
const { result, waitForNextUpdate } = renderWrappedHook(client)
|
|
70
|
+
const nextUpdate = waitForNextUpdate()
|
|
71
|
+
|
|
72
|
+
act(() => {
|
|
73
|
+
const handler = client.on.mock.calls[0][1]
|
|
74
|
+
handler(error)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
await nextUpdate
|
|
78
|
+
const { ClientErrors } = result.current
|
|
79
|
+
const node = wrappedShallow(<ClientErrors />, client)
|
|
80
|
+
return { node, result, client }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
it('displays a a QuotaAlert', async () => {
|
|
84
|
+
const { node } = await setup()
|
|
85
|
+
expect(node).toHaveLength(1)
|
|
86
|
+
expect(findQuotaAlert(node).type().name).toEqual('QuotaAlert')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('can be dismissed', async () => {
|
|
90
|
+
const { node, result, client } = await setup()
|
|
91
|
+
const quotaAlert = findQuotaAlert(node)
|
|
92
|
+
const onClose = quotaAlert.props().onClose
|
|
93
|
+
act(() => onClose())
|
|
94
|
+
|
|
95
|
+
// re-render ClientErrors returned by the hook
|
|
96
|
+
const { ClientErrors } = result.current
|
|
97
|
+
const updatedNode = wrappedShallow(<ClientErrors />, client)
|
|
98
|
+
expect(updatedNode.at(0).length).toBe(0)
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
})
|
package/react/index.js
CHANGED
|
@@ -65,7 +65,6 @@ export { default as AppTitle } from './AppTitle'
|
|
|
65
65
|
export { default as Filename } from './Filename'
|
|
66
66
|
export { default as FilePath } from './FilePath'
|
|
67
67
|
export { default as FilePathLink } from './FilePathLink'
|
|
68
|
-
export { default as Viewer } from './Viewer/ViewerExposer'
|
|
69
68
|
export { default as FileInput } from './FileInput'
|
|
70
69
|
export { default as Card } from './Card'
|
|
71
70
|
export { default as InlineCard } from './deprecated/InlineCard'
|
|
@@ -15,6 +15,7 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
|
|
|
15
15
|
import PropTypes from 'prop-types';
|
|
16
16
|
import { Component } from 'react';
|
|
17
17
|
import { withClient } from 'cozy-client';
|
|
18
|
+
import { isEncrypted } from 'cozy-client/dist/models/file';
|
|
18
19
|
import logger from 'cozy-logger';
|
|
19
20
|
var PENDING = 'PENDING';
|
|
20
21
|
var LOADING_LINK = 'LOADING_LINK';
|
|
@@ -23,8 +24,7 @@ var LOADED = 'LOADED';
|
|
|
23
24
|
var FAILED = 'FAILED';
|
|
24
25
|
var GET_LINK = 'GET_LINK';
|
|
25
26
|
import { checkImageSource } from "cozy-ui/transpiled/react/FileImageLoader/checkImageSource";
|
|
26
|
-
import {
|
|
27
|
-
import { EncryptedContext } from "cozy-ui/transpiled/react/Viewer/providers/EncryptedProvider";
|
|
27
|
+
import { EncryptedContext } from "cozy-ui/transpiled/react/providers/Encrypted";
|
|
28
28
|
export var FileImageLoader = /*#__PURE__*/function (_Component) {
|
|
29
29
|
_inherits(FileImageLoader, _Component);
|
|
30
30
|
|
|
@@ -99,7 +99,7 @@ export var FileImageLoader = /*#__PURE__*/function (_Component) {
|
|
|
99
99
|
var lastError = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
100
100
|
var file = this.props.file;
|
|
101
101
|
|
|
102
|
-
if (
|
|
102
|
+
if (isEncrypted(file)) {
|
|
103
103
|
// No link available for encrypted files
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import filter from 'lodash/filter';
|
|
3
|
+
import React, { useCallback, useState, useEffect } from 'react';
|
|
4
|
+
import { useClient } from 'cozy-client';
|
|
5
|
+
import { FetchError } from 'cozy-stack-client';
|
|
6
|
+
import QuotaAlert from "cozy-ui/transpiled/react/deprecated/QuotaAlert";
|
|
7
|
+
/**
|
|
8
|
+
* Rendering functions for client fetch errors by status code
|
|
9
|
+
*
|
|
10
|
+
* @private
|
|
11
|
+
* @type {object}
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
var byHttpStatus = {
|
|
15
|
+
413: QuotaError // <QuotaError />
|
|
16
|
+
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Display for a quota error from the client
|
|
20
|
+
*
|
|
21
|
+
* @see QuotaAlert
|
|
22
|
+
* @private
|
|
23
|
+
* @param {object} props - Props
|
|
24
|
+
* @param {Function} props.dismiss - remove the error from the stack to display
|
|
25
|
+
* @returns {React.ReactElement}
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
function QuotaError(_ref) {
|
|
29
|
+
var dismiss = _ref.dismiss;
|
|
30
|
+
return /*#__PURE__*/React.createElement(QuotaAlert, {
|
|
31
|
+
onClose: dismiss
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns the handler for an error
|
|
36
|
+
*
|
|
37
|
+
* @param {import("../types").ClientError} error - The error
|
|
38
|
+
* @returns {Function|null} React Component
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
function getErrorComponent(error) {
|
|
43
|
+
if (error instanceof Response || error instanceof FetchError) {
|
|
44
|
+
var status = error.status || '';
|
|
45
|
+
return byHttpStatus[status] || null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Renders a stack of errors
|
|
52
|
+
*
|
|
53
|
+
* @private
|
|
54
|
+
* @see ClientErrors
|
|
55
|
+
* @param {import("../types").ClientError[]} errorStack - array of errors/exceptions
|
|
56
|
+
* @param {Function} setErrorStack - mutates the array of errors
|
|
57
|
+
* @returns {Array<React.ReactElement>} React rendering
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
function renderErrors(errorStack, setErrorStack) {
|
|
62
|
+
var errors = errorStack.map(function (error, key) {
|
|
63
|
+
var Component = getErrorComponent(error);
|
|
64
|
+
|
|
65
|
+
if (Component) {
|
|
66
|
+
var dismiss = function dismiss() {
|
|
67
|
+
return setErrorStack(function (stack) {
|
|
68
|
+
return filter(stack, function (e) {
|
|
69
|
+
return e !== error;
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return /*#__PURE__*/React.createElement(Component, {
|
|
75
|
+
key: key,
|
|
76
|
+
error: error,
|
|
77
|
+
dismiss: dismiss
|
|
78
|
+
});
|
|
79
|
+
} else {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return errors;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Manages the client errors and allows to display them
|
|
87
|
+
*
|
|
88
|
+
* Returns a `ClientErrors` React component that takes care
|
|
89
|
+
* of how to display cozy-client errors (probably displaying a modal)
|
|
90
|
+
*
|
|
91
|
+
* Only Quota Errors are managed for now.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```
|
|
95
|
+
* const App = () => {
|
|
96
|
+
* const { ClientErrors } = useClientErrors()
|
|
97
|
+
*
|
|
98
|
+
* return <Layout>
|
|
99
|
+
* <h1>My app</h1>
|
|
100
|
+
* <ClientErrors />
|
|
101
|
+
* </Layout>
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @param {object} [props] - Props
|
|
106
|
+
* @param {boolean} [props.handleExceptions] - should cozy-client directly handle errors before forwarding them to the caller?
|
|
107
|
+
* @returns {{ClientErrors: Function}} React component
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
export default function useClientErrors() {
|
|
112
|
+
var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
|
113
|
+
_ref2$handleException = _ref2.handleExceptions,
|
|
114
|
+
handleExceptions = _ref2$handleException === void 0 ? true : _ref2$handleException;
|
|
115
|
+
|
|
116
|
+
var client = useClient();
|
|
117
|
+
|
|
118
|
+
var _useState = useState([]),
|
|
119
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
120
|
+
errorStack = _useState2[0],
|
|
121
|
+
setErrorStack = _useState2[1];
|
|
122
|
+
/**
|
|
123
|
+
* Handle client errors, add them to the error stack
|
|
124
|
+
*
|
|
125
|
+
* @param {import("../types").ClientError} error -
|
|
126
|
+
* @returns {boolean} true if the error was manager, false otherwise
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
var handleError = useCallback(function (error) {
|
|
131
|
+
// `isErrorManaged` is there to avoid the same error to be added twice
|
|
132
|
+
// once the error has been added once, the `isErrorManaged`is set to true
|
|
133
|
+
// and any future push is ignored
|
|
134
|
+
if (error.isErrorManaged) return false;
|
|
135
|
+
var isManageable = !!getErrorComponent(error);
|
|
136
|
+
|
|
137
|
+
if (isManageable) {
|
|
138
|
+
error.isErrorManaged = true;
|
|
139
|
+
setErrorStack(function (stack) {
|
|
140
|
+
return stack.concat(error);
|
|
141
|
+
});
|
|
142
|
+
return true;
|
|
143
|
+
} else {
|
|
144
|
+
error.isErrorManaged = false;
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}, [setErrorStack]);
|
|
148
|
+
useEffect(function () {
|
|
149
|
+
if (handleExceptions) {
|
|
150
|
+
client.on('error', handleError);
|
|
151
|
+
return function () {
|
|
152
|
+
return client.removeListener('error', handleError);
|
|
153
|
+
};
|
|
154
|
+
} else {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
}, [client, handleError, handleExceptions]); // @ts-ignore
|
|
158
|
+
|
|
159
|
+
var ClientErrors = useCallback(function () {
|
|
160
|
+
return renderErrors(errorStack, setErrorStack);
|
|
161
|
+
}, [errorStack, setErrorStack]); // @ts-ignore
|
|
162
|
+
|
|
163
|
+
ClientErrors.displayName = 'ClientErrors';
|
|
164
|
+
return {
|
|
165
|
+
ClientErrors: ClientErrors
|
|
166
|
+
};
|
|
167
|
+
}
|
|
@@ -52,7 +52,6 @@ export { default as AppTitle } from './AppTitle';
|
|
|
52
52
|
export { default as Filename } from './Filename';
|
|
53
53
|
export { default as FilePath } from './FilePath';
|
|
54
54
|
export { default as FilePathLink } from './FilePathLink';
|
|
55
|
-
export { default as Viewer } from './Viewer/ViewerExposer';
|
|
56
55
|
export { default as FileInput } from './FileInput';
|
|
57
56
|
export { default as Card } from './Card';
|
|
58
57
|
export { default as InlineCard } from './deprecated/InlineCard';
|