Skip to content

Commit

Permalink
feat: add multiselect to timelapse file manager (#1039)
Browse files Browse the repository at this point in the history
  • Loading branch information
meteyou authored Aug 23, 2022
1 parent 99075fb commit cbb7075
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 13 deletions.
116 changes: 103 additions & 13 deletions src/components/panels/Timelapse/TimelapseFilesPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
dense
style="max-width: 300px"></v-text-field>
<v-spacer></v-spacer>
<v-btn
v-if="selectedFiles.length"
:title="$t('Timelapse.Delete')"
color="error"
class="px-2 minwidth-0 ml-3"
@click="deleteSelectedDialog = true">
<v-icon>{{ mdiDelete }}</v-icon>
</v-btn>
<v-btn
v-if="directoryPermissions.includes('w')"
:title="$t('Timelapse.CreateNewDirectory')"
Expand Down Expand Up @@ -78,6 +86,7 @@
</v-card-text>
<v-divider class="mb-3"></v-divider>
<v-data-table
v-model="selectedFiles"
:items="displayFiles"
class="files-table"
:headers="headers"
Expand All @@ -90,10 +99,11 @@
itemsPerPageAllText: $t('Timelapse.AllFiles'),
itemsPerPageOptions: [10, 25, 50, 100, -1],
}"
item-key="name"
item-key="filename"
:search="search"
:custom-filter="advancedSearch"
mobile-breakpoint="0">
mobile-breakpoint="0"
show-select>
<template slot="items">
<td v-for="header in headers" :key="header.value">{{ header.text }}</td>
</template>
Expand All @@ -111,19 +121,26 @@
</tr>
</template>

