cozy-ui 91.2.0 → 92.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 CHANGED
@@ -1,3 +1,32 @@
1
+ # [92.0.0](https://github.com/cozy/cozy-ui/compare/v91.2.0...v92.0.0) (2023-08-28)
2
+
3
+
4
+ ### Features
5
+
6
+ * **Viewer:** Display file path into the toolbar ([e76e2f7](https://github.com/cozy/cozy-ui/commit/e76e2f7))
7
+ * **Viewer:** Move toolbarProps into componentsProps ([b0582da](https://github.com/cozy/cozy-ui/commit/b0582da))
8
+ * **Viewer:** Remove onlyOfficeProps ([9983c4a](https://github.com/cozy/cozy-ui/commit/9983c4a))
9
+
10
+
11
+ ### BREAKING CHANGES
12
+
13
+ * **Viewer:** The `toolbarProps` attribute from Viewer property has been moved into the `componentsProps` attribute.
14
+
15
+ You can use this codemods to migrate. **Don't forget to run js linter after the codemods.**
16
+
17
+ The `--parser` option is essential to manage any TSX files in the project.
18
+
19
+ ```
20
+ yarn global add @cozy/codemods
21
+ yarn global add jscodeshift@0.13.1
22
+ jscodeshift -t $(yarn global dir)/node_modules/@cozy/codemods/src/transforms/transform-viewer-components-props.js src babel --ignore-pattern=src/targets/ --extensions js,jsx,tsx --parser tsx
23
+ ```
24
+
25
+ You can do this manually by transferring the contents of `toolbarProps` to `componentsProps` under a `toolbarProps` property.
26
+ * **Viewer:** The `onlyOfficeProps` attribute from Viewer property has been moved into the `componentsProps` attribute.
27
+
28
+ You have to move the contents of `onlyOfficeProps ` to `componentsProps` under a `OnlyOfficeViewer` property.
29
+
1
30
  # [91.2.0](https://github.com/cozy/cozy-ui/compare/v91.1.1...v91.2.0) (2023-08-24)
2
31
 
3
32
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-ui",
3
- "version": "91.2.0",
3
+ "version": "92.0.0",
4
4
  "description": "Cozy apps UI SDK",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -17,13 +17,8 @@ The `Viewer` can display an **information panel** to show additional information
17
17
  * **currentIndex** : `<number>` – Index of the file to show
18
18
  * **currentURL** : `<string>` – Optionnal URL of the file
19
19
  * **className** : `<string>` – CSS classes
20
- * **toolbarProps** : `<object>` – Toolbar properties
21
- * **toolbarRef** : `<object>` – React reference of the toolbar node
22
- * **showToolbar** : `<boolean>` – Whether to show the toolbar or not. Note that the built-in close button is in the toolbar
23
- * **showClose** : `<boolean>` – Whether to show close button in toolbar
24
20
  * **showNavigation** : `<boolean>` – Whether to show left and right arrows to navigate between files
25
21
  * **renderFallbackExtraContent** : `<function>` – A render prop that is called when a file can't be displayed
26
- * **onlyOfficeProps** : `<object>` – Used to open an Only Office file (deprecated)
27
22
  * **disablePanel** : `<boolean>` – Show/Hide the panel containing more information about the file only on Desktop
28
23
  * **disableFooter** : `<boolean>` – Show/Hide the panel containing more information about the file only on Phone & Tablet devices
29
24
  * **editPathByModelProps** : `<object>` – Edit path by model properties
@@ -35,6 +30,12 @@ The `Viewer` can display an **information panel** to show additional information
35
30
  * **OnlyOfficeViewer** : `<object>` – Used to open an Only Office file
36
31
  * **isEnabled** : `<boolean>` – Whether Only Office is enabled on the server
37
32
  * **opener** : `<function>` – To open the Only Office file
33
+ * **toolbarProps** : `<object>` – Toolbar properties
34
+ * **toolbarRef** : `<object>` – React reference of the toolbar node
35
+ * **showToolbar** : `<boolean>` – Whether to show the toolbar or not. Note that the built-in close button is in the toolbar
36
+ * **showClose** : `<boolean>` – Whether to show close button in toolbar
37
+ * **showFilePath** : `<boolean>` – Whether to show file path below his name
38
+
38
39
 
39
40
  ### Demo
40
41
 
@@ -69,13 +70,15 @@ const files = [
69
70
  _id: 'audio',
70
71
  class: 'audio',
71
72
  name: 'Sample.mp3',
72
- mime: 'audio/mp3'
73
+ mime: 'audio/mp3',
74
+ dir_id: 'parent_folder'
73
75
  },
74
76
  {
75
77
  _id: 'slide',
76
78
  class: 'slide',
77
79
  name: 'Slide.pptx',
78
- mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
80
+ mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
81
+ dir_id: 'parent_folder'
79
82
  },
80
83
  {
81
84
  _id: 'pdf',
@@ -99,7 +102,8 @@ const files = [
99
102
  sourceSubCategory: "transport",
100
103
  subjects: ["permit", "driving"]
101
104
  }
102
- }
105
+ },
106
+ dir_id: 'parent_folder'
103
107
  },
104
108
  {
105
109
  _id: 'text',
@@ -163,7 +167,8 @@ const ShareButtonFake = () => {
163
167
  initialState = {
164
168
  viewerOpened: isTesting(),
165
169
  currentIndex: 0,
166
- showToolbarCloseButton: true
170
+ showToolbarCloseButton: true,
171
+ showToolbarWithPath: false
167
172
  }
168
173
 
169
174
  const initialVariants = [
@@ -183,13 +188,12 @@ const getURL = (file) => {
183
188
 
184
189
  const toggleViewer = () => setState({ viewerOpened: !state.viewerOpened })
185
190
  const handleToggleToolbarClose = () => setState({ showToolbarCloseButton: !state.showToolbarCloseButton })
191
+ const handleToggleToolbarWithPath = () => setState({ showToolbarWithPath: !state.showToolbarWithPath })
186
192
  const onFileChange = (file, nextIndex) => setState({ currentIndex: nextIndex, currentURL: getURL(file) })
187
193
  const editPathByModelProps = {
188
194
  information: `#!/Viewer?metadata=__NAME__`,
189
195
  page: `#!/Viewer`
190
- }
191
-
192
- ;
196
+ };
193
197
 
194
198
  <DemoProvider>
195
199
  <Variants initialVariants={initialVariants}>{
@@ -204,6 +208,12 @@ const editPathByModelProps = {
204
208
  checked={state.showToolbarCloseButton}
205
209
  onChange={handleToggleToolbarClose}
206
210
  />
211
+ <Checkbox
212
+ className="u-dib"
213
+ label="Show path"
214
+ checked={state.showToolbarWithPath}
215
+ onChange={handleToggleToolbarWithPath}
216
+ />
207
217
  </Card>
208
218
  )}
209
219
  <Button label="Open viewer" variant="ghost" size="small" onClick={toggleViewer} />
@@ -215,16 +225,17 @@ const editPathByModelProps = {
215
225
  currentURL={state.currentURL}
216
226
  showNavigation={variant.navigation}
217
227
  editPathByModelProps={editPathByModelProps}
218
- toolbarProps={{
219
- showToolbar: variant.toolbar,
220
- showClose: state.showToolbarCloseButton
221
- }}
222
228
  onCloseRequest={toggleViewer}
223
229
  onChangeRequest={onFileChange}
224
230
  componentsProps={{
225
231
  OnlyOfficeViewer: {
226
232
  isEnabled: variant.onlyOfficeEnabled,
227
233
  opener: () => alert('This is a demo, no Only Office opener here')
234
+ },
235
+ toolbarProps:{
236
+ showToolbar: variant.toolbar,
237
+ showClose: state.showToolbarCloseButton,
238
+ showFilePath: state.showToolbarWithPath
228
239
  }
229
240
  }}
230
241
  >
@@ -66,12 +66,10 @@ class Viewer extends Component {
66
66
  currentFile,
67
67
  hasPrevious,
68
68
  hasNext,
69
- toolbarProps,
70
69
  toolbarRef,
71
70
  showNavigation,
72
71
  renderFallbackExtraContent,
73
72
  validForPanel,
74
- onlyOfficeProps,
75
73
  componentsProps
76
74
  } = this.props
77
75
 
@@ -88,7 +86,7 @@ class Viewer extends Component {
88
86
  onPrevious={this.onPrevious}
89
87
  onNext={this.onNext}
90
88
  expanded={expanded}
91
- toolbarProps={{ ...toolbarProps, toolbarRef }}
89
+ toolbarProps={{ ...componentsProps.toolbarProps, toolbarRef }}
92
90
  showNavigation={showNavigation}
93
91
  showInfoPanel={validForPanel}
94
92
  >
@@ -96,7 +94,6 @@ class Viewer extends Component {
96
94
  file={currentFile}
97
95
  onClose={this.onClose}
98
96
  renderFallbackExtraContent={renderFallbackExtraContent}
99
- onlyOfficeProps={onlyOfficeProps}
100
97
  componentsProps={componentsProps}
101
98
  />
102
99
  </ViewerControls>
@@ -114,19 +111,11 @@ Viewer.propTypes = {
114
111
  onCloseRequest: PropTypes.func,
115
112
  /** Called with (nextFile, nextIndex) when the user requests to navigate to another file */
116
113
  onChangeRequest: PropTypes.func,
117
- toolbarProps: PropTypes.shape(toolbarPropsPropType),
118
114
  toolbarRef: PropTypes.object,
119
115
  /** Whether to show left and right arrows to navigate between files */
120
116
  showNavigation: PropTypes.bool,
121
117
  /** A render prop that is called when a file can't be displayed */
122
118
  renderFallbackExtraContent: PropTypes.func,
123
- /** Used to open an Only Office file */
124
- onlyOfficeProps: PropTypes.shape({
125
- /** Whether Only Office is enabled on the server */
126
- isEnabled: PropTypes.bool,
127
- /** To open the Only Office file */
128
- opener: PropTypes.func
129
- }),
130
119
  validForPanel: PropTypes.bool,
131
120
  /* Props passed to components with the same name */
132
121
  componentsProps: PropTypes.shape({
@@ -136,7 +125,8 @@ Viewer.propTypes = {
136
125
  isEnabled: PropTypes.bool,
137
126
  /** To open the Only Office file */
138
127
  opener: PropTypes.func
139
- })
128
+ }),
129
+ toolbarProps: PropTypes.shape(toolbarPropsPropType)
140
130
  })
141
131
  }
142
132
 
@@ -23,6 +23,7 @@ const ViewerContainer = props => {
23
23
  disablePanel,
24
24
  editPathByModelProps,
25
25
  children,
26
+ componentsProps,
26
27
  ...rest
27
28
  } = props
28
29
  const { currentIndex, files, currentURL } = props
@@ -35,6 +36,15 @@ const ViewerContainer = props => {
35
36
  const validForPanel =
36
37
  isValidForPanel({ file: currentFile }) && isDesktop && !disablePanel
37
38
 
39
+ const componentsPropsWithDefault = {
40
+ ...componentsProps,
41
+ toolbarProps: {
42
+ showToolbar: true,
43
+ showClose: true,
44
+ ...componentsProps?.toolbarProps
45
+ }
46
+ }
47
+
38
48
  return (
39
49
  <ViewerSnackbarProvider>
40
50
  <ActionMenuProvider editPathByModelProps={editPathByModelProps}>
@@ -45,6 +55,7 @@ const ViewerContainer = props => {
45
55
  <EncryptedProvider url={currentURL}>
46
56
  <Viewer
47
57
  {...rest}
58
+ componentsProps={componentsPropsWithDefault}
48
59
  currentFile={currentFile}
49
60
  hasPrevious={hasPrevious}
50
61
  hasNext={hasNext}
@@ -79,19 +90,10 @@ ViewerContainer.propTypes = {
79
90
  onCloseRequest: PropTypes.func,
80
91
  /** Called with (nextFile, nextIndex) when the user requests to navigate to another file */
81
92
  onChangeRequest: PropTypes.func,
82
- /** Toolbar properties */
83
- toolbarProps: PropTypes.shape(toolbarPropsPropType),
84
93
  /** Whether to show left and right arrows to navigate between files */
85
94
  showNavigation: PropTypes.bool,
86
95
  /** A render prop that is called when a file can't be displayed */
87
96
  renderFallbackExtraContent: PropTypes.func,
88
- /** Used to open an Only Office file */
89
- onlyOfficeProps: PropTypes.shape({
90
- /** Whether Only Office is enabled on the server */
91
- isEnabled: PropTypes.bool,
92
- /** To open the Only Office file */
93
- opener: PropTypes.func
94
- }),
95
97
  /** Edit path by model properties */
96
98
  editPathByModelProps: PropTypes.shape({
97
99
  /** URL used to edit the file when editing a `information` type metadata (text, date) */
@@ -111,13 +113,14 @@ ViewerContainer.propTypes = {
111
113
  isEnabled: PropTypes.bool,
112
114
  /** To open the Only Office file */
113
115
  opener: PropTypes.func
114
- })
116
+ }),
117
+ /** Toolbar properties */
118
+ toolbarProps: PropTypes.shape(toolbarPropsPropType)
115
119
  })
116
120
  }
117
121
 
118
122
  ViewerContainer.defaultProps = {
119
123
  currentIndex: 0,
120
- toolbarProps: { showToolbar: true, showClose: true },
121
124
  showNavigation: true
122
125
  }
123
126
 
@@ -17,6 +17,7 @@ import DownloadIcon from '../../Icons/Download'
17
17
  import { withViewerLocales } from '../hoc/withViewerLocales'
18
18
  import { downloadFile } from '../helpers'
19
19
  import { useEncrypted } from '../providers/EncryptedProvider'
20
+ import { ToolbarFilePath } from './ToolbarFilePath'
20
21
 
21
22
  import styles from './styles.styl'
22
23
 
@@ -36,7 +37,8 @@ const Toolbar = ({
36
37
  onClose,
37
38
  t,
38
39
  toolbarRef,
39
- breakpoints: { isDesktop }
40
+ breakpoints: { isDesktop },
41
+ showFilePath
40
42
  }) => {
41
43
  const client = useClient()
42
44
  const classes = useClasses()
@@ -62,14 +64,17 @@ const Toolbar = ({
62
64
  <Icon icon={PreviousIcon} />
63
65
  </IconButton>
64
66
  )}
65
- <Typography
66
- className="u-pl-half"
67
- variant="h3"
68
- color={isDesktop ? 'inherit' : 'textPrimary'}
69
- noWrap
70
- >
71
- {file.name}
72
- </Typography>
67
+ <div className="u-pl-half">
68
+ <Typography
69
+ variant="h3"
70
+ color={isDesktop ? 'inherit' : 'textPrimary'}
71
+ noWrap
72
+ >
73
+ {file.name}
74
+ </Typography>
75
+ {showFilePath ? <ToolbarFilePath file={file} /> : null}
76
+ </div>
77
+
73
78
  <div className="u-ml-auto u-ph-1">
74
79
  {isDesktop && (
75
80
  <Button
@@ -90,7 +95,8 @@ Toolbar.propTypes = {
90
95
  onMouseEnter: PropTypes.func.isRequired,
91
96
  onMouseLeave: PropTypes.func.isRequired,
92
97
  file: PropTypes.object.isRequired,
93
- onClose: PropTypes.func
98
+ onClose: PropTypes.func,
99
+ showFilePath: PropTypes.bool
94
100
  }
95
101
 
96
102
  export default flow(
@@ -0,0 +1,58 @@
1
+ import React, { useMemo } from 'react'
2
+
3
+ import { useClient, useQuery, models } from 'cozy-client'
4
+
5
+ import Link from '../../Link'
6
+ import AppLinker from '../../AppLinker'
7
+ import FilePath from '../../FilePath'
8
+ import useBreakpoints from '../../hooks/useBreakpoints'
9
+
10
+ import { makeWebLink, normalizeAndSpreadAttributes } from '../helpers'
11
+ import { buildFileByIdQuery } from '../queries'
12
+
13
+ const { ensureFilePath } = models.file
14
+
15
+ const ToolbarFilePath = ({ file }) => {
16
+ const client = useClient()
17
+ const { isDesktop } = useBreakpoints()
18
+
19
+ const normalizeFile = normalizeAndSpreadAttributes(file)
20
+
21
+ const parentQuery = buildFileByIdQuery(normalizeFile.dir_id)
22
+ const parentResult = useQuery(parentQuery.definition, {
23
+ ...parentQuery.options,
24
+ enabled: !!normalizeFile.dir_id
25
+ })
26
+
27
+ const fileWithPath = useMemo(
28
+ () =>
29
+ parentResult.data
30
+ ? ensureFilePath(normalizeFile, parentResult.data)
31
+ : undefined,
32
+ [normalizeFile, parentResult.data]
33
+ )
34
+
35
+ if (fileWithPath) {
36
+ const appSlug = 'drive'
37
+ const nativePath = `/folder/${fileWithPath.dir_id}`
38
+ const path = fileWithPath.path.replace(fileWithPath.name, '')
39
+ const link = makeWebLink({ client, path: nativePath, slug: appSlug })
40
+
41
+ if (isDesktop && link) {
42
+ return (
43
+ <AppLinker app={{ slug: appSlug }} nativePath={nativePath} href={link}>
44
+ {({ href, onClick }) => (
45
+ <Link href={href} onClick={onClick} color="inherit">
46
+ <FilePath className="u-white">{path}</FilePath>
47
+ </Link>
48
+ )}
49
+ </AppLinker>
50
+ )
51
+ }
52
+ return <FilePath className={isDesktop ? 'u-white' : null}>{path}</FilePath>
53
+ }
54
+
55
+ return null
56
+ }
57
+
58
+ export { ToolbarFilePath }
@@ -19,10 +19,6 @@ import OnlyOfficeViewer from '../ViewersByFile/OnlyOfficeViewer'
19
19
 
20
20
  import { useEncrypted } from '../providers/EncryptedProvider'
21
21
 
22
- import createDepreciationLogger from '../../helpers/createDepreciationLogger'
23
-
24
- const logDepecratedOnlyOfficeProps = createDepreciationLogger()
25
-
26
22
  const { isPlainText } = models.file
27
23
 
28
24
  export const getViewerComponentName = ({
@@ -63,20 +59,11 @@ const ViewerByFile = ({
63
59
  gestures,
64
60
  gesturesRef,
65
61
  onSwipe,
66
- onlyOfficeProps,
67
62
  breakpoints: { isDesktop },
68
63
  componentsProps
69
64
  }) => {
70
- if (onlyOfficeProps) {
71
- logDepecratedOnlyOfficeProps(
72
- 'onlyOfficeProps in Viewer is deprecated. Please use componentsProps.OnlyOfficeViewer instead.'
73
- )
74
- }
75
-
76
- const isOnlyOfficeEnabled =
77
- componentsProps?.OnlyOfficeViewer?.isEnabled || onlyOfficeProps?.isEnabled
78
- const onlyOfficeOpener =
79
- componentsProps?.OnlyOfficeViewer?.opener || onlyOfficeProps?.opener
65
+ const isOnlyOfficeEnabled = componentsProps?.OnlyOfficeViewer?.isEnabled
66
+ const onlyOfficeOpener = componentsProps?.OnlyOfficeViewer?.opener
80
67
 
81
68
  const { url } = useEncrypted()
82
69
 
@@ -108,7 +95,6 @@ ViewerByFile.propTypes = {
108
95
  file: FileDoctype.isRequired,
109
96
  onClose: PropTypes.func.isRequired,
110
97
  renderFallbackExtraContent: PropTypes.func,
111
- onlyOfficeProps: PropTypes.object,
112
98
  // gestures, gesturesRef and onSwipe are got from ViewerControls
113
99
  gestures: PropTypes.object,
114
100
  gesturesRef: PropTypes.object,
@@ -115,7 +115,7 @@ class ViewerControls extends Component {
115
115
  classes,
116
116
  breakpoints: { isDesktop }
117
117
  } = this.props
118
- const { showToolbar, showClose, toolbarRef } = toolbarProps
118
+ const { showToolbar, showClose, toolbarRef, showFilePath } = toolbarProps
119
119
  const { hidden } = this.state
120
120
 
121
121
  const shouldDisplayContentTop = isValidForPanel({ file })
@@ -140,6 +140,7 @@ class ViewerControls extends Component {
140
140
  onClose={showClose && onClose}
141
141
  onMouseEnter={this.showControls}
142
142
  onMouseLeave={this.hideControls}
143
+ showFilePath={showFilePath}
143
144
  />
144
145
  )}
145
146
  {showNavigation && isDesktop && hasPrevious && (
@@ -1,11 +1,12 @@
1
- import { models } from 'cozy-client'
1
+ import { models, generateWebLink } from 'cozy-client'
2
2
  import flag from 'cozy-flags'
3
3
 
4
4
  const {
5
5
  isEncrypted,
6
6
  isFromKonnector,
7
7
  hasQualifications,
8
- hasCertifications
8
+ hasCertifications,
9
+ normalize
9
10
  } = models.file
10
11
 
11
12
  export const knownDateMetadataNames = [
@@ -168,3 +169,37 @@ export const isEditableAttribute = (name, file) => {
168
169
  ((name === 'issueDate' && !isFromKonnector(file)) || name !== 'issueDate')
169
170
  )
170
171
  }
172
+
173
+ export const normalizeAndSpreadAttributes = rawFile => {
174
+ const normalizedFile = normalize(rawFile)
175
+
176
+ return {
177
+ ...normalizedFile,
178
+ ...normalizedFile?.attributes
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Return a web link to an application in the Cozy environment with the specified path
184
+ * @param {object} param
185
+ * @param {CozyClient} param.client - Instance of CozyClient
186
+ * @param {string} param.slug - Slug of the application
187
+ * @param {string} param.path - Path into the application
188
+ * @returns {string} web link
189
+ */
190
+ export const makeWebLink = ({ client, slug, path }) => {
191
+ try {
192
+ const cozyURL = new URL(client.getStackClient().uri)
193
+ const { subdomain: subDomainType } = client.getInstanceOptions()
194
+
195
+ return generateWebLink({
196
+ pathname: '/',
197
+ cozyUrl: cozyURL.origin,
198
+ slug,
199
+ hash: path,
200
+ subDomainType
201
+ })
202
+ } catch (e) {
203
+ return null
204
+ }
205
+ }
@@ -6,5 +6,7 @@ export const toolbarPropsPropType = {
6
6
  /** Whether to show close button in toolbar */
7
7
  showClose: PropTypes.bool,
8
8
  /** React reference of the toolbar node */
9
- toolbarRef: PropTypes.object
9
+ toolbarRef: PropTypes.object,
10
+ /** Whether to show file path below his name */
11
+ showFilePath: PropTypes.bool
10
12
  }
@@ -9,3 +9,12 @@ export const buildContactByIdsQuery = (ids = []) => ({
9
9
  fetchPolicy: defaultFetchPolicy
10
10
  }
11
11
  })
12
+
13
+ export const buildFileByIdQuery = fileId => ({
14
+ definition: () => Q('io.cozy.files').getById(fileId),
15
+ options: {
16
+ as: `io.cozy.files/${fileId}`,
17
+ fetchPolicy: defaultFetchPolicy,
18
+ singleDocData: true
19
+ }
20
+ })
@@ -103,12 +103,10 @@ var Viewer = /*#__PURE__*/function (_Component) {
103
103
  currentFile = _this$props3.currentFile,
104
104
  hasPrevious = _this$props3.hasPrevious,
105
105
  hasNext = _this$props3.hasNext,
106
- toolbarProps = _this$props3.toolbarProps,
107
106
  toolbarRef = _this$props3.toolbarRef,
108
107
  showNavigation = _this$props3.showNavigation,
109
108
  renderFallbackExtraContent = _this$props3.renderFallbackExtraContent,
110
109
  validForPanel = _this$props3.validForPanel,
111
- onlyOfficeProps = _this$props3.onlyOfficeProps,
112
110
  componentsProps = _this$props3.componentsProps; // this `expanded` property makes the next/previous controls cover the displayed image
113
111
 
114
112
  var expanded = currentFile && currentFile.class === 'image';
@@ -120,7 +118,7 @@ var Viewer = /*#__PURE__*/function (_Component) {
120
118
  onPrevious: this.onPrevious,
121
119
  onNext: this.onNext,
122
120
  expanded: expanded,
123
- toolbarProps: _objectSpread(_objectSpread({}, toolbarProps), {}, {
121
+ toolbarProps: _objectSpread(_objectSpread({}, componentsProps.toolbarProps), {}, {
124
122
  toolbarRef: toolbarRef
125
123
  }),
126
124
  showNavigation: showNavigation,
@@ -129,7 +127,6 @@ var Viewer = /*#__PURE__*/function (_Component) {
129
127
  file: currentFile,
130
128
  onClose: this.onClose,
131
129
  renderFallbackExtraContent: renderFallbackExtraContent,
132
- onlyOfficeProps: onlyOfficeProps,
133
130
  componentsProps: componentsProps
134
131
  })));
135
132
  }
@@ -149,7 +146,6 @@ Viewer.propTypes = {
149
146
 
150
147
  /** Called with (nextFile, nextIndex) when the user requests to navigate to another file */
151
148
  onChangeRequest: PropTypes.func,
152
- toolbarProps: PropTypes.shape(toolbarPropsPropType),
153
149
  toolbarRef: PropTypes.object,
154
150
 
155
151
  /** Whether to show left and right arrows to navigate between files */
@@ -157,15 +153,6 @@ Viewer.propTypes = {
157
153
 
158
154
  /** A render prop that is called when a file can't be displayed */
159
155
  renderFallbackExtraContent: PropTypes.func,
160
-
161
- /** Used to open an Only Office file */
162
- onlyOfficeProps: PropTypes.shape({
163
- /** Whether Only Office is enabled on the server */
164
- isEnabled: PropTypes.bool,
165
-
166
- /** To open the Only Office file */
167
- opener: PropTypes.func
168
- }),
169
156
  validForPanel: PropTypes.bool,
170
157
 
171
158
  /* Props passed to components with the same name */
@@ -177,7 +164,8 @@ Viewer.propTypes = {
177
164
 
178
165
  /** To open the Only Office file */
179
166
  opener: PropTypes.func
180
- })
167
+ }),
168
+ toolbarProps: PropTypes.shape(toolbarPropsPropType)
181
169
  })
182
170
  };
183
171
  export default Viewer;
@@ -1,6 +1,12 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
3
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- var _excluded = ["className", "disableFooter", "disablePanel", "editPathByModelProps", "children"];
4
+ var _excluded = ["className", "disableFooter", "disablePanel", "editPathByModelProps", "children", "componentsProps"];
5
+
6
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
7
+
8
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
9
+
4
10
  import React, { createRef } from 'react';
5
11
  import PropTypes from 'prop-types';
6
12
  import cx from 'classnames';
@@ -25,6 +31,7 @@ var ViewerContainer = function ViewerContainer(props) {
25
31
  disablePanel = props.disablePanel,
26
32
  editPathByModelProps = props.editPathByModelProps,
27
33
  children = props.children,
34
+ componentsProps = props.componentsProps,
28
35
  rest = _objectWithoutProperties(props, _excluded);
29
36
 
30
37
  var currentIndex = props.currentIndex,
@@ -42,6 +49,14 @@ var ViewerContainer = function ViewerContainer(props) {
42
49
  var validForPanel = isValidForPanel({
43
50
  file: currentFile
44
51
  }) && isDesktop && !disablePanel;
52
+
53
+ var componentsPropsWithDefault = _objectSpread(_objectSpread({}, componentsProps), {}, {
54
+ toolbarProps: _objectSpread({
55
+ showToolbar: true,
56
+ showClose: true
57
+ }, componentsProps === null || componentsProps === void 0 ? void 0 : componentsProps.toolbarProps)
58
+ });
59
+
45
60
  return /*#__PURE__*/React.createElement(ViewerSnackbarProvider, null, /*#__PURE__*/React.createElement(ActionMenuProvider, {
46
61
  editPathByModelProps: editPathByModelProps
47
62
  }, /*#__PURE__*/React.createElement("div", {
@@ -50,6 +65,7 @@ var ViewerContainer = function ViewerContainer(props) {
50
65
  }, /*#__PURE__*/React.createElement(EncryptedProvider, {
51
66
  url: currentURL
52
67
  }, /*#__PURE__*/React.createElement(Viewer, _extends({}, rest, {
68
+ componentsProps: componentsPropsWithDefault,
53
69
  currentFile: currentFile,
54
70
  hasPrevious: hasPrevious,
55
71
  hasNext: hasNext,
@@ -80,24 +96,12 @@ ViewerContainer.propTypes = {
80
96
  /** Called with (nextFile, nextIndex) when the user requests to navigate to another file */
81
97
  onChangeRequest: PropTypes.func,
82
98
 
83
- /** Toolbar properties */
84
- toolbarProps: PropTypes.shape(toolbarPropsPropType),
85
-
86
99
  /** Whether to show left and right arrows to navigate between files */
87
100
  showNavigation: PropTypes.bool,
88
101
 
89
102
  /** A render prop that is called when a file can't be displayed */
90
103
  renderFallbackExtraContent: PropTypes.func,
91
104
 
92
- /** Used to open an Only Office file */
93
- onlyOfficeProps: PropTypes.shape({
94
- /** Whether Only Office is enabled on the server */
95
- isEnabled: PropTypes.bool,
96
-
97
- /** To open the Only Office file */
98
- opener: PropTypes.func
99
- }),
100
-
101
105
  /** Edit path by model properties */
102
106
  editPathByModelProps: PropTypes.shape({
103
107
  /** URL used to edit the file when editing a `information` type metadata (text, date) */
@@ -122,15 +126,14 @@ ViewerContainer.propTypes = {
122
126
 
123
127
  /** To open the Only Office file */
124
128
  opener: PropTypes.func
125
- })
129
+ }),
130
+
131
+ /** Toolbar properties */
132
+ toolbarProps: PropTypes.shape(toolbarPropsPropType)
126
133
  })
127
134
  };
128
135
  ViewerContainer.defaultProps = {
129
136
  currentIndex: 0,
130
- toolbarProps: {
131
- showToolbar: true,
132
- showClose: true
133
- },
134
137
  showNavigation: true
135
138
  };
136
139
  export default ViewerContainer;
@@ -15,6 +15,7 @@ import DownloadIcon from "cozy-ui/transpiled/react/Icons/Download";
15
15
  import { withViewerLocales } from "cozy-ui/transpiled/react/Viewer/hoc/withViewerLocales";
16
16
  import { downloadFile } from "cozy-ui/transpiled/react/Viewer/helpers";
17
17
  import { useEncrypted } from "cozy-ui/transpiled/react/Viewer/providers/EncryptedProvider";
18
+ import { ToolbarFilePath } from "cozy-ui/transpiled/react/Viewer/components/ToolbarFilePath";
18
19
  var styles = {
19
20
  "viewer-nav": "styles__viewer-nav___1MSd7",
20
21
  "viewer-nav--visible": "styles__viewer-nav--visible___h_KJD",
@@ -44,7 +45,8 @@ var Toolbar = function Toolbar(_ref) {
44
45
  onClose = _ref.onClose,
45
46
  t = _ref.t,
46
47
  toolbarRef = _ref.toolbarRef,
47
- isDesktop = _ref.breakpoints.isDesktop;
48
+ isDesktop = _ref.breakpoints.isDesktop,
49
+ showFilePath = _ref.showFilePath;
48
50
  var client = useClient();
49
51
  var classes = useClasses();
50
52
 
@@ -65,12 +67,15 @@ var Toolbar = function Toolbar(_ref) {
65
67
  })
66
68
  }, /*#__PURE__*/React.createElement(Icon, {
67
69
  icon: PreviousIcon
68
- })), /*#__PURE__*/React.createElement(Typography, {
69
- className: "u-pl-half",
70
+ })), /*#__PURE__*/React.createElement("div", {
71
+ className: "u-pl-half"
72
+ }, /*#__PURE__*/React.createElement(Typography, {
70
73
  variant: "h3",
71
74
  color: isDesktop ? 'inherit' : 'textPrimary',
72
75
  noWrap: true
73
- }, file.name), /*#__PURE__*/React.createElement("div", {
76
+ }, file.name), showFilePath ? /*#__PURE__*/React.createElement(ToolbarFilePath, {
77
+ file: file
78
+ }) : null), /*#__PURE__*/React.createElement("div", {
74
79
  className: "u-ml-auto u-ph-1"
75
80
  }, isDesktop && /*#__PURE__*/React.createElement(Button, {
76
81
  className: "u-white",
@@ -92,6 +97,7 @@ Toolbar.propTypes = {
92
97
  onMouseEnter: PropTypes.func.isRequired,
93
98
  onMouseLeave: PropTypes.func.isRequired,
94
99
  file: PropTypes.object.isRequired,
95
- onClose: PropTypes.func
100
+ onClose: PropTypes.func,
101
+ showFilePath: PropTypes.bool
96
102
  };
97
103
  export default flow(withBreakpoints(), withViewerLocales)(Toolbar);
@@ -0,0 +1,71 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
4
+
5
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
6
+
7
+ import React, { useMemo } from 'react';
8
+ import { useClient, useQuery, models } from 'cozy-client';
9
+ import Link from "cozy-ui/transpiled/react/Link";
10
+ import AppLinker from "cozy-ui/transpiled/react/AppLinker";
11
+ import FilePath from "cozy-ui/transpiled/react/FilePath";
12
+ import useBreakpoints from "cozy-ui/transpiled/react/hooks/useBreakpoints";
13
+ import { makeWebLink, normalizeAndSpreadAttributes } from "cozy-ui/transpiled/react/Viewer/helpers";
14
+ import { buildFileByIdQuery } from "cozy-ui/transpiled/react/Viewer/queries";
15
+ var ensureFilePath = models.file.ensureFilePath;
16
+
17
+ var ToolbarFilePath = function ToolbarFilePath(_ref) {
18
+ var file = _ref.file;
19
+ var client = useClient();
20
+
21
+ var _useBreakpoints = useBreakpoints(),
22
+ isDesktop = _useBreakpoints.isDesktop;
23
+
24
+ var normalizeFile = normalizeAndSpreadAttributes(file);
25
+ var parentQuery = buildFileByIdQuery(normalizeFile.dir_id);
26
+ var parentResult = useQuery(parentQuery.definition, _objectSpread(_objectSpread({}, parentQuery.options), {}, {
27
+ enabled: !!normalizeFile.dir_id
28
+ }));
29
+ var fileWithPath = useMemo(function () {
30
+ return parentResult.data ? ensureFilePath(normalizeFile, parentResult.data) : undefined;
31
+ }, [normalizeFile, parentResult.data]);
32
+
33
+ if (fileWithPath) {
34
+ var appSlug = 'drive';
35
+ var nativePath = "/folder/".concat(fileWithPath.dir_id);
36
+ var path = fileWithPath.path.replace(fileWithPath.name, '');
37
+ var link = makeWebLink({
38
+ client: client,
39
+ path: nativePath,
40
+ slug: appSlug
41
+ });
42
+
43
+ if (isDesktop && link) {
44
+ return /*#__PURE__*/React.createElement(AppLinker, {
45
+ app: {
46
+ slug: appSlug
47
+ },
48
+ nativePath: nativePath,
49
+ href: link
50
+ }, function (_ref2) {
51
+ var href = _ref2.href,
52
+ onClick = _ref2.onClick;
53
+ return /*#__PURE__*/React.createElement(Link, {
54
+ href: href,
55
+ onClick: onClick,
56
+ color: "inherit"
57
+ }, /*#__PURE__*/React.createElement(FilePath, {
58
+ className: "u-white"
59
+ }, path));
60
+ });
61
+ }
62
+
63
+ return /*#__PURE__*/React.createElement(FilePath, {
64
+ className: isDesktop ? 'u-white' : null
65
+ }, path);
66
+ }
67
+
68
+ return null;
69
+ };
70
+
71
+ export { ToolbarFilePath };
@@ -14,8 +14,6 @@ import NoViewer from "cozy-ui/transpiled/react/Viewer/NoViewer";
14
14
  import ShortcutViewer from "cozy-ui/transpiled/react/Viewer/ViewersByFile/ShortcutViewer";
15
15
  import OnlyOfficeViewer from "cozy-ui/transpiled/react/Viewer/ViewersByFile/OnlyOfficeViewer";
16
16
  import { useEncrypted } from "cozy-ui/transpiled/react/Viewer/providers/EncryptedProvider";
17
- import createDepreciationLogger from "cozy-ui/transpiled/react/helpers/createDepreciationLogger";
18
- var logDepecratedOnlyOfficeProps = createDepreciationLogger();
19
17
  var isPlainText = models.file.isPlainText;
20
18
  export var getViewerComponentName = function getViewerComponentName(_ref) {
21
19
  var file = _ref.file,
@@ -61,16 +59,10 @@ var ViewerByFile = function ViewerByFile(_ref2) {
61
59
  gestures = _ref2.gestures,
62
60
  gesturesRef = _ref2.gesturesRef,
63
61
  onSwipe = _ref2.onSwipe,
64
- onlyOfficeProps = _ref2.onlyOfficeProps,
65
62
  isDesktop = _ref2.breakpoints.isDesktop,
66
63
  componentsProps = _ref2.componentsProps;
67
-
68
- if (onlyOfficeProps) {
69
- logDepecratedOnlyOfficeProps('onlyOfficeProps in Viewer is deprecated. Please use componentsProps.OnlyOfficeViewer instead.');
70
- }
71
-
72
- var isOnlyOfficeEnabled = (componentsProps === null || componentsProps === void 0 ? void 0 : (_componentsProps$Only = componentsProps.OnlyOfficeViewer) === null || _componentsProps$Only === void 0 ? void 0 : _componentsProps$Only.isEnabled) || (onlyOfficeProps === null || onlyOfficeProps === void 0 ? void 0 : onlyOfficeProps.isEnabled);
73
- var onlyOfficeOpener = (componentsProps === null || componentsProps === void 0 ? void 0 : (_componentsProps$Only2 = componentsProps.OnlyOfficeViewer) === null || _componentsProps$Only2 === void 0 ? void 0 : _componentsProps$Only2.opener) || (onlyOfficeProps === null || onlyOfficeProps === void 0 ? void 0 : onlyOfficeProps.opener);
64
+ var isOnlyOfficeEnabled = componentsProps === null || componentsProps === void 0 ? void 0 : (_componentsProps$Only = componentsProps.OnlyOfficeViewer) === null || _componentsProps$Only === void 0 ? void 0 : _componentsProps$Only.isEnabled;
65
+ var onlyOfficeOpener = componentsProps === null || componentsProps === void 0 ? void 0 : (_componentsProps$Only2 = componentsProps.OnlyOfficeViewer) === null || _componentsProps$Only2 === void 0 ? void 0 : _componentsProps$Only2.opener;
74
66
 
75
67
  var _useEncrypted = useEncrypted(),
76
68
  url = _useEncrypted.url;
@@ -98,7 +90,6 @@ ViewerByFile.propTypes = {
98
90
  file: FileDoctype.isRequired,
99
91
  onClose: PropTypes.func.isRequired,
100
92
  renderFallbackExtraContent: PropTypes.func,
101
- onlyOfficeProps: PropTypes.object,
102
93
  // gestures, gesturesRef and onSwipe are got from ViewerControls
103
94
  gestures: PropTypes.object,
104
95
  gesturesRef: PropTypes.object,
@@ -166,7 +166,8 @@ var ViewerControls = /*#__PURE__*/function (_Component) {
166
166
  isDesktop = _this$props.breakpoints.isDesktop;
167
167
  var showToolbar = toolbarProps.showToolbar,
168
168
  showClose = toolbarProps.showClose,
169
- toolbarRef = toolbarProps.toolbarRef;
169
+ toolbarRef = toolbarProps.toolbarRef,
170
+ showFilePath = toolbarProps.showFilePath;
170
171
  var hidden = this.state.hidden;
171
172
  var shouldDisplayContentTop = isValidForPanel({
172
173
  file: file
@@ -181,7 +182,8 @@ var ViewerControls = /*#__PURE__*/function (_Component) {
181
182
  file: file,
182
183
  onClose: showClose && onClose,
183
184
  onMouseEnter: this.showControls,
184
- onMouseLeave: this.hideControls
185
+ onMouseLeave: this.hideControls,
186
+ showFilePath: showFilePath
185
187
  }), showNavigation && isDesktop && hasPrevious && /*#__PURE__*/React.createElement(Navigation, {
186
188
  className: styles['viewer-nav--previous'],
187
189
  hidden: hidden,
@@ -1,13 +1,20 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
1
2
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
3
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
4
+
5
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
6
+
7
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
8
+
3
9
  import _regeneratorRuntime from "@babel/runtime/regenerator";
4
- import { models } from 'cozy-client';
10
+ import { models, generateWebLink } from 'cozy-client';
5
11
  import flag from 'cozy-flags';
6
12
  var _models$file = models.file,
7
13
  isEncrypted = _models$file.isEncrypted,
8
14
  isFromKonnector = _models$file.isFromKonnector,
9
15
  hasQualifications = _models$file.hasQualifications,
10
- hasCertifications = _models$file.hasCertifications;
16
+ hasCertifications = _models$file.hasCertifications,
17
+ normalize = _models$file.normalize;
11
18
  export var knownDateMetadataNames = ['AObtentionDate', 'BObtentionDate', 'CObtentionDate', 'DObtentionDate', 'obtentionDate', 'expirationDate', 'referencedDate', 'issueDate', 'shootingDate', 'date', 'datetime'];
12
19
  export var knownInformationMetadataNames = flag('mespapiers.migrated.metadata') ? ['number', 'country', 'refTaxIncome', 'contractType', 'noticePeriod'] : ['number', 'cafFileNumber', 'cardNumber', 'vinNumber', 'ibanNumber', 'country', 'passportNumber', 'refTaxIncome', 'contractType', 'noticePeriod'];
13
20
  export var knownOtherMetadataNames = ['contact', 'page', 'qualification'];
@@ -151,4 +158,39 @@ export var buildEditAttributePath = function buildEditAttributePath(editPathByMo
151
158
  export var isEditableAttribute = function isEditableAttribute(name, file) {
152
159
  var isNotEditableAttributes = ['datetime', 'qualification'];
153
160
  return !isNotEditableAttributes.includes(name) && (name === 'issueDate' && !isFromKonnector(file) || name !== 'issueDate');
161
+ };
162
+ export var normalizeAndSpreadAttributes = function normalizeAndSpreadAttributes(rawFile) {
163
+ var normalizedFile = normalize(rawFile);
164
+ return _objectSpread(_objectSpread({}, normalizedFile), normalizedFile === null || normalizedFile === void 0 ? void 0 : normalizedFile.attributes);
165
+ };
166
+ /**
167
+ * Return a web link to an application in the Cozy environment with the specified path
168
+ * @param {object} param
169
+ * @param {CozyClient} param.client - Instance of CozyClient
170
+ * @param {string} param.slug - Slug of the application
171
+ * @param {string} param.path - Path into the application
172
+ * @returns {string} web link
173
+ */
174
+
175
+ export var makeWebLink = function makeWebLink(_ref6) {
176
+ var client = _ref6.client,
177
+ slug = _ref6.slug,
178
+ path = _ref6.path;
179
+
180
+ try {
181
+ var cozyURL = new URL(client.getStackClient().uri);
182
+
183
+ var _client$getInstanceOp = client.getInstanceOptions(),
184
+ subDomainType = _client$getInstanceOp.subdomain;
185
+
186
+ return generateWebLink({
187
+ pathname: '/',
188
+ cozyUrl: cozyURL.origin,
189
+ slug: slug,
190
+ hash: path,
191
+ subDomainType: subDomainType
192
+ });
193
+ } catch (e) {
194
+ return null;
195
+ }
154
196
  };
@@ -7,5 +7,8 @@ export var toolbarPropsPropType = {
7
7
  showClose: PropTypes.bool,
8
8
 
9
9
  /** React reference of the toolbar node */
10
- toolbarRef: PropTypes.object
10
+ toolbarRef: PropTypes.object,
11
+
12
+ /** Whether to show file path below his name */
13
+ showFilePath: PropTypes.bool
11
14
  };
@@ -11,4 +11,16 @@ export var buildContactByIdsQuery = function buildContactByIdsQuery() {
11
11
  fetchPolicy: defaultFetchPolicy
12
12
  }
13
13
  };
14
+ };
15
+ export var buildFileByIdQuery = function buildFileByIdQuery(fileId) {
16
+ return {
17
+ definition: function definition() {
18
+ return Q('io.cozy.files').getById(fileId);
19
+ },
20
+ options: {
21
+ as: "io.cozy.files/".concat(fileId),
22
+ fetchPolicy: defaultFetchPolicy,
23
+ singleDocData: true
24
+ }
25
+ };
14
26
  };