Skip to content

Commit

Permalink
Download and bookmark on listing item mouseover (#3697)
Browse files Browse the repository at this point in the history
* Download and bookmark on listing item mouseover

* use physicalKey for package files

* fix passing physicalKey

* add snapshot unit tests

* there is path always, because we download something inside package

* throw error on unexpected

* cleaner mock for URL

* throw instead of assertNever
  • Loading branch information
fiskus authored Aug 23, 2023
1 parent 683809b commit ac96f3d
Show file tree
Hide file tree
Showing 12 changed files with 720 additions and 21 deletions.
13 changes: 8 additions & 5 deletions catalog/app/containers/Bucket/Dir.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -362,11 +362,14 @@ export default function Dir() {
prefs,
)}
{!cfg.noDownload && !cfg.desktop && (
<FileView.ZipDownloadForm
className={classes.button}
suffix={`dir/${bucket}/${path}`}
label="Download directory"
/>
<FileView.ZipDownloadForm suffix={`dir/${bucket}/${path}`}>
<Buttons.Iconized
className={classes.button}
label="Download directory"
icon="archive"
type="submit"
/>
</FileView.ZipDownloadForm>
)}
<DirectoryMenu className={classes.button} bucket={bucket} path={path} />
</div>
Expand Down
11 changes: 10 additions & 1 deletion catalog/app/containers/Bucket/Download.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,16 @@ export function DownloadButton({ className, label, onClick, path }: DownloadButt
)
}

return <FileView.ZipDownloadForm className={className} label={label} suffix={path} />
return (
<FileView.ZipDownloadForm suffix={path}>
<Buttons.Iconized
className={className}
label={label}
icon="archive"
type="submit"
/>
</FileView.ZipDownloadForm>
)
}

const STORAGE_KEYS = {
Expand Down
11 changes: 4 additions & 7 deletions catalog/app/containers/Bucket/FileView.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,21 @@ export function ViewModeSelector({ className, ...props }) {
)
}

export function ZipDownloadForm({ className, suffix, label, newTab = false }) {
/** Child button must have `type="submit"` */
export function ZipDownloadForm({ className = '', suffix, children, newTab = false }) {
const { token } = redux.useSelector(tokensSelector) || {}
if (!token || cfg.noDownload) return null
const action = `${cfg.s3Proxy}/zip/${suffix}`
return (
<form
className={className}
action={action}
target={newTab ? '_blank' : undefined}
method="POST"
style={{ flexShrink: 0 }}
>
<input type="hidden" name="token" value={token} />
<Buttons.Iconized
className={className}
label={label}
icon="archive"
type="submit"
/>
{children}
</form>
)
}
Expand Down
29 changes: 27 additions & 2 deletions catalog/app/containers/Bucket/Listing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { readableBytes } from 'utils/string'
import * as tagged from 'utils/taggedV2'
import usePrevious from 'utils/usePrevious'

import { RowActions } from './ListingActions'

const EMPTY = <i>{'<EMPTY>'}</i>

const TIP_DELAY = 1000
Expand All @@ -33,7 +35,13 @@ export interface Item {
}

export const Entry = tagged.create('app/containers/Listing:Entry' as const, {
File: (f: { key: string; size?: number; archived?: boolean; modified?: Date }) => f,
File: (f: {
archived?: boolean
key: string
modified?: Date
physicalKey?: string
size?: number
}) => f,
Dir: (d: { key: string; size?: number }) => d,
})

Expand Down Expand Up @@ -105,11 +113,12 @@ export function format(
to: toDir(key),
size,
}),
File: ({ key, size, archived, modified }) => ({
File: ({ key, size, archived, modified, physicalKey }) => ({
type: 'file' as const,
name: s3paths.withoutPrefix(prefix, key),
to: toFile(key),
size,
physicalKey,
modified,
archived,
}),
Expand Down Expand Up @@ -1152,6 +1161,22 @@ export function Listing({
},
})
}
columnsWithValues.push({
field: 'actions',
headerName: '',
align: 'right',
width: 0,
renderCell: (params: DG.GridCellParams) =>
params.id === '..' ? (
<></>
) : (
<RowActions
archived={params.row.archived}
physicalKey={params.row.physicalKey}
to={params.row.to}
/>
),
})
return columnsWithValues
}, [classes, CellComponent, items, sm])

Expand Down
103 changes: 103 additions & 0 deletions catalog/app/containers/Bucket/ListingActions.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import * as React from 'react'
import renderer from 'react-test-renderer'
import * as NamedRoutes from 'utils/NamedRoutes'
import * as Bookmarks from 'containers/Bookmarks/Provider'
import { bucketFile, bucketDir, bucketPackageTree } from 'constants/routes'

import { RowActions } from './ListingActions'

function TestBucket({ children }: React.PropsWithChildren<{}>) {
return (
<Bookmarks.Provider>
<NamedRoutes.Provider routes={{ bucketFile, bucketDir, bucketPackageTree }}>
{children}
</NamedRoutes.Provider>
</Bookmarks.Provider>
)
}

describe('components/ListingActions', () => {
describe('RowActions', () => {
it('should render nothing if archived', () => {
const tree = renderer
.create(
<TestBucket>
<RowActions archived to="" />
</TestBucket>,
)
.toJSON()
expect(tree).toMatchSnapshot()
})

it('should render nothing if no route', () => {
const tree = renderer
.create(
<TestBucket>
<RowActions to="" />
</TestBucket>,
)
.toJSON()
expect(tree).toMatchSnapshot()
})

it('should render nothing if wrong route', () => {
const tree = renderer
.create(
<TestBucket>
<RowActions to="/b/bucketA/BRANCH/fileB" />
</TestBucket>,
)
.toJSON()
expect(tree).toMatchSnapshot()
})

it('should render Bucket directory', () => {
jest.mock('react-redux')
const tree = renderer
.create(
<TestBucket>
<RowActions to="/b/bucketA/tree/dirB/" />
</TestBucket>,
)
.toJSON()
expect(tree).toMatchSnapshot()
})

it('should render Bucket file', () => {
jest.mock('utils/AWS')
const tree = renderer
.create(
<TestBucket>
<RowActions to="/b/bucketA/tree/fileB" />
</TestBucket>,
)
.toJSON()
expect(tree).toMatchSnapshot()
})

it('should render Package directory', () => {
const tree = renderer
.create(
<TestBucket>
<RowActions to="/b/bucketA/packages/namespaceB/nameC/tree/latest/dirD/" />
</TestBucket>,
)
.toJSON()
expect(tree).toMatchSnapshot()
})

it('should render Package file', () => {
const tree = renderer
.create(
<TestBucket>
<RowActions
to="/b/bucketA/packages/namespaceB/nameC/tree/latest/fileD"
physicalKey="s3://bucketA/pathB/fileB"
/>
</TestBucket>,
)
.toJSON()
expect(tree).toMatchSnapshot()
})
})
})
Loading

0 comments on commit ac96f3d

Please sign in to comment.