<template #item="{ index, item }">
<template #item="{ index, item, isSelected, select }">
<tr
:key="`${index} ${item.filename}`"
v-longpress:600="(e) => showContextMenu(e, item)"
class="file-list-cursor user-select-none"
@contextmenu="showContextMenu($event, item)"
@click="clickRow(item)">
<td class="pr-0 text-center" style="width: 32px">
<td class="file-list__select-td pr-0">
<v-simple-checkbox
v-ripple
:value="isSelected"
class="pa-0 mr-0"
@click.stop="select(!isSelected)"></v-simple-checkbox>
</td>
<td class="px-0 text-center" style="width: 32px">
<template v-if="item.isDirectory">
<v-icon>{{ mdiFolder }}</v-icon>
<v-icon width="32">{{ mdiFolder }}</v-icon>
</template>
<template v-else-if="item.filename.endsWith('zip')">
<v-icon>{{ mdiFolderZipOutline }}</v-icon>
<v-icon width="32">{{ mdiFolderZipOutline }}</v-icon>
</template>
<template v-else-if="getThumbnail(item)">
<v-tooltip
Expand All @@ -139,11 +156,15 @@
width="32"
v-bind="attrs"
v-on="on" />
<v-progress-circular
slot="preloader"
indeterminate
color="primary"></v-progress-circular>
<v-icon slot="error">{{ mdiFile }}</v-icon>
<div slot="preloader">
<v-progress-circular
slot="preloader"
indeterminate
color="primary"></v-progress-circular>
</div>
<div slot="error">
<v-icon>{{ mdiFile }}</v-icon>
</div>
</vue-load-image>
</template>
<span><img :src="getThumbnail(item)" :alt="item.filename" width="250" /></span>
Expand Down Expand Up @@ -339,13 +360,33 @@
</v-card-text>
</panel>
</v-dialog>
<v-dialog v-model="deleteSelectedDialog" max-width="400">
<panel
:title="$t('Timelapse.Delete').toString()"
card-class="timelapse-delete-selected-dialog"
:margin-bottom="false">
<template #buttons>
<v-btn icon tile @click="deleteSelectedDialog = false">
<v-icon>{{ mdiCloseThick }}</v-icon>
</v-btn>
</template>
<v-card-text>
<p class="mb-0">{{ $t('Timelapse.DeleteSelectedQuestion', { count: selectedFiles.length }) }}</p>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="" text @click="deleteSelectedDialog = false">{{ $t('Timelapse.Cancel') }}</v-btn>
<v-btn color="error" text @click="deleteSelectedFiles">{{ $t('Timelapse.Delete') }}</v-btn>
</v-card-actions>
</panel>
</v-dialog>
</div>
</template>
<script lang="ts">
import { Component, Mixins } from 'vue-property-decorator'
import BaseMixin from '@/components/mixins/base'
import { formatFilesize, formatDate, sortFiles } from '@/plugins/helpers'
import { FileStateFile } from '@/store/files/types'
import { FileStateFile, FileStateGcodefile } from '@/store/files/types'
import Panel from '@/components/ui/Panel.vue'
import {
mdiFolderPlus,
Expand Down Expand Up @@ -453,11 +494,13 @@ export default class TimelapseFilesPanel extends Mixins(BaseMixin) {
},
}
private deleteSelectedDialog = false
private input_rules = [(value: string) => value.indexOf(' ') === -1 || 'Name contains spaces!']
get headers() {
return [
{ text: '', value: '', align: 'left', configable: false, visible: true, filterable: false },
{ text: '', value: '', align: 'left', configable: false, visible: true, sortable: false },
{ text: this.$t('Timelapse.Name'), value: 'filename', align: 'left', configable: false, visible: true },
{ text: this.$t('Timelapse.Filesize'), value: 'size', align: 'right', configable: true, visible: true },
{
Expand Down Expand Up @@ -532,6 +575,14 @@ export default class TimelapseFilesPanel extends Mixins(BaseMixin) {
this.$store.dispatch('gui/saveSettingWithoutUpload', { name: 'view.timelapse.currentPath', value: newVal })
}
get selectedFiles() {
return this.$store.state.gui.view.timelapse.selectedFiles ?? []
}
set selectedFiles(newVal) {
this.$store.dispatch('gui/saveSettingWithoutUpload', { name: 'view.timelapse.selectedFiles', value: newVal })
}
createDirectory() {
this.dialogCreateDirectory.name = ''
this.dialogCreateDirectory.show = true
Expand Down Expand Up @@ -733,5 +784,44 @@ export default class TimelapseFilesPanel extends Mixins(BaseMixin) {
{ action: 'files/getDeleteDir' }
)
}
deleteSelectedFiles() {
this.selectedFiles.forEach((item: FileStateGcodefile) => {
if (item.isDirectory) {
this.$socket.emit(
'server.files.delete_directory',
{ path: this.currentPath + '/' + item.filename, force: true },
{ action: 'files/getDeleteDir' }
)
} else {
const filename = item.filename.slice(0, item.filename.lastIndexOf('.'))
const fileExtension = item.filename.split('.').pop()
this.$socket.emit(
'server.files.delete_file',
{ path: this.currentPath + '/' + item.filename },
{ action: 'files/getDeleteFile' }
)
if (fileExtension !== 'mp4') return
/**
* if file-extension is mp4, also delete its corresponding thumbnail jpg
*/
const previewFilename = filename + '.jpg'
const previewExists = this.files.findIndex((file) => file.filename === previewFilename) !== -1
if (previewExists)
this.$socket.emit(
'server.files.delete_file',
{ path: this.currentPath + '/' + previewFilename },
{ action: 'files/getDeleteFile' }
)
}
})
this.selectedFiles = []
this.deleteSelectedDialog = false
}
}
</script>
1 change: 1 addition & 0 deletions src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@
"Delete": "Löschen",
"DeleteDirectory": "Verzeichnis löschen",
"DeleteDirectoryQuestion": "Willst du wirklich das Verzeichnis \"{name}\" mit seinem gesamten Inhalt löschen?",
"DeleteSelectedQuestion": "Sollen wirklich {count} ausgewählte Dateien gelöscht werden?",
"Download": "Download",
"DuplicateLastframe": "Letztes Bild duplizieren",
"Empty": "Keine fertigen Zeitraffer gefunden.",
Expand Down
1 change: 1 addition & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@
"Delete": "Delete",
"DeleteDirectory": "Delete Directory",
"DeleteDirectoryQuestion": "Do you really want to delete the \"{name}\" directory with all its contents?",
"DeleteSelectedQuestion": "Do you really want to delete {count} selected files?",
"Download": "Download",
"DuplicateLastframe": "Duplicate last frame",
"Empty": "No finished timelapse found.",
Expand Down
1 change: 1 addition & 0 deletions src/store/gui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ export const getDefaultState = (): GuiState => {
sortDesc: true,
showHiddenFiles: false,
currentPath: 'timelapse',
selectedFiles: [],
},
webcam: {
currentCam: {
Expand Down
1 change: 1 addition & 0 deletions src/store/gui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export interface GuiState {
sortDesc: boolean
showHiddenFiles: boolean
currentPath: string
selectedFiles: FileStateFile[]
}
webcam: {
currentCam: {
Expand Down

0 comments on commit cbb7075

Please sign in to comment.