Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix preview rendering inside packages, refactor logic related to view modes #2328

Merged
merged 15 commits into from
Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions catalog/app/components/Preview/Display.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as AWS from 'utils/AWS'
import AsyncResult from 'utils/AsyncResult'
import * as Config from 'utils/Config'
import StyledLink from 'utils/StyledLink'
import pipeThru from 'utils/pipeThru'

import render from './render'
import { PreviewError } from './types'
Expand Down Expand Up @@ -42,11 +41,17 @@ export default function PreviewDisplay({
renderProgress = defaultProgress,
renderMessage = defaultMessage,
renderAction = defaultAction,
onData,
}) {
const cfg = Config.use()
const noDl = noDownload != null ? noDownload : cfg.noDownload
return pipeThru(data)(
AsyncResult.case({

React.useEffect(() => {
onData?.(data)
}, [data, onData])

return AsyncResult.case(
{
_: renderProgress,
Ok: R.pipe(render, renderContents),
Err: PreviewError.case({
Expand Down Expand Up @@ -133,7 +138,8 @@ export default function PreviewDisplay({
action: !!retry && renderAction({ label: 'Retry', onClick: retry }),
}),
}),
}),
},
data,
)
}

Expand Down
9 changes: 6 additions & 3 deletions catalog/app/components/SelectDropdown/SelectDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import cx from 'classnames'
import * as React from 'react'
import * as M from '@material-ui/core'

Expand All @@ -19,7 +20,7 @@ const useStyles = M.makeStyles((t) => ({
},
}))

