Skip to content

Commit

Permalink
Merge pull request #4473 from FlowFuse/4449_add-a-directory-navigatio…
Browse files Browse the repository at this point in the history
…n-component

Add a directory navigation component
  • Loading branch information
cstns authored Sep 19, 2024
2 parents e25d5ed + 82b5128 commit 191a309
Show file tree
Hide file tree
Showing 11 changed files with 843 additions and 91 deletions.
18 changes: 18 additions & 0 deletions forge/ee/routes/staticAssets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ module.exports = async function (app) {
try {
const sharingConfig = await request.project.getSetting(KEY_SHARED_ASSETS) || {}
const result = await app.containers.listFiles(request.project, filePath)

result.files.forEach(file => {
if (file.type === 'directory') {
const absolutePath = filePath + (filePath.length > 0 ? '/' : '') + file.name
Expand All @@ -69,6 +70,23 @@ module.exports = async function (app) {
}
}
})

const parentDirectoryName = filePath.split('/').pop()
const parentDirectoryPath = filePath.split('/').slice(0, -1).join('/')

const parentFiles = await app.containers.listFiles(
request.project, parentDirectoryPath
)
const currentDirectory = parentFiles.files.filter(file => file.name === parentDirectoryName).shift()

if (currentDirectory) {
result.folder = currentDirectory
const absolutePath = parentDirectoryPath + (parentDirectoryPath.length > 0 ? '/' : '') + currentDirectory.name
if (sharingConfig[absolutePath]) {
result.folder.share = sharingConfig[absolutePath]
}
} else result.folder = null

reply.send(result)
} catch (err) {
if (err.statusCode === 404) {
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/api/assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ const getFiles = function (instanceId, path) {
// remove leading / from path
path = path.replace(/^\//, '')
return client.get(`/api/v1/projects/${instanceId}/files/_/${encodeURIComponent(path || '')}`).then(res => {
return res.data.files
return {
files: res.data.files,
folder: res.data.folder
}
})
}

Expand All @@ -30,6 +33,14 @@ const updateFolder = function (instanceId, pwd, oldName, newName) {
})
}

const updateVisibility = function (instanceId, pwd, visibility, staticPath = '') {
// remove leading / from path
pwd = pwd.replace(/^\//, '')
return client.put(`/api/v1/projects/${instanceId}/files/_/${encodeURIComponent(pwd)}`, {
share: visibility === 'public' ? { root: staticPath } : {}
})
}

const deleteItem = function (instanceId, path) {
// remove leading / from path
path = path.replace(/^\//, '')
Expand All @@ -52,6 +63,7 @@ export default {
getFiles,
createFolder,
updateFolder,
updateVisibility,
deleteItem,
uploadFile
}
62 changes: 62 additions & 0 deletions frontend/src/components/TextCopier.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<template>
<span class="ff-text-copier">
<span @click="copyPath">
<slot name="default">
<span class="text">{{ text }}</span>
</slot>
</span>
<DuplicateIcon v-if="text.length" class="ff-icon" @click="copyPath" @click.prevent.stop />
<span ref="copied" class="ff-copied">Copied!</span>
</span>
</template>

<script>
import { DuplicateIcon } from '@heroicons/vue/outline'
export default {
name: 'TextCopier',
components: { DuplicateIcon },
props: {
text: {
required: true,
type: String
}
},
methods: {
copyPath () {
navigator.clipboard.writeText(this.text)
// show "Copied" notification
this.$refs.copied.style.display = 'inline'
// hide after 500ms
setTimeout(() => {
this.$refs.copied.style.display = 'none'
}, 500)
}
}
}
</script>

<style scoped lang="scss">
.ff-text-copier {
display: inline-flex;
align-items: center;
gap: 3px;
position: relative;
&:hover {
cursor: pointer;
}
.ff-copied {
background-color: black;
color: white;
padding: 3px;
border-radius: 3px;
position: absolute;
margin-top: -3px;
margin-left: 3px;
display: none;
z-index: 100;
left: 100%;
}
}
</style>
59 changes: 47 additions & 12 deletions frontend/src/components/file-browser/FileBrowser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,9 @@ export default {
required: true,
type: Object
},
folder: {
required: true,
type: Object
},
breadcrumbs: {
required: true,
type: Object
type: Array
},
disabled: {
required: false,
Expand All @@ -136,6 +132,10 @@ export default {
required: false,
default: '',
type: String
},
instance: {
required: true,
type: Object
}
},
emits: ['change-directory', 'items-updated'],
Expand All @@ -154,15 +154,36 @@ export default {
}
},
computed: {
folder () {
return [...this.breadcrumbs].pop()
},
isPublicFolder () {
if (!this.folder) {
return false
}
return Object.prototype.hasOwnProperty.call(this.folder, 'share') &&
Object.prototype.hasOwnProperty.call(this.folder.share, 'root')
},
publicFolderPath () {
if (!this.isPublicFolder) {
return null
}
return this.folder.share.root
},
instanceId () {
return this.$route.params.id
},
pwd () {
return [...this.breadcrumbs, this.folder.name].filter(b => b).join('/').replace('//', '/')
return [...this.breadcrumbs.map(crumb => crumb.name)]
.filter(b => b)
.join('/')
.replace('//', '/')
},
baseURI () {
// clear null values
const breadcrumbs = this.breadcrumbs.filter(n => n)
const breadcrumbs = this.breadcrumbs.map(crumb => crumb.name).filter(n => n)
return breadcrumbs.join('/').replace('//', '/')
},
columns () {
Expand Down Expand Up @@ -195,10 +216,25 @@ export default {
is: markRaw(ItemFilePath),
extraProps: {
breadcrumbs: this.breadcrumbs,
folder: this.folder.name || ''
folder: this.folder?.name || ''
}
}
},
{
key: 'url',
label: 'URL',
sortable: true,
component: {
is: markRaw(ItemFilePath),
extraProps: {
baseURL: this.instance?.url,
breadcrumbs: this.breadcrumbs,
prepend: this.publicFolderPath,
isNotAvailable: !this.isPublicFolder
}
},
hidden: true
},
{
key: 'lastModified',
label: 'Last Modified',
Expand All @@ -207,17 +243,16 @@ export default {
]
},
noDataMessages () {
return this.noDataMessage.length ? this.noDataMessage : `No files in '${this.folder.name || 'Storage'}'`
return this.noDataMessage.length ? this.noDataMessage : `No files in '${this.folder?.name || 'Storage'}'`
}
},
methods: {
showDialog (dialog) {
this.$refs[dialog].show()
},
createFolder () {
const pwd = this.baseURI + '/' + (this.folder.name || '')
this.loading = true
AssetsAPI.createFolder(this.instanceId, pwd, this.forms.newFolder.name)
AssetsAPI.createFolder(this.instanceId, this.baseURI, this.forms.newFolder.name)
.then(() => this.$emit('items-updated'))
.catch(error => {
console.error(error)
Expand Down Expand Up @@ -292,7 +327,7 @@ export default {
})
},
uploadFile () {
const pwd = this.baseURI + '/' + (this.folder.name || '')
const pwd = this.baseURI + '/'
const filename = this.forms.file.name
this.loading = true
AssetsAPI.uploadFile(this.instanceId, pwd, filename, this.forms.file)
Expand Down
Loading

0 comments on commit 191a309

Please sign in to comment.