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

file browser configurable top limit #9237

Merged
merged 10 commits into from
Nov 20, 2023
41 changes: 26 additions & 15 deletions packages/client-core/src/common/services/FileBrowserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { defineState, getMutableState } from '@etherealengine/hyperflux'

import { Engine } from '@etherealengine/engine/src/ecs/classes/Engine'
import { FileBrowserContentType, fileBrowserPath } from '@etherealengine/engine/src/schemas/media/file-browser.schema'
import { NotificationService } from './NotificationService'

export const FILES_PAGE_LIMIT = 100

Expand All @@ -55,21 +56,26 @@ export const FileBrowserService = {

fileBrowserState.retrieving.set(true)

const files = (await Engine.instance.api.service(fileBrowserPath).find({
query: {
$skip: skip * FILES_PAGE_LIMIT,
$limit: FILES_PAGE_LIMIT,
directory
}
})) as Paginated<FileBrowserContentType>
fileBrowserState.merge({
files: files.data,
skip: files.skip,
total: files.total,
retrieving: false,
fetched: true,
lastFetched: Date.now()
})
try {
const files = (await Engine.instance.api.service(fileBrowserPath).find({
query: {
$skip: skip * FILES_PAGE_LIMIT,
$limit: FILES_PAGE_LIMIT,
directory
}
})) as Paginated<FileBrowserContentType>
fileBrowserState.merge({
files: files.data,
skip: files.skip,
total: files.total,
retrieving: false,
fetched: true,
lastFetched: Date.now()
})
} catch (err) {
NotificationService.dispatchNotify((err as Error)?.message, { variant: 'error' })
fileBrowserState.retrieving.set(false)
}
},
moveContent: async (oldName: string, newName: string, oldPath: string, newPath: string, isCopy = false) => {
return Engine.instance.api.service(fileBrowserPath).update(null, { oldName, newName, oldPath, newPath, isCopy })
Expand All @@ -83,5 +89,10 @@ export const FileBrowserService = {
resetSkip: () => {
const fileBrowserState = getMutableState(FileBrowserState)
fileBrowserState.skip.set(0)
},
getNestingDirectory: () => {
return Engine.instance.api
.service(fileBrowserPath)
.get('', { query: { getNestingDirectory: true } }) as Promise<string>
}
}
42 changes: 24 additions & 18 deletions packages/editor/src/components/assets/AssetsPreviewPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ Original Code is the Ethereal Engine team.
All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023
Ethereal Engine. All Rights Reserved.
*/
import React, { useImperativeHandle, useState } from 'react'
import React, { useImperativeHandle } from 'react'

import { AssetLoader } from '@etherealengine/engine/src/assets/classes/AssetLoader'
import { AssetType } from '@etherealengine/engine/src/assets/enum/AssetType'
import createReadableTexture from '@etherealengine/engine/src/assets/functions/createReadableTexture'
import { useHookstate } from '@etherealengine/hyperflux'
import { NO_PROXY, useHookstate } from '@etherealengine/hyperflux'

import { AudioPreviewPanel } from './AssetPreviewPanels/AudioPreviewPanel'
import { ImagePreviewPanel } from './AssetPreviewPanels/ImagePreviewPanel'
Expand All @@ -49,20 +49,23 @@ interface Props {
hideHeading?: boolean
}

export type AssetSelectionChangePropsType = {
type ResourceProps = {
resourceUrl: string
name: string
contentType: string
size: string | undefined
}

export type AssetSelectionChangePropsType = ResourceProps & {
contentType: string
}

/**
* Used to see the Preview of the Asset in the FileBrowser Panel
*/
export const AssetsPreviewPanel = React.forwardRef(({ hideHeading }: Props, ref) => {
useImperativeHandle(ref, () => ({ onSelectionChanged }))
const [previewPanel, usePreviewPanel] = useState({
PreviewSource: null as any,
const previewPanel = useHookstate({
PreviewSource: null as ((props: { resourceProps: ResourceProps }) => JSX.Element) | null,
resourceProps: { resourceUrl: '', name: '', size: '' }
})

Expand Down Expand Up @@ -94,7 +97,7 @@ export const AssetsPreviewPanel = React.forwardRef(({ hideHeading }: Props, ref)
PreviewSource: ModelPreviewPanel,
resourceProps: { resourceUrl: props.resourceUrl, name: props.name, size: props.size }
}
usePreviewPanel(modelPreviewPanel)
previewPanel.set(modelPreviewPanel)
break
case 'image/png':
case 'image/jpeg':
Expand All @@ -105,15 +108,15 @@ export const AssetsPreviewPanel = React.forwardRef(({ hideHeading }: Props, ref)
PreviewSource: ImagePreviewPanel,
resourceProps: { resourceUrl: props.resourceUrl, name: props.name, size: props.size }
}
usePreviewPanel(imagePreviewPanel)
previewPanel.set(imagePreviewPanel)
break
case 'ktx2':
case 'image/ktx2':
const compImgPreviewPanel = {
PreviewSource: ImagePreviewPanel,
resourceProps: { resourceUrl: thumbnail.value, name: props.name, size: props.size }
}
usePreviewPanel(compImgPreviewPanel)
previewPanel.set(compImgPreviewPanel)
break

case 'video/mp4':
Expand All @@ -123,7 +126,7 @@ export const AssetsPreviewPanel = React.forwardRef(({ hideHeading }: Props, ref)
PreviewSource: VideoPreviewPanel,
resourceProps: { resourceUrl: props.resourceUrl, name: props.name, size: props.size }
}
usePreviewPanel(videoPreviewPanel)
previewPanel.set(videoPreviewPanel)
break
case 'audio/mpeg':
case 'mpeg':
Expand All @@ -132,44 +135,47 @@ export const AssetsPreviewPanel = React.forwardRef(({ hideHeading }: Props, ref)
PreviewSource: AudioPreviewPanel,
resourceProps: { resourceUrl: props.resourceUrl, name: props.name, size: props.size }
}
usePreviewPanel(audioPreviewPanel)
previewPanel.set(audioPreviewPanel)
break
case 'md':
case 'ts':
case 'js':
const txtPreviewPanel = {
PreviewSource: TxtPreviewPanel,
resourceProps: { resourceUrl: props.resourceUrl, name: props.name, size: props.size }
}
usePreviewPanel(txtPreviewPanel)
previewPanel.set(txtPreviewPanel)
break
case 'json':
const jsonPreviewPanel = {
PreviewSource: JsonPreviewPanel,
resourceProps: { resourceUrl: props.resourceUrl, name: props.name, size: props.size }
}
usePreviewPanel(jsonPreviewPanel)
previewPanel.set(jsonPreviewPanel)
break

default:
const unavailable = {
PreviewSource: PreviewUnavailable,
resourceProps: { resourceUrl: props.resourceUrl, name: props.name, size: props.size }
}
usePreviewPanel(unavailable)
previewPanel.set(unavailable)
break
}
}

const PreviewSource = previewPanel.get(NO_PROXY).PreviewSource

return (
<>
{!hideHeading && (
<div style={assetHeadingStyles as React.CSSProperties}>
{previewPanel.resourceProps.name &&
previewPanel.resourceProps.size &&
`${previewPanel.resourceProps.name} (${previewPanel.resourceProps.size})`}
{previewPanel.resourceProps.name.value &&
previewPanel.resourceProps.size.value &&
`${previewPanel.resourceProps.name.value} (${previewPanel.resourceProps.size.value})`}
</div>
)}
{previewPanel.PreviewSource && <previewPanel.PreviewSource resourceProps={previewPanel.resourceProps} />}
{PreviewSource && <PreviewSource resourceProps={previewPanel.resourceProps.value} />}
</>
)
})
105 changes: 60 additions & 45 deletions packages/editor/src/components/assets/FileBrowserContentPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
ImageConvertDefaultParms,
ImageConvertParms
} from '@etherealengine/engine/src/assets/constants/ImageConvertParms'
import { getMutableState, NO_PROXY, useHookstate, useState } from '@etherealengine/hyperflux'
import { getMutableState, NO_PROXY, useHookstate } from '@etherealengine/hyperflux'

import AccessibilityNewIcon from '@mui/icons-material/AccessibilityNew'
import AddIcon from '@mui/icons-material/Add'
Expand Down Expand Up @@ -150,19 +150,19 @@ const FileBrowserContentPanel: React.FC<FileBrowserContentPanelProps> = (props)
const anchorEl = useHookstate<null | HTMLElement>(null)
const anchorPosition = useHookstate<undefined | PopoverPosition>(undefined)

const isLoading = useState(true)
const selectedDirectory = useState(
`/${props.folderName || 'projects'}/${props.selectedFile ? props.selectedFile + '/' : ''}`
)
const fileProperties = useState<any>(null)
const originalPath = `/${props.folderName || 'projects'}/${props.selectedFile ? props.selectedFile + '/' : ''}`
const selectedDirectory = useHookstate(originalPath)
const nestingDirectory = useHookstate('projects')
const fileProperties = useHookstate<FileType | null>(null)
const isLoading = useHookstate(true)

const openProperties = useState(false)
const openCompress = useState(false)
const openConvert = useState(false)
const convertProperties = useState<ImageConvertParms>(ImageConvertDefaultParms)
const openProperties = useHookstate(false)
const openCompress = useHookstate(false)
const openConvert = useHookstate(false)
const convertProperties = useHookstate<ImageConvertParms>(ImageConvertDefaultParms)

const openConfirm = useState(false)
const contentToDeletePath = useState('')
const openConfirm = useHookstate(false)
const contentToDeletePath = useHookstate('')

const fileState = useHookstate(getMutableState(FileBrowserState))
const filesValue = fileState.files.attach(Downgraded).value
Expand Down Expand Up @@ -191,7 +191,11 @@ const FileBrowserContentPanel: React.FC<FileBrowserContentPanelProps> = (props)

useEffect(() => {
refreshDirectory()
}, [selectedDirectory.value])
}, [selectedDirectory])

