@ossy/resources 3.10.0 → 3.11.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/package.json +4 -4
- package/src/CreateDirectory.jsx +47 -53
- package/src/CreateDocument.jsx +1 -0
- package/src/GenericResourceForm.jsx +49 -31
- package/src/ResourceDialogMove.jsx +99 -50
- package/src/ResourceGrid.jsx +36 -84
- package/src/ResourceList.jsx +10 -1
- package/src/ResourcePanel.jsx +96 -17
- package/src/ResourceShareDialog.jsx +50 -12
- package/src/Upload.jsx +25 -8
- package/src/batch-delete.flow.js +81 -0
- package/src/batch-download.flow.js +69 -0
- package/src/cancel-upload.action.js +4 -0
- package/src/cancel-upload.flow.js +40 -0
- package/src/close-share.action.js +4 -0
- package/src/confirm-upload.action.js +4 -0
- package/src/copy-share-link.action.js +4 -0
- package/src/create-directory.action.js +5 -0
- package/src/create-directory.flow.js +30 -0
- package/src/create-directory.form.js +5 -0
- package/src/create-directory.schema.js +9 -0
- package/src/create-document.flow.js +36 -0
- package/src/create-document.form.js +5 -0
- package/src/create-document.schema.js +11 -0
- package/src/create.action.js +5 -1
- package/src/delete-directory.flow.js +39 -0
- package/src/delete-file.flow.js +32 -0
- package/src/done-selecting.action.js +5 -0
- package/src/download-file.flow.js +31 -0
- package/src/download-resource.action.js +4 -0
- package/src/download-selected.action.js +4 -0
- package/src/en.translations.json +18 -0
- package/src/finish-upload.action.js +4 -0
- package/src/index.js +42 -0
- package/src/list.task.js +17 -6
- package/src/list.task.spec.js +81 -0
- package/src/make-private-resource.flow.js +72 -0
- package/src/make-private.action.js +4 -0
- package/src/make-public.action.js +4 -0
- package/src/move-file.flow.js +78 -0
- package/src/move.form.js +5 -0
- package/src/move.schema.js +9 -0
- package/src/open-delete-directory.action.js +7 -0
- package/src/open-move.action.js +4 -0
- package/src/open-remove-selected.action.js +5 -0
- package/src/open-rename.action.js +4 -0
- package/src/open-share.action.js +4 -0
- package/src/open-sort.action.js +5 -0
- package/src/open-view.action.js +5 -0
- package/src/rename-file.flow.js +43 -0
- package/src/rename.form.js +5 -0
- package/src/rename.schema.js +9 -0
- package/src/resource-list-query.js +182 -0
- package/src/resource-list-query.spec.js +75 -0
- package/src/resource-selection.js +25 -0
- package/src/resource-selection.spec.js +40 -0
- package/src/resource.helpers.js +8 -1
- package/src/resources-list-options.js +169 -0
- package/src/resources-list-options.spec.js +141 -0
- package/src/resources.action-media.js +6 -0
- package/src/resources.queries.js +91 -6
- package/src/search-payload.js +10 -0
- package/src/search-payload.spec.js +20 -0
- package/src/search.task.js +2 -1
- package/src/share-resource.flow.js +59 -0
- package/src/sort-ascending.action.js +5 -0
- package/src/sort-by-created.action.js +5 -0
- package/src/sort-by-last-updated.action.js +5 -0
- package/src/sort-by-name.action.js +5 -0
- package/src/sort-by-size.action.js +5 -0
- package/src/sort-by-type.action.js +5 -0
- package/src/sort-descending.action.js +5 -0
- package/src/sort-storage-created.flow.js +87 -0
- package/src/sort-storage-last-updated.flow.js +119 -0
- package/src/sort-storage-name-asc.flow.js +34 -0
- package/src/sort-storage-size-desc.flow.js +34 -0
- package/src/sort-storage-size.flow.js +87 -0
- package/src/sort-storage-type.flow.js +83 -0
- package/src/sort-storage.flow.js +86 -0
- package/src/sv.translations.json +18 -0
- package/src/toggle-selection-mode.action.js +4 -0
- package/src/upload-file.flow.js +44 -0
- package/src/useResourceList.js +94 -0
- package/src/view-grid.action.js +5 -0
- package/src/view-list.action.js +5 -0
- package/src/view-storage.flow.js +49 -0
package/src/ResourcePanel.jsx
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
Button,
|
|
17
17
|
InputTitle,
|
|
18
18
|
Alert,
|
|
19
|
+
Form,
|
|
19
20
|
useInputValue,
|
|
20
21
|
useLocale,
|
|
21
22
|
Dropdown,
|
|
@@ -35,6 +36,15 @@ import {
|
|
|
35
36
|
resourceAccessIcon,
|
|
36
37
|
resourceAccessOf,
|
|
37
38
|
} from './resource-share.js'
|
|
39
|
+
import { metadata as OpenShare } from './open-share.action.js'
|
|
40
|
+
import { metadata as OpenRename } from './open-rename.action.js'
|
|
41
|
+
import { metadata as OpenMove } from './open-move.action.js'
|
|
42
|
+
import { metadata as DownloadResource } from './download-resource.action.js'
|
|
43
|
+
import { metadata as DeleteResource } from './delete.action.js'
|
|
44
|
+
import { metadata as UpdateResourceName } from './update-name.action.js'
|
|
45
|
+
import { metadata as RenameForm } from './rename.form.js'
|
|
46
|
+
import renameTemplate from './rename.schema.js'
|
|
47
|
+
import { ResourceDialogMove } from './ResourceDialogMove.jsx'
|
|
38
48
|
|
|
39
49
|
const ViewMode = {
|
|
40
50
|
Closed: 'Closed',
|
|
@@ -63,6 +73,7 @@ export const ResourcePanel = memo(function ResourcePanel ({
|
|
|
63
73
|
const [accessBusy, setAccessBusy] = useState(false)
|
|
64
74
|
const [accessError, setAccessError] = useState(null)
|
|
65
75
|
const [shareOpen, setShareOpen] = useState(false)
|
|
76
|
+
const [moveOpen, setMoveOpen] = useState(false)
|
|
66
77
|
|
|
67
78
|
const { data: resource = {} } = sdk.read(GetResource, { resourceId }, { enabled: !!resourceId })
|
|
68
79
|
const template = useSchema(resource?.type)
|
|
@@ -89,12 +100,21 @@ export const ResourcePanel = memo(function ResourcePanel ({
|
|
|
89
100
|
_onClose()
|
|
90
101
|
}
|
|
91
102
|
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
103
|
+
const commitRename = (nextName) => {
|
|
104
|
+
const name = String(nextName ?? '').trim()
|
|
105
|
+
if (!name || name === resource.name) {
|
|
106
|
+
setPanelViewModes(x => ({ ...x, 'panel-header': ViewMode.View }))
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
setResourceName(name)
|
|
110
|
+
renameResource(sdk, resourceId, name)
|
|
95
111
|
.then(() => setPanelViewModes(x => ({ ...x, 'panel-header': ViewMode.View })))
|
|
96
112
|
}
|
|
97
113
|
|
|
114
|
+
const onRenameSubmit = (data) => {
|
|
115
|
+
commitRename(data?.name)
|
|
116
|
+
}
|
|
117
|
+
|
|
98
118
|
const onUpdateResource = () => {
|
|
99
119
|
if (template) {
|
|
100
120
|
const result = validateContent(engine, template, form.data)
|
|
@@ -242,6 +262,7 @@ export const ResourcePanel = memo(function ResourcePanel ({
|
|
|
242
262
|
)}
|
|
243
263
|
{shareable && (
|
|
244
264
|
<Button
|
|
265
|
+
{...OpenShare}
|
|
245
266
|
prefix="share"
|
|
246
267
|
variant="command"
|
|
247
268
|
aria-label={t('resources.share.title')}
|
|
@@ -250,6 +271,7 @@ export const ResourcePanel = memo(function ResourcePanel ({
|
|
|
250
271
|
)}
|
|
251
272
|
{downloadHref && (
|
|
252
273
|
<Button
|
|
274
|
+
{...DownloadResource}
|
|
253
275
|
prefix="software-download"
|
|
254
276
|
variant="command"
|
|
255
277
|
href={downloadHref}
|
|
@@ -257,27 +279,78 @@ export const ResourcePanel = memo(function ResourcePanel ({
|
|
|
257
279
|
aria-label={t('resources.panel.download')}
|
|
258
280
|
/>
|
|
259
281
|
)}
|
|
260
|
-
<Button
|
|
261
|
-
|
|
282
|
+
<Button
|
|
283
|
+
{...OpenMove}
|
|
284
|
+
prefix="details-more"
|
|
285
|
+
variant="command"
|
|
286
|
+
label={undefined}
|
|
287
|
+
aria-label={t('resources.panel.move')}
|
|
288
|
+
onClick={() => setMoveOpen(true)}
|
|
289
|
+
/>
|
|
290
|
+
<Button
|
|
291
|
+
{...DeleteResource}
|
|
292
|
+
prefix="trash-empty"
|
|
293
|
+
variant="command-danger"
|
|
294
|
+
aria-label={t('resources.panel.delete')}
|
|
295
|
+
onClick={onRemoveResource}
|
|
296
|
+
/>
|
|
297
|
+
<Button
|
|
298
|
+
{...OpenRename}
|
|
299
|
+
prefix="pen"
|
|
300
|
+
variant="command"
|
|
301
|
+
label={undefined}
|
|
302
|
+
aria-label={t('resources.panel.rename')}
|
|
303
|
+
onClick={() => setPanelViewModes(x => ({ ...x, 'panel-header': ViewMode.Edit }))}
|
|
304
|
+
/>
|
|
262
305
|
{ !!_onClose && (<Button prefix="close" variant="command" onClick={onCloseResource} /> ) }
|
|
263
306
|
|
|
264
307
|
</Switch.Case>
|
|
265
308
|
|
|
266
309
|
<Switch.Case match={[ViewMode.Edit]}>
|
|
267
310
|
|
|
268
|
-
<
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
311
|
+
<Form
|
|
312
|
+
id={RenameForm.id}
|
|
313
|
+
schemaId={RenameForm.schemaId}
|
|
314
|
+
fields={renameTemplate.fields}
|
|
315
|
+
data={{ name: resourceName }}
|
|
316
|
+
onChange={({ value }) => setResourceName(String(value ?? ''))}
|
|
317
|
+
onSubmit={onRenameSubmit}
|
|
318
|
+
stack
|
|
319
|
+
horizontal
|
|
320
|
+
style={{ height: '48px', alignItems: 'center', gap: '4px', flex: 1, minWidth: 0, width: '100%' }}
|
|
321
|
+
>
|
|
322
|
+
<View.Item fill surface="primary" style={{ padding: '4px 8px' }}>
|
|
323
|
+
<InputTitle
|
|
324
|
+
id="document-name"
|
|
325
|
+
name="name"
|
|
326
|
+
type="text"
|
|
327
|
+
required
|
|
328
|
+
style={{ display: 'block', width: '100%' }}
|
|
329
|
+
value={resourceName}
|
|
330
|
+
onChange={setResourceName}
|
|
331
|
+
aria-label={t('resources.panel.rename')}
|
|
332
|
+
/>
|
|
333
|
+
</View.Item>
|
|
334
|
+
|
|
335
|
+
<Button
|
|
336
|
+
prefix="close"
|
|
337
|
+
variant="command"
|
|
338
|
+
type="button"
|
|
339
|
+
aria-label={t('design-system.cancel')}
|
|
340
|
+
onClick={() => {
|
|
341
|
+
setResourceName(resource.name || '')
|
|
342
|
+
setPanelViewModes(x => ({ ...x, 'panel-header': ViewMode.View }))
|
|
343
|
+
}}
|
|
276
344
|
/>
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
345
|
+
<Button
|
|
346
|
+
{...UpdateResourceName}
|
|
347
|
+
prefix="check"
|
|
348
|
+
variant="command"
|
|
349
|
+
type="submit"
|
|
350
|
+
label={undefined}
|
|
351
|
+
aria-label={t('@ossy/resources/actions/update-name.label')}
|
|
352
|
+
/>
|
|
353
|
+
</Form>
|
|
281
354
|
|
|
282
355
|
</Switch.Case>
|
|
283
356
|
|
|
@@ -344,6 +417,12 @@ export const ResourcePanel = memo(function ResourcePanel ({
|
|
|
344
417
|
onClose={() => setShareOpen(false)}
|
|
345
418
|
/>
|
|
346
419
|
|
|
420
|
+
<ResourceDialogMove
|
|
421
|
+
resourceId={resourceId}
|
|
422
|
+
isVisible={moveOpen}
|
|
423
|
+
onClose={() => setMoveOpen(false)}
|
|
424
|
+
/>
|
|
425
|
+
|
|
347
426
|
</View>
|
|
348
427
|
)
|
|
349
428
|
})
|
|
@@ -3,6 +3,10 @@ import React, { useEffect, useState } from 'react'
|
|
|
3
3
|
import { Overlay, View, Text, Button, Guide, useLocale } from '@ossy/design-system'
|
|
4
4
|
import { AsyncStatus, useSdk } from '@ossy/sdk-react'
|
|
5
5
|
import { metadata as GetResource } from './get.action.js'
|
|
6
|
+
import { metadata as MakePublic } from './make-public.action.js'
|
|
7
|
+
import { metadata as MakePrivate } from './make-private.action.js'
|
|
8
|
+
import { metadata as CopyShareLink } from './copy-share-link.action.js'
|
|
9
|
+
import { metadata as CloseShare } from './close-share.action.js'
|
|
6
10
|
import { updateResourceAccess } from './resource.helpers.js'
|
|
7
11
|
import {
|
|
8
12
|
getResourceShareUrl,
|
|
@@ -80,12 +84,30 @@ export function ResourceShareDialog ({
|
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
86
|
|
|
87
|
+
const onMakePrivate = async () => {
|
|
88
|
+
if (!resourceId || busy) return
|
|
89
|
+
setError(null)
|
|
90
|
+
setBusy(true)
|
|
91
|
+
try {
|
|
92
|
+
await updateResourceAccess(sdk, { id: resourceId, access: 'restricted' })
|
|
93
|
+
setMadePublic(false)
|
|
94
|
+
} catch {
|
|
95
|
+
setError(t('resources.share.publishError'))
|
|
96
|
+
} finally {
|
|
97
|
+
setBusy(false)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
83
101
|
if (!isVisible || !resourceId) return null
|
|
84
102
|
|
|
85
103
|
return (
|
|
86
104
|
<Overlay isVisible={true} onClose={onClose}>
|
|
87
105
|
<View layout="off-center-s" style={{ height: '100%' }}>
|
|
88
|
-
<View
|
|
106
|
+
<View
|
|
107
|
+
data-region="resource-share"
|
|
108
|
+
data-share-status={loading ? 'loading' : !shareable ? 'unavailable' : isPublic ? 'public' : 'private'}
|
|
109
|
+
style={{ width: 'min(420px, 92vw)' }}
|
|
110
|
+
>
|
|
89
111
|
<View surface="primary" roundness="s">
|
|
90
112
|
<View surface="primary" inset="l" roundness="s" gap="m">
|
|
91
113
|
{loading ? (
|
|
@@ -94,6 +116,7 @@ export function ResourceShareDialog ({
|
|
|
94
116
|
text={t('resources.share.sharing')}
|
|
95
117
|
actions={[
|
|
96
118
|
{
|
|
119
|
+
...CloseShare,
|
|
97
120
|
label: t('resources.share.close'),
|
|
98
121
|
variant: 'command',
|
|
99
122
|
onClick: onClose,
|
|
@@ -106,6 +129,7 @@ export function ResourceShareDialog ({
|
|
|
106
129
|
text={t('resources.share.notShareable')}
|
|
107
130
|
actions={[
|
|
108
131
|
{
|
|
132
|
+
...CloseShare,
|
|
109
133
|
label: t('resources.share.close'),
|
|
110
134
|
variant: 'command',
|
|
111
135
|
onClick: onClose,
|
|
@@ -125,6 +149,7 @@ export function ResourceShareDialog ({
|
|
|
125
149
|
<View gap="xs">
|
|
126
150
|
<Text
|
|
127
151
|
variant="small"
|
|
152
|
+
data-share-url={shareUrl}
|
|
128
153
|
style={{
|
|
129
154
|
wordBreak: 'break-all',
|
|
130
155
|
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
|
|
@@ -145,22 +170,35 @@ export function ResourceShareDialog ({
|
|
|
145
170
|
)}
|
|
146
171
|
|
|
147
172
|
<View layout="row" gap="s" style={{ justifyContent: 'flex-end', flexWrap: 'wrap' }}>
|
|
148
|
-
<Button variant="command" onClick={onClose} disabled={busy}>
|
|
173
|
+
<Button {...CloseShare} variant="command" onClick={onClose} disabled={busy}>
|
|
149
174
|
{t('resources.share.close')}
|
|
150
175
|
</Button>
|
|
151
176
|
{isPublic ? (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
177
|
+
<>
|
|
178
|
+
<Button
|
|
179
|
+
{...MakePrivate}
|
|
180
|
+
variant="neutral"
|
|
181
|
+
prefix="lock"
|
|
182
|
+
disabled={busy || !resource?.id}
|
|
183
|
+
onClick={onMakePrivate}
|
|
184
|
+
>
|
|
185
|
+
{t('resources.share.makePrivate')}
|
|
186
|
+
</Button>
|
|
187
|
+
<Button
|
|
188
|
+
{...CopyShareLink}
|
|
189
|
+
variant="cta"
|
|
190
|
+
prefix="link"
|
|
191
|
+
disabled={busy || !shareUrl}
|
|
192
|
+
onClick={() => copyLink(shareUrl)}
|
|
193
|
+
>
|
|
194
|
+
{linkCopied
|
|
195
|
+
? t('resources.share.linkCopied')
|
|
196
|
+
: t('resources.share.copyLink')}
|
|
197
|
+
</Button>
|
|
198
|
+
</>
|
|
162
199
|
) : (
|
|
163
200
|
<Button
|
|
201
|
+
{...MakePublic}
|
|
164
202
|
variant="cta"
|
|
165
203
|
prefix="share"
|
|
166
204
|
disabled={busy || !resource?.id}
|
package/src/Upload.jsx
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import React, { useCallback, useState } from 'react'
|
|
2
2
|
import { Button, View, Text, UploadInput, Icon, LocalFilePreview, DropZone } from '@ossy/design-system'
|
|
3
|
+
import { metadata as CancelUpload } from './cancel-upload.action.js'
|
|
4
|
+
import { metadata as ConfirmUpload } from './confirm-upload.action.js'
|
|
5
|
+
import { metadata as FinishUpload } from './finish-upload.action.js'
|
|
3
6
|
|
|
4
7
|
const FlowStage = {
|
|
5
8
|
Error: 'Error',
|
|
@@ -55,7 +58,11 @@ export const Upload = ({
|
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
return (
|
|
58
|
-
<View
|
|
61
|
+
<View
|
|
62
|
+
gap="s"
|
|
63
|
+
style={{ height: '100%' }}
|
|
64
|
+
data-flow-stage={flowStageAttr(flowStage, files)}
|
|
65
|
+
>
|
|
59
66
|
{
|
|
60
67
|
files.length > 0 && (
|
|
61
68
|
<View gap="s" style={{ flexGrow: '1', overflow: 'auto', padding: 'var(--space-m) 0' }}>
|
|
@@ -83,6 +90,7 @@ export const Upload = ({
|
|
|
83
90
|
>
|
|
84
91
|
<UploadInput
|
|
85
92
|
id="upload-resources"
|
|
93
|
+
data-ossy-upload-input
|
|
86
94
|
type="file"
|
|
87
95
|
multiple
|
|
88
96
|
onChange={onUserInput}
|
|
@@ -94,15 +102,15 @@ export const Upload = ({
|
|
|
94
102
|
|
|
95
103
|
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 'var(--space-m)' }}>
|
|
96
104
|
<Button
|
|
97
|
-
|
|
105
|
+
{...CancelUpload}
|
|
98
106
|
onClick={onCancel}
|
|
99
107
|
>Cancel
|
|
100
108
|
</Button>
|
|
101
109
|
|
|
102
110
|
{
|
|
103
|
-
flowStage === FlowStage.Preview && (
|
|
111
|
+
flowStage === FlowStage.Preview && files.length > 0 && (
|
|
104
112
|
<Button
|
|
105
|
-
|
|
113
|
+
{...ConfirmUpload}
|
|
106
114
|
variant="cta"
|
|
107
115
|
onClick={uploadFiles}
|
|
108
116
|
>Upload
|
|
@@ -113,7 +121,7 @@ export const Upload = ({
|
|
|
113
121
|
{
|
|
114
122
|
flowStage === FlowStage.Uploading && (
|
|
115
123
|
<Button
|
|
116
|
-
|
|
124
|
+
{...ConfirmUpload}
|
|
117
125
|
variant="cta"
|
|
118
126
|
disabled
|
|
119
127
|
>Upploading...
|
|
@@ -124,7 +132,7 @@ export const Upload = ({
|
|
|
124
132
|
{
|
|
125
133
|
flowStage === FlowStage.Error && (
|
|
126
134
|
<Button
|
|
127
|
-
|
|
135
|
+
{...ConfirmUpload}
|
|
128
136
|
variant="cta"
|
|
129
137
|
onClick={uploadFiles}
|
|
130
138
|
>Retry failed uploads
|
|
@@ -135,7 +143,7 @@ export const Upload = ({
|
|
|
135
143
|
{
|
|
136
144
|
flowStage === FlowStage.Done && (
|
|
137
145
|
<Button
|
|
138
|
-
|
|
146
|
+
{...FinishUpload}
|
|
139
147
|
variant="cta"
|
|
140
148
|
onClick={finishUpload}
|
|
141
149
|
>Done
|
|
@@ -170,4 +178,13 @@ function getFlowStage(files = []) {
|
|
|
170
178
|
if (areAllFilesUploadedSuccessfully) return FlowStage.Done
|
|
171
179
|
|
|
172
180
|
return FlowStage.Preview
|
|
173
|
-
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function flowStageAttr(flowStage, files = []) {
|
|
184
|
+
if (files.length === 0) return 'upload-idle'
|
|
185
|
+
if (flowStage === FlowStage.Preview) return 'upload-preview'
|
|
186
|
+
if (flowStage === FlowStage.Uploading) return 'upload-uploading'
|
|
187
|
+
if (flowStage === FlowStage.Error) return 'upload-error'
|
|
188
|
+
if (flowStage === FlowStage.Done) return 'upload-done'
|
|
189
|
+
return 'upload-idle'
|
|
190
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { metadata as ConfirmUpload } from './confirm-upload.action.js'
|
|
2
|
+
import { metadata as FinishUpload } from './finish-upload.action.js'
|
|
3
|
+
import { metadata as DeleteResource } from './delete.action.js'
|
|
4
|
+
import { metadata as OpenRemoveSelected } from './open-remove-selected.action.js'
|
|
5
|
+
import { metadata as ToggleSelectionMode } from './toggle-selection-mode.action.js'
|
|
6
|
+
import uploadFileFlow from './upload-file.flow.js'
|
|
7
|
+
|
|
8
|
+
export const metadata = {
|
|
9
|
+
id: '@ossy/resources/flows/batch-delete',
|
|
10
|
+
feature: 'resources',
|
|
11
|
+
requires: ['server', 'database'],
|
|
12
|
+
timeout: 180_000,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Upload two files, enter selection mode, select both, confirm batch remove,
|
|
17
|
+
* and assert both leave storage home.
|
|
18
|
+
*/
|
|
19
|
+
export default {
|
|
20
|
+
title: 'Batch delete selected files',
|
|
21
|
+
description:
|
|
22
|
+
'Signed-in user uploads two files, selects both in selection mode, confirms remove, and sees them leave storage',
|
|
23
|
+
steps: [
|
|
24
|
+
...uploadFileFlow.steps,
|
|
25
|
+
{ page: '@upload-media', search: { location: '/' } },
|
|
26
|
+
{ result: { selector: '#upload-resources', timeout: 15000 } },
|
|
27
|
+
{ result: { selector: '[data-flow-stage="upload-idle"]', timeout: 15000 } },
|
|
28
|
+
{
|
|
29
|
+
files: {
|
|
30
|
+
selector: '#upload-resources',
|
|
31
|
+
items: [{
|
|
32
|
+
name: 'e2e-upload-2.txt',
|
|
33
|
+
mimeType: 'text/plain',
|
|
34
|
+
content: 'hello from ossy e2e upload two',
|
|
35
|
+
}],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{ result: { selector: '[data-flow-stage="upload-preview"]', timeout: 15000 } },
|
|
39
|
+
{ result: { action: ConfirmUpload, timeout: 10000 } },
|
|
40
|
+
{ action: ConfirmUpload },
|
|
41
|
+
{ result: { selector: '[data-flow-stage="upload-done"]', timeout: 30000 } },
|
|
42
|
+
{ result: { action: FinishUpload, timeout: 10000 } },
|
|
43
|
+
{ action: FinishUpload },
|
|
44
|
+
{ result: { page: '@storage/home', timeout: 20000 } },
|
|
45
|
+
{ result: { selector: '[data-resource-name="e2e-upload.txt"]', timeout: 20000 } },
|
|
46
|
+
{ result: { selector: '[data-resource-name="e2e-upload-2.txt"]', timeout: 20000 } },
|
|
47
|
+
{ result: { action: ToggleSelectionMode, timeout: 10000 } },
|
|
48
|
+
{ action: ToggleSelectionMode },
|
|
49
|
+
{ result: { selector: '[data-selection-mode="on"]', timeout: 10000 } },
|
|
50
|
+
{
|
|
51
|
+
click: {
|
|
52
|
+
selector: '[data-resource-name="e2e-upload.txt"] [role="checkbox"]',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
click: {
|
|
57
|
+
selector: '[data-resource-name="e2e-upload-2.txt"] [role="checkbox"]',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{ result: { selector: '[data-resource-name="e2e-upload.txt"][data-selected]', timeout: 10000 } },
|
|
61
|
+
{ result: { selector: '[data-resource-name="e2e-upload-2.txt"][data-selected]', timeout: 10000 } },
|
|
62
|
+
{ result: { action: OpenRemoveSelected, timeout: 10000 } },
|
|
63
|
+
{ action: OpenRemoveSelected },
|
|
64
|
+
{ result: { action: DeleteResource, timeout: 10000 } },
|
|
65
|
+
{ action: DeleteResource },
|
|
66
|
+
{
|
|
67
|
+
result: {
|
|
68
|
+
selector: '[data-resource-name="e2e-upload.txt"]',
|
|
69
|
+
hidden: true,
|
|
70
|
+
timeout: 20000,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
result: {
|
|
75
|
+
selector: '[data-resource-name="e2e-upload-2.txt"]',
|
|
76
|
+
hidden: true,
|
|
77
|
+
timeout: 20000,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { metadata as ConfirmUpload } from './confirm-upload.action.js'
|
|
2
|
+
import { metadata as FinishUpload } from './finish-upload.action.js'
|
|
3
|
+
import { metadata as DownloadSelected } from './download-selected.action.js'
|
|
4
|
+
import { metadata as ToggleSelectionMode } from './toggle-selection-mode.action.js'
|
|
5
|
+
import uploadFileFlow from './upload-file.flow.js'
|
|
6
|
+
|
|
7
|
+
export const metadata = {
|
|
8
|
+
id: '@ossy/resources/flows/batch-download',
|
|
9
|
+
feature: 'resources',
|
|
10
|
+
requires: ['server', 'database'],
|
|
11
|
+
timeout: 180_000,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Upload two files, enter selection mode, select both, and batch-download them.
|
|
16
|
+
*/
|
|
17
|
+
export default {
|
|
18
|
+
title: 'Batch download selected files',
|
|
19
|
+
description:
|
|
20
|
+
'Signed-in user uploads two files, selects both in selection mode, and downloads them together',
|
|
21
|
+
steps: [
|
|
22
|
+
...uploadFileFlow.steps,
|
|
23
|
+
{ page: '@upload-media', search: { location: '/' } },
|
|
24
|
+
{ result: { selector: '#upload-resources', timeout: 15000 } },
|
|
25
|
+
{ result: { selector: '[data-flow-stage="upload-idle"]', timeout: 15000 } },
|
|
26
|
+
{
|
|
27
|
+
files: {
|
|
28
|
+
selector: '#upload-resources',
|
|
29
|
+
items: [{
|
|
30
|
+
name: 'e2e-upload-2.txt',
|
|
31
|
+
mimeType: 'text/plain',
|
|
32
|
+
content: 'hello from ossy e2e upload two',
|
|
33
|
+
}],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{ result: { selector: '[data-flow-stage="upload-preview"]', timeout: 15000 } },
|
|
37
|
+
{ result: { action: ConfirmUpload, timeout: 10000 } },
|
|
38
|
+
{ action: ConfirmUpload },
|
|
39
|
+
{ result: { selector: '[data-flow-stage="upload-done"]', timeout: 30000 } },
|
|
40
|
+
{ result: { action: FinishUpload, timeout: 10000 } },
|
|
41
|
+
{ action: FinishUpload },
|
|
42
|
+
{ result: { page: '@storage/home', timeout: 20000 } },
|
|
43
|
+
{ result: { selector: '[data-resource-name="e2e-upload.txt"]', timeout: 20000 } },
|
|
44
|
+
{ result: { selector: '[data-resource-name="e2e-upload-2.txt"]', timeout: 20000 } },
|
|
45
|
+
{ result: { action: ToggleSelectionMode, timeout: 10000 } },
|
|
46
|
+
{ action: ToggleSelectionMode },
|
|
47
|
+
{ result: { selector: '[data-selection-mode="on"]', timeout: 10000 } },
|
|
48
|
+
{
|
|
49
|
+
click: {
|
|
50
|
+
selector: '[data-resource-name="e2e-upload.txt"] [role="checkbox"]',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
click: {
|
|
55
|
+
selector: '[data-resource-name="e2e-upload-2.txt"] [role="checkbox"]',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{ result: { action: DownloadSelected, timeout: 10000 } },
|
|
59
|
+
{ result: { selector: '[data-resource-name="e2e-upload.txt"][data-selected]', timeout: 10000 } },
|
|
60
|
+
{ result: { selector: '[data-resource-name="e2e-upload-2.txt"][data-selected]', timeout: 10000 } },
|
|
61
|
+
{
|
|
62
|
+
download: {
|
|
63
|
+
action: DownloadSelected,
|
|
64
|
+
filenames: ['e2e-upload.txt', 'e2e-upload-2.txt'],
|
|
65
|
+
timeout: 45000,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import signUpFlow from '@ossy/authentication/sign-up.flow.js'
|
|
2
|
+
import { metadata as CancelUpload } from './cancel-upload.action.js'
|
|
3
|
+
|
|
4
|
+
export const metadata = {
|
|
5
|
+
id: '@ossy/resources/flows/cancel-upload',
|
|
6
|
+
feature: 'resources',
|
|
7
|
+
requires: ['server', 'database'],
|
|
8
|
+
timeout: 120_000,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* New user opens upload-media, attaches a file, cancels before confirming,
|
|
13
|
+
* and returns to storage home without the file listed.
|
|
14
|
+
*/
|
|
15
|
+
export default {
|
|
16
|
+
title: 'Cancel upload before confirm',
|
|
17
|
+
description:
|
|
18
|
+
'Signed-in user opens upload-media, selects a file, cancels, and lands on storage home without the file',
|
|
19
|
+
steps: [
|
|
20
|
+
...signUpFlow.steps,
|
|
21
|
+
{ page: '@upload-media', search: { location: '/' } },
|
|
22
|
+
{ result: { selector: '#upload-resources', timeout: 15000 } },
|
|
23
|
+
{ result: { selector: '[data-flow-stage="upload-idle"]', timeout: 15000 } },
|
|
24
|
+
{
|
|
25
|
+
files: {
|
|
26
|
+
selector: '#upload-resources',
|
|
27
|
+
items: [{
|
|
28
|
+
name: 'e2e-cancel-upload.txt',
|
|
29
|
+
mimeType: 'text/plain',
|
|
30
|
+
content: 'hello from ossy e2e cancel upload',
|
|
31
|
+
}],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{ result: { selector: '[data-flow-stage="upload-preview"]', timeout: 15000 } },
|
|
35
|
+
{ result: { action: CancelUpload, timeout: 10000 } },
|
|
36
|
+
{ action: CancelUpload },
|
|
37
|
+
{ result: { page: '@storage/home', timeout: 20000 } },
|
|
38
|
+
{ result: { selector: '[data-resource-name="e2e-cancel-upload.txt"]', hidden: true, timeout: 10000 } },
|
|
39
|
+
],
|
|
40
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import signUpFlow from '@ossy/authentication/sign-up.flow.js'
|
|
2
|
+
import { metadata as CreateDirectoryAction } from './create-directory.action.js'
|
|
3
|
+
import { metadata as CreateDirectoryForm } from './create-directory.form.js'
|
|
4
|
+
|
|
5
|
+
export const metadata = {
|
|
6
|
+
id: '@ossy/resources/flows/create-directory',
|
|
7
|
+
feature: 'resources',
|
|
8
|
+
requires: ['server', 'database'],
|
|
9
|
+
timeout: 120_000,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* New user signs up, opens create-directory, names a folder, and sees it on
|
|
14
|
+
* storage home.
|
|
15
|
+
*/
|
|
16
|
+
export default {
|
|
17
|
+
title: 'Create directory in storage',
|
|
18
|
+
description:
|
|
19
|
+
'Signed-in user opens create-directory, submits a folder name, and lands on storage home with the folder listed',
|
|
20
|
+
steps: [
|
|
21
|
+
...signUpFlow.steps,
|
|
22
|
+
{ page: '@create-directory', search: { location: '/' } },
|
|
23
|
+
{ result: { selector: '[data-flow-stage="create-directory"]', timeout: 15000 } },
|
|
24
|
+
{ result: { action: CreateDirectoryAction, timeout: 10000 } },
|
|
25
|
+
{ form: CreateDirectoryForm, fields: { name: 'e2e-folder' } },
|
|
26
|
+
{ action: CreateDirectoryAction },
|
|
27
|
+
{ result: { page: '@storage/home', timeout: 20000 } },
|
|
28
|
+
{ result: { selector: '[data-resource-name="e2e-folder"]', timeout: 20000 } },
|
|
29
|
+
],
|
|
30
|
+
}
|