Skip to content

Commit

Permalink
selection works
Browse files Browse the repository at this point in the history
  • Loading branch information
fiskus committed Oct 8, 2024
1 parent fc14166 commit c8e16fb
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 77 deletions.
10 changes: 5 additions & 5 deletions catalog/app/containers/Bucket/Dir.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ interface DirContentsProps {
bucket: string
path: string
loadMore?: () => void
selection: string[]
onSelection: (ids: string[]) => void
selection: Selection.SelectionItem[]
onSelection: (ids: Selection.SelectionItem[]) => void
}

function DirContents({
Expand Down Expand Up @@ -156,8 +156,8 @@ const useSelectionWidgetStyles = M.makeStyles({

interface SelectionWidgetProps {
className: string
selection: Selection.PrefixedKeysMap
onSelection: (changed: Selection.PrefixedKeysMap) => void
selection: Selection.ListingSelection
onSelection: (changed: Selection.ListingSelection) => void
}

function SelectionWidget({ className, selection, onSelection }: SelectionWidgetProps) {
Expand Down Expand Up @@ -281,7 +281,7 @@ export default function Dir() {
)
}, [data.result])

const [selection, setSelection] = React.useState<Record<string, string[]>>(
const [selection, setSelection] = React.useState<Selection.ListingSelection>(
Selection.EMPTY_MAP,
)
const handleSelection = React.useCallback(
Expand Down
29 changes: 17 additions & 12 deletions catalog/app/containers/Bucket/Listing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import * as tagged from 'utils/taggedV2'
import usePrevious from 'utils/usePrevious'

import { RowActions } from './ListingActions'
import * as Selection from './Selection'

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

Expand Down Expand Up @@ -474,24 +475,28 @@ function FilterToolbarButton() {

// Iterate over `items`, and add slash if selection item is directory
// Iterate over `items` only once, but keep the sort order as in original selection
function formatSelection(ids: DG.GridRowId[], items: Item[]): string[] {
if (!ids.length) return ids as string[]
function formatSelection(ids: DG.GridRowId[], items: Item[]): Selection.SelectionItem[] {
if (!ids.length) return []

const names: string[] = []
const names: Selection.SelectionItem[] = []
const sortOrder = ids.reduce(
(memo, id, index) => ({ ...memo, [id]: index + 1 }),
{} as Record<DG.GridRowId, number>,
)
items.some(({ name, type }) => {
if (name === '..') return false
if (ids.includes(name)) {
names.push(type === 'dir' ? s3paths.ensureSlash(name) : name)
names.push(
type === 'dir'
? { logicalKey: s3paths.ensureSlash(name) }
: { logicalKey: name.toString() },
)
}
if (names.length === ids.length) return true
})
names.sort((a, b) => {
const aPos = sortOrder[a] || sortOrder[s3paths.ensureNoSlash(a.toString())]
const bPos = sortOrder[b] || sortOrder[s3paths.ensureNoSlash(b.toString())]
const aPos = sortOrder[a.logicalKey] || sortOrder[s3paths.ensureNoSlash(a.logicalKey)]
const bPos = sortOrder[b.logicalKey] || sortOrder[s3paths.ensureNoSlash(b.logicalKey)]
return aPos - bPos
})
return names
Expand Down Expand Up @@ -1035,8 +1040,8 @@ interface ListingProps {
prefixFilter?: string
toolbarContents?: React.ReactNode
loadMore?: () => void
selection?: string[]
onSelectionChange?: (newSelection: string[]) => void
selection?: Selection.SelectionItem[]
onSelectionChange?: (newSelection: Selection.SelectionItem[]) => void
CellComponent?: React.ComponentType<CellProps>
RootComponent?: React.ElementType<{ className: string }>
className?: string
Expand Down Expand Up @@ -1229,10 +1234,10 @@ export function Listing({
[items, onSelectionChange],
)

const selectionModel = React.useMemo(
() => (selection?.length ? selection.map(s3paths.ensureNoSlash) : selection),
[selection],
)
const selectionModel = React.useMemo(() => {
if (!selection) return selection
return selection.map(({ logicalKey }) => s3paths.ensureNoSlash(logicalKey))
}, [selection])

// TODO: control page, pageSize, filtering and sorting via props
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ export function usePackageCreationDialog({
async (initial?: {
successor?: workflows.Successor
path?: string
selection?: Selection.PrefixedKeysMap
selection?: Selection.ListingSelection
}) => {
if (initial?.successor) {
setSuccessor(initial?.successor)
Expand Down
8 changes: 4 additions & 4 deletions catalog/app/containers/Bucket/PackageDialog/S3FilePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ const useSelectionWidgetStyles = M.makeStyles((t) => ({

interface SelectionWidgetProps {
className: string
selection: Selection.PrefixedKeysMap
onSelection: (changed: Selection.PrefixedKeysMap) => void
selection: Selection.ListingSelection
onSelection: (changed: Selection.ListingSelection) => void
}

function SelectionWidget({ className, selection, onSelection }: SelectionWidgetProps) {
Expand Down Expand Up @@ -362,8 +362,8 @@ interface DirContentsProps {
setPath: (path: string) => void
setPrefix: (prefix: string) => void
loadMore: () => void
selection: string[]
onSelectionChange: (ids: string[]) => void
selection: Selection.SelectionItem[]
onSelectionChange: (ids: Selection.SelectionItem[]) => void
}

function DirContents({
Expand Down
120 changes: 88 additions & 32 deletions catalog/app/containers/Bucket/PackageTree/PackageTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,75 @@ function TopBar({ crumbs, children }: React.PropsWithChildren<TopBarProps>) {
)
}

const useSelectionWidgetStyles = M.makeStyles({
close: {
marginLeft: 'auto',
},
title: {
alignItems: 'center',
display: 'flex',
},
badge: {
right: '4px',
},
})

interface SelectionWidgetProps {
className: string
selection: Selection.ListingSelection
onSelection: (changed: Selection.ListingSelection) => void
}

function SelectionWidget({ className, selection, onSelection }: SelectionWidgetProps) {
const classes = useSelectionWidgetStyles()
const location = RRDom.useLocation()
const count = Object.values(selection).reduce((memo, ids) => memo + ids.length, 0)
const [opened, setOpened] = React.useState(false)
const open = React.useCallback(() => setOpened(true), [])
const close = React.useCallback(() => setOpened(false), [])
React.useEffect(() => close(), [close, location])
const badgeClasses = React.useMemo(() => ({ badge: classes.badge }), [classes])
return (
<>
<M.Badge
badgeContent={count}
classes={badgeClasses}
className={className}
color="primary"
max={999}
showZero
>
<M.Button onClick={open} size="small">
Selected items
</M.Button>
</M.Badge>

<M.Dialog open={opened} onClose={close} fullWidth maxWidth="md">
<M.DialogTitle disableTypography>
<M.Typography className={classes.title} variant="h6">
{count} items selected
<M.IconButton size="small" className={classes.close} onClick={close}>
<M.Icon>close</M.Icon>
</M.IconButton>
</M.Typography>
</M.DialogTitle>
<M.DialogContent>
<Selection.Dashboard
onSelection={onSelection}
onDone={close}
selection={selection}
/>
</M.DialogContent>
<M.DialogActions>
<M.Button onClick={close} variant="contained" color="primary" size="small">
Close
</M.Button>
</M.DialogActions>
</M.Dialog>
</>
)
}

const useDirDisplayStyles = M.makeStyles((t) => ({
button: {
flexShrink: 0,
Expand All @@ -117,8 +186,8 @@ interface DirDisplayProps {
path: string
crumbs: BreadCrumbs.Crumb[]
size?: number
selection: string[]
onSelection: (ids: string[]) => void
selection: Selection.ListingSelection
onSelection: (ids: Selection.ListingSelection) => void
}

function DirDisplay({
Expand Down Expand Up @@ -339,21 +408,11 @@ function DirDisplay({
{
Ok: ({ ui: { actions } }) => (
<>
<M.Badge
badgeContent={Object.values(selection).reduce(
(memo, ids) => memo + ids.length,
0,
)}
classes={{}}
className={''}
color="primary"
max={999}
showZero
>
<M.Button onClick={() => {}} size="small">
Selected items
</M.Button>
</M.Badge>
<SelectionWidget
className={classes.button}
selection={selection}
onSelection={onSelection}
/>
{actions.revisePackage && (
<M.Button
className={classes.button}
Expand Down Expand Up @@ -421,8 +480,14 @@ function DirDisplay({
<M.Box mt={2}>
{blocks.browser && (
<Listing.Listing
onSelectionChange={onSelection}
selection={selection}
onSelectionChange={(ids) =>
onSelection(Selection.merge(ids, bucket, path)(selection))
}
selection={Selection.getDirectorySelection(
selection,
bucket,
path,
)}
items={items}
key={hash}
/>
Expand Down Expand Up @@ -843,14 +908,10 @@ function PackageTree({
tailSeparator: path.endsWith('/'),
})

const [selection, setSelection] = React.useState<Record<string, string[]>>(
// TODO: guard for leaving this exact package
const [selection, setSelection] = React.useState<Selection.ListingSelection>(
Selection.EMPTY_MAP,
)
const handleSelection = React.useCallback(
(ids) => setSelection(Selection.merge(ids, bucket, path)),
[bucket, path],
)
// TODO: guard for leaving this exact package

return (
<FileView.Root>
Expand Down Expand Up @@ -892,11 +953,6 @@ function PackageTree({
</Lab.Alert>
</M.Box>
)}
<Selection.Dashboard
onSelection={setSelection}
onDone={() => {}}
selection={selection}
/>
<M.Typography variant="body1">
<PackageLink {...{ bucket, name }} />
{' @ '}
Expand All @@ -914,8 +970,8 @@ function PackageTree({
hashOrTag,
crumbs,
size,
selection: Selection.getDirectorySelection(selection, bucket, path),
onSelection: handleSelection,
selection,
onSelection: setSelection,
}}
/>
) : (
Expand Down
8 changes: 4 additions & 4 deletions catalog/app/containers/Bucket/Selection/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as NamedRoutes from 'utils/NamedRoutes'
import StyledLink from 'utils/StyledLink'
import * as s3paths from 'utils/s3paths'

import { EMPTY_MAP, PrefixedKeysMap, toHandlesMap } from './utils'
import { EMPTY_MAP, ListingSelection, toHandlesMap } from './utils'

const useEmptyStateStyles = M.makeStyles((t) => ({
root: {
Expand Down Expand Up @@ -126,8 +126,8 @@ const useStyles = M.makeStyles((t) => ({

interface DashboardProps {
onDone: () => void
onSelection: (changed: PrefixedKeysMap) => void
selection: PrefixedKeysMap
onSelection: (changed: ListingSelection) => void
selection: ListingSelection
}

export default function Dashboard({ onDone, onSelection, selection }: DashboardProps) {
Expand Down Expand Up @@ -161,7 +161,7 @@ export default function Dashboard({ onDone, onSelection, selection }: DashboardP

const handleRemove = React.useCallback(
(prefixUrl: string, index: number) => {
const newSelection = R.dissocPath<PrefixedKeysMap>([prefixUrl, index], selection)
const newSelection = R.dissocPath<ListingSelection>([prefixUrl, index], selection)
onSelection(newSelection)
if (!Object.values(newSelection).some((ids) => !!ids.length)) {
onDone()
Expand Down
Loading

0 comments on commit c8e16fb

Please sign in to comment.