useEffect(() => {
FileBrowserService.getNestingDirectory().then((directory) => nestingDirectory.set(directory))
}, [])

const refreshDirectory = async () => {
await FileBrowserService.fetchFiles(selectedDirectory.value, page)
Expand Down Expand Up @@ -267,7 +271,7 @@ const FileBrowserContentPanel: React.FC<FileBrowserContentPanelProps> = (props)
const onBackDirectory = () => {
const pattern = /([^/]+)/g
const result = selectedDirectory.value.match(pattern)
if (!result) return
if (!result || result.length === 1) return
let newPath = '/'
for (let i = 0; i < result.length - 1; i++) {
newPath += result[i] + '/'
Expand Down Expand Up @@ -314,6 +318,7 @@ const FileBrowserContentPanel: React.FC<FileBrowserContentPanelProps> = (props)
const showUploadAndDownloadButtons =
selectedDirectory.value.slice(1).startsWith('projects/') &&
!['projects', 'projects/'].includes(selectedDirectory.value.slice(1))
const showBackButton = selectedDirectory.value !== originalPath

const handleDownloadProject = async () => {
const url = selectedDirectory.value
Expand Down Expand Up @@ -352,33 +357,41 @@ const FileBrowserContentPanel: React.FC<FileBrowserContentPanelProps> = (props)
changeDirectoryByPath(newPath)
}

let nestingDirectoryFiles = nestingDirectory.value.split('/')
let breadcrumbDirectoryFiles = selectedDirectory.value
.slice(1, -1)
.split('/')
.filter((file, idx) => {
if (idx < nestingDirectoryFiles.length && file === nestingDirectoryFiles[idx]) {
return false
}
return true
})

return (
<Breadcrumbs
style={{}}
maxItems={3}
classes={{ separator: styles.separator, li: styles.breadcrumb, ol: styles.breadcrumbList }}
separator="›"
>
{selectedDirectory.value
.slice(1, -1)
.split('/')
.map((file, index, arr) =>
arr.length - 1 == index ? (
<Typography key={file} style={{ fontSize: '0.9rem' }}>
{file}
</Typography>
) : (
<Link
underline="hover"
key={file}
color="#5d646c"
style={{ fontSize: '0.9rem' }}
onClick={() => handleBreadcrumbDirectoryClick(file)}
>
{file}
</Link>
)
)}
{breadcrumbDirectoryFiles.map((file, index, arr) =>
arr.length - 1 == index ? (
<Typography key={file} style={{ fontSize: '0.9rem' }}>
{file}
</Typography>
) : (
<Link
underline="hover"
key={file}
color="#5d646c"
style={{ fontSize: '0.9rem' }}
onClick={() => handleBreadcrumbDirectoryClick(file)}
>
{file}
</Link>
)
)}
</Breadcrumbs>
)
}
Expand Down Expand Up @@ -459,12 +472,14 @@ const FileBrowserContentPanel: React.FC<FileBrowserContentPanelProps> = (props)
flexWrap: 'wrap'
}}
>
<ToolButton
tooltip={t('editor:layout.filebrowser.back')}
icon={ArrowBackIcon}
onClick={onBackDirectory}
id="backDir"
/>
{showBackButton && (
<ToolButton
tooltip={t('editor:layout.filebrowser.back')}
icon={ArrowBackIcon}
onClick={onBackDirectory}
id="backDir"
/>
)}
<ToolButton
tooltip={t('editor:layout.filebrowser.refresh')}
icon={AutorenewIcon}
Expand Down Expand Up @@ -553,7 +568,7 @@ const FileBrowserContentPanel: React.FC<FileBrowserContentPanelProps> = (props)
classes={{ paper: styles.paperDialog }}
>
<DialogTitle style={{ padding: '0', textTransform: 'capitalize' }}>
{`${fileProperties.value?.name} ${fileProperties.value?.type == 'folder' ? 'folder' : 'file'} Properties`}
{`${fileProperties.value.name} ${fileProperties.value.type == 'folder' ? 'folder' : 'file'} Properties`}
</DialogTitle>
<Grid container spacing={1} style={{ width: '100%', margin: '0' }}>
<Grid item xs={4} style={{ paddingLeft: '10px', paddingTop: '10px', width: '100%' }}>
Expand All @@ -571,10 +586,10 @@ const FileBrowserContentPanel: React.FC<FileBrowserContentPanelProps> = (props)
</Typography>
</Grid>
<Grid item xs={8} style={{ paddingLeft: '10px', paddingTop: '10px', width: '100%' }}>
<Typography className={styles.secondaryText}>{fileProperties.value?.name}</Typography>
<Typography className={styles.secondaryText}>{fileProperties.value?.type}</Typography>
<Typography className={styles.secondaryText}>{fileProperties.value?.size}</Typography>
<Typography className={styles.secondaryText}>{fileProperties.value?.url}</Typography>
<Typography className={styles.secondaryText}>{fileProperties.value.name}</Typography>
<Typography className={styles.secondaryText}>{fileProperties.value.type}</Typography>
<Typography className={styles.secondaryText}>{fileProperties.value.size}</Typography>
<Typography className={styles.secondaryText}>{fileProperties.value.url}</Typography>
</Grid>
</Grid>
</Dialog>
Expand Down
7 changes: 6 additions & 1 deletion packages/editor/src/components/assets/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@

.breadcrumb {
color: var(--textColor);

[class*=MuiLink-root] {
cursor: pointer;
}
}

.pagination {
Expand All @@ -255,4 +259,5 @@
.horizontalCenter {
margin: 0 auto;
display: block;
}
}

Loading