interface ValueBase {
export interface ValueBase {
toString: () => string
valueOf: () => string | number | boolean
}
Expand All @@ -36,7 +37,9 @@ export default function SelectDropdown<Value extends ValueBase>({
onChange,
options,
value,
}: SelectDropdownProps<Value>) {
className,
...props
}: SelectDropdownProps<Value> & M.PaperProps) {
const classes = useStyles()

const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null)
Expand All @@ -57,7 +60,7 @@ export default function SelectDropdown<Value extends ValueBase>({
const aboveSm = M.useMediaQuery(t.breakpoints.up('sm'))

return (
<M.Paper className={classes.root}>
<M.Paper className={cx(className, classes.root)} {...props}>
<M.Button
className={classes.button}
onClick={handleOpen}
Expand Down
1 change: 1 addition & 0 deletions catalog/app/components/SelectDropdown/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default } from './SelectDropdown'
export * from './SelectDropdown'
54 changes: 18 additions & 36 deletions catalog/app/containers/Bucket/File.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import * as FileView from './FileView'
import Section from './Section'
import renderPreview from './renderPreview'
import * as requests from './requests'
import useViewModes from './viewModes'
import { useViewModes, viewModeToSelectOption } from './viewModes'

const getCrumbs = ({ bucket, path, urls }) =>
R.chain(
Expand Down Expand Up @@ -325,7 +325,7 @@ export default function File({
},
location,
}) {
const { version, mode: viewModeSlug } = parseSearch(location.search)
const { version, mode } = parseSearch(location.search)
const classes = useStyles()
const { urls } = NamedRoutes.use()
const history = useHistory()
Expand Down Expand Up @@ -382,9 +382,18 @@ export default function File({
}),
})

const viewModes = useViewModes(path, mode)

const onViewModeChange = React.useCallback(
(m) => {
history.push(urls.bucketFile(bucket, encodedPath, version, m.valueOf()))
},
[history, urls, bucket, encodedPath, version],
)

const handle = { bucket, key: path, version }

const withPreview = (callback, mode) =>
const withPreview = (callback) =>
requests.ObjectExistence.case({
Exists: (h) => {
if (h.deleted) {
Expand All @@ -393,39 +402,12 @@ export default function File({
if (h.archived) {
return callback(AsyncResult.Err(Preview.PreviewError.Archived({ handle })))
}
return mode
? Preview.load(R.assoc('mode', mode.key, handle), callback)
: Preview.load(handle, callback)
return Preview.load({ ...handle, mode: viewModes.mode }, callback)
},
DoesNotExist: () =>
callback(AsyncResult.Err(Preview.PreviewError.InvalidVersion({ handle }))),
})

const [previewResult, setPreviewResult] = React.useState(false)
const onRender = React.useCallback(
(result) => {
if (AsyncResult.Ok.is(result) && !previewResult) {
setPreviewResult(result)
return renderPreview(AsyncResult.Pending())
}
return renderPreview(result)
},
[previewResult, setPreviewResult],
)

const { registryUrl } = Config.use()
const viewModes = useViewModes(registryUrl, path, previewResult)
const viewMode = React.useMemo(
() => viewModes.find(({ key }) => key === viewModeSlug) || viewModes[0] || null,
[viewModes, viewModeSlug],
)
const onViewModeChange = React.useCallback(
(mode) => {
history.push(urls.bucketFile(bucket, encodedPath, version, mode.key))
},
[history, urls, bucket, encodedPath, version],
)

return (
<FileView.Root>
<MetaTitle>{[path || 'Files', bucket]}</MetaTitle>
Expand All @@ -449,11 +431,11 @@ export default function File({
</div>

<div className={classes.actions}>
{!!viewModes.length && (
<FileView.ViewWithVoilaButtonLayout
{!!viewModes.modes.length && (
<FileView.ViewModeSelector
className={classes.button}
modesList={viewModes}
mode={viewMode}
options={viewModes.modes.map(viewModeToSelectOption)}
value={viewModeToSelectOption(viewModes.mode)}
onChange={onViewModeChange}
/>
)}
Expand Down Expand Up @@ -487,7 +469,7 @@ export default function File({
Err: (e) => {
throw e
},
Ok: withPreview(onRender, viewMode),
Ok: withPreview(renderPreview(viewModes.handlePreviewResult)),
})}
</Section>
</>
Expand Down
13 changes: 3 additions & 10 deletions catalog/app/containers/Bucket/FileView.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,12 @@ export function DownloadButton({ className, handle }) {
))
}

const viewModeToSelectOption = ({ key, label }) => ({
key,
toString: () => label,
valueOf: () => key,
})

export function ViewWithVoilaButtonLayout({ modesList, mode, ...props }) {
export function ViewModeSelector({ className, ...props }) {
const classes = useDownloadButtonStyles()
const t = M.useTheme()
const sm = M.useMediaQuery(t.breakpoints.down('sm'))
const options = React.useMemo(() => modesList.map(viewModeToSelectOption), [modesList])
const value = React.useMemo(() => viewModeToSelectOption(mode), [mode])
return (
<SelectDropdown options={options} value={value} {...props}>
<SelectDropdown className={cx(classes.root, className)} {...props}>
{sm ? <M.Icon>visibility</M.Icon> : 'View as:'}
</SelectDropdown>
)
Expand Down
80 changes: 31 additions & 49 deletions catalog/app/containers/Bucket/PackageTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import Summary from './Summary'
import * as errors from './errors'
import renderPreview from './renderPreview'
import * as requests from './requests'
import useViewModes from './viewModes'
import { useViewModes, viewModeToSelectOption } from './viewModes'

/*
function ExposeLinkedData({ bucketCfg, bucket, name, hash, modified }) {
Expand Down Expand Up @@ -395,11 +395,12 @@ const useFileDisplayStyles = M.makeStyles((t) => ({
},
}))

function FileDisplay({ bucket, mode: modeSlug, name, hash, revision, path, crumbs }) {
function FileDisplay({ bucket, mode, name, hash, revision, path, crumbs }) {
const s3 = AWS.S3.use()
const credentials = AWS.Credentials.use()
const { apiGatewayEndpoint: endpoint, noDownload } = Config.use()

const history = useHistory()
const { urls } = NamedRoutes.use()
const classes = useFileDisplayStyles()

const data = useData(requests.packageFileDetail, {
Expand All @@ -412,6 +413,25 @@ function FileDisplay({ bucket, mode: modeSlug, name, hash, revision, path, crumb
path,
})

const viewModes = useViewModes(path, mode)

const onViewModeChange = React.useCallback(
(m) => {
history.push(urls.bucketPackageTree(bucket, name, revision, path, m.valueOf()))
},
[bucket, history, name, path, revision, urls],
)

const withPreview = ({ archived, deleted, handle }, callback) => {
if (deleted) {
return callback(AsyncResult.Err(Preview.PreviewError.Deleted({ handle })))
}
if (archived) {
return callback(AsyncResult.Err(Preview.PreviewError.Archived({ handle })))
}
return Preview.load({ ...handle, mode: viewModes.mode }, callback)
}

const renderProgress = () => (
// TODO: skeleton placeholder
<>
Expand All @@ -438,47 +458,6 @@ function FileDisplay({ bucket, mode: modeSlug, name, hash, revision, path, crumb
</>
)

const withPreview = ({ archived, deleted, handle, mode }, callback) => {
if (deleted) {
return callback(AsyncResult.Err(Preview.PreviewError.Deleted({ handle })))
}
if (archived) {
return callback(AsyncResult.Err(Preview.PreviewError.Archived({ handle })))
}
return mode
? Preview.load(R.assoc('mode', mode.key, handle), callback)
: Preview.load(handle, callback)
}

const history = useHistory()
const { urls } = NamedRoutes.use()

const [previewResult, setPreviewResult] = React.useState(false)
const onRender = React.useCallback(
(result) => {
if (previewResult === result) {
return renderPreview(result)
}

setPreviewResult(result)
return renderPreview(AsyncResult.Pending())
},
[previewResult, setPreviewResult],
)

const { registryUrl } = Config.use()
const viewModes = useViewModes(registryUrl, path, previewResult)
const viewMode = React.useMemo(
() => viewModes.find(({ key }) => key === modeSlug) || viewModes[0] || null,
[viewModes, modeSlug],
)
const onViewModeChange = React.useCallback(
(mode) => {
history.push(urls.bucketPackageTree(bucket, name, revision, path, mode.key))
},
[bucket, history, name, path, revision, urls],
)

return data.case({
Ok: ({ meta, ...handle }) => (
<Data fetch={requests.getObjectExistence} params={{ s3, ...handle }}>
Expand All @@ -496,11 +475,11 @@ function FileDisplay({ bucket, mode: modeSlug, name, hash, revision, path, crumb
Exists: ({ archived, deleted }) => (
<>
<TopBar crumbs={crumbs}>
{!!viewModes.length && (
<FileView.ViewWithVoilaButtonLayout
{!!viewModes.modes.length && (
<FileView.ViewModeSelector
className={classes.button}
modesList={viewModes}
mode={viewMode}
options={viewModes.modes.map(viewModeToSelectOption)}
value={viewModeToSelectOption(viewModes.mode)}
onChange={onViewModeChange}
/>
)}
Expand All @@ -511,7 +490,10 @@ function FileDisplay({ bucket, mode: modeSlug, name, hash, revision, path, crumb
<PkgCode {...{ bucket, name, hash, revision, path }} />
<FileView.Meta data={AsyncResult.Ok(meta)} />
<Section icon="remove_red_eye" heading="Preview" expandable={false}>
{withPreview({ archived, deleted, handle, mode: viewMode }, onRender)}
{withPreview(
{ archived, deleted, handle },
renderPreview(viewModes.handlePreviewResult),
)}
</Section>
</>
),
Expand Down
2 changes: 1 addition & 1 deletion catalog/app/containers/Bucket/renderPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ const renderProgress = () => (
</Message>
)

export default Preview.display({ renderMessage, renderProgress })
export default (onData) => Preview.display({ renderMessage, renderProgress, onData })
Loading