mirror of
https://github.com/ApfelTeeSaft/R2-Explorer.git
synced 2026-08-26 19:33:39 +00:00
Change default dashboard to v2.0
This commit is contained in:
@@ -11,8 +11,8 @@ build-dashboard:
|
||||
npm install && \
|
||||
npm run build
|
||||
|
||||
cp -r packages/dashboard/dist/ dist/
|
||||
cp -r packages/dashboard-v2/dist/spa/ dist/v2.0/
|
||||
cp -r packages/dashboard-v2/dist/spa/ dist/
|
||||
cp -r packages/dashboard/dist/ dist/v1.0/
|
||||
|
||||
build-worker:
|
||||
rm -rf worker/dist/
|
||||
|
||||
@@ -69,7 +69,7 @@ module.exports = configure(function (/* ctx */) {
|
||||
|
||||
// rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
|
||||
|
||||
publicPath: '/v2.0/',
|
||||
publicPath: '/',
|
||||
// analyze: true,
|
||||
// env: {},
|
||||
// rawDefine: {}
|
||||
|
||||
@@ -53,13 +53,13 @@
|
||||
explore the new features and improvements, feel free to provide feedback or report any issues you encounter.
|
||||
Your input helps us fine-tune the dashboard to meet your needs better.<br>
|
||||
<br>
|
||||
<template v-if="firstTimeAlert">
|
||||
To revisit this message in the future, simply click on the question mark icon located in the left corner. Your
|
||||
feedback is invaluable to us, so don't hesitate to reach out with any thoughts or concerns.<br>
|
||||
<br>
|
||||
</template>
|
||||
To revisit this message in the future, simply click on the question mark icon located in the left corner. Your
|
||||
feedback is invaluable to us, so don't hesitate to reach out with any thoughts or concerns.<br>
|
||||
<br>
|
||||
Please report issues here: <a href="https://github.com/G4brym/R2-Explorer/issues/58" target="_blank">https://github.com/G4brym/R2-Explorer/issues/58</a><br>
|
||||
<br>
|
||||
If you would like to continue using the old Dashboard: <a href="/v1.0/">click here</a><br>
|
||||
<br>
|
||||
Thank you for being a part of our journey towards excellence! 🌟<br>
|
||||
<br>
|
||||
Best regards<br>
|
||||
@@ -83,8 +83,7 @@ export default defineComponent({
|
||||
name: "LeftSidebar",
|
||||
data: function() {
|
||||
return {
|
||||
alert: false,
|
||||
firstTimeAlert: true
|
||||
alert: false
|
||||
};
|
||||
},
|
||||
components: { CreateFolder },
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<q-toolbar-title style="overflow: unset" class="text-bold">
|
||||
<q-avatar>
|
||||
<img src="/v2.0/logo-white.svg">
|
||||
<img src="/logo-white.svg">
|
||||
</q-avatar>
|
||||
R2-Explorer
|
||||
</q-toolbar-title>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
import { useMainStore } from "stores/main-store";
|
||||
import { apiHandler, decode, ROOT_FOLDER } from "src/appUtils";
|
||||
import { useQuasar } from "quasar";
|
||||
|
||||
export default {
|
||||
data: function () {
|
||||
@@ -127,9 +128,22 @@ export default {
|
||||
this.$bus.emit('fetchFiles')
|
||||
// self.$store.dispatch('addUploadingFiles', filenames) // TODO!
|
||||
|
||||
const notif = this.q.notify({
|
||||
group: false,
|
||||
spinner: true,
|
||||
message: `Uploading files 1/${filenames.length}...`,
|
||||
caption: '0%',
|
||||
timeout: 0
|
||||
})
|
||||
|
||||
// Upload files
|
||||
let uploadCount = 0
|
||||
for (const [folder, files] of Object.entries(folders)) {
|
||||
notif({
|
||||
message: `Uploading files ${uploadCount+1}/${filenames.length}...`,
|
||||
caption: `${parseInt((uploadCount+1)*100/(filenames.length))}%` // +1 because still needs to delete the folder
|
||||
})
|
||||
|
||||
let targetFolder = this.selectedFolder + folder
|
||||
if (targetFolder.length > 0 && targetFolder.slice(-1) !== '/') {
|
||||
targetFolder += '/'
|
||||
@@ -159,7 +173,7 @@ export default {
|
||||
// console.log(`${start} -> ${end}`)
|
||||
|
||||
const { data } = await apiHandler.multipartUpload(uploadId, partNumber, this.selectedBucket, key, chunk, (progressEvent) => {
|
||||
console.log((start + progressEvent.loaded) * 100 / file.size)
|
||||
//console.log((start + progressEvent.loaded) * 100 / file.size)
|
||||
// self.$store.dispatch('setUploadProgress', {
|
||||
// filename: file.name,
|
||||
// progress: (start + progressEvent.loaded) * 100 / file.size
|
||||
@@ -173,7 +187,7 @@ export default {
|
||||
await apiHandler.multipartComplete(file, key, this.selectedBucket, parts, uploadId)
|
||||
} else {
|
||||
await apiHandler.uploadObjects(file, key, this.selectedBucket, (progressEvent) => {
|
||||
console.log(progressEvent.loaded * 100 / file.size)
|
||||
//console.log(progressEvent.loaded * 100 / file.size)
|
||||
// self.$store.dispatch('setUploadProgress', {
|
||||
// filename: file.name,
|
||||
// progress: progressEvent.loaded * 100 / file.size
|
||||
@@ -183,9 +197,13 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// this.$store.dispatch('makeToast', {
|
||||
// message: `${totalFiles} Files uploaded successfully`, timeout: 5000
|
||||
// })
|
||||
notif({
|
||||
icon: 'done', // we add an icon
|
||||
spinner: false, // we reset the spinner setting so the icon can be displayed
|
||||
caption: '100%',
|
||||
message: 'Files Uploaded!',
|
||||
timeout: 5000 // we will timeout it in 5s
|
||||
})
|
||||
|
||||
this.$bus.emit('fetchFiles')
|
||||
},
|
||||
@@ -273,7 +291,8 @@ export default {
|
||||
},
|
||||
setup () {
|
||||
return {
|
||||
mainStore: useMainStore()
|
||||
mainStore: useMainStore(),
|
||||
q: useQuasar()
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -281,6 +300,7 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.upload-box {
|
||||
//outline: 2px dashed black;
|
||||
.box {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<q-page class="">
|
||||
<div class="q-pa-md">
|
||||
<q-infinite-scroll ref="infScroll" :disable="loadMoreAutomatically" @load="loadNextPage" :offset="250" :debounce="100">
|
||||
<q-infinite-scroll ref="infScroll" :disable="loadMoreAutomatically" @load="loadNextPage" :offset="250"
|
||||
:debounce="100">
|
||||
<q-table
|
||||
ref="table"
|
||||
:rows="rows"
|
||||
@@ -27,23 +28,33 @@
|
||||
|
||||
<template v-slot:body-cell="prop">
|
||||
<q-td :props="prop" :class="rowClass(prop)">
|
||||
{{prop.value}}
|
||||
{{ prop.value }}
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template v-slot:header>
|
||||
<!-- sfd-->
|
||||
<tr class="q-mb-md">
|
||||
<th class="text-left">
|
||||
<q-btn color="green" icon="refresh" :loading="loading" @click="fetchFiles">
|
||||
<template v-slot:loading>
|
||||
<q-spinner
|
||||
color="white"
|
||||
/>
|
||||
</template>
|
||||
</q-btn>
|
||||
</th>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<template v-slot:body-cell-sender="prop">
|
||||
<q-td :props="prop" class="email-sender" :class="rowClass(prop)">
|
||||
{{prop.value}}
|
||||
{{ prop.value }}
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template v-slot:body-cell-subject="prop">
|
||||
<q-td :props="prop" class="email-subject" :class="rowClass(prop)">
|
||||
{{prop.value}}
|
||||
{{ prop.value }}
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
@@ -88,6 +99,7 @@ export default defineComponent({
|
||||
name: "EmailFolderPage",
|
||||
data: function() {
|
||||
return {
|
||||
timeInterval: null,
|
||||
indexCursors: null,
|
||||
loading: false,
|
||||
loadMoreAutomatically: true,
|
||||
@@ -121,7 +133,7 @@ export default defineComponent({
|
||||
align: "left",
|
||||
field: "has_attachments",
|
||||
sortable: false
|
||||
},
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
@@ -139,8 +151,8 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
rowClass: function (prop) {
|
||||
return prop.row.customMetadata.read === 'true' ? 'email-read' : 'email-unread'
|
||||
rowClass: function(prop) {
|
||||
return prop.row.customMetadata.read === "true" ? "email-read" : "email-unread";
|
||||
},
|
||||
rowClick: function(evt, row, index) {
|
||||
const file = row.key.replace(/^.*[\\/]/, "");
|
||||
@@ -211,29 +223,31 @@ export default defineComponent({
|
||||
return updatedIndex;
|
||||
},
|
||||
loadNextPage: async function(index, done) {
|
||||
const page = this.indexCursors[index]
|
||||
const page = this.indexCursors[index];
|
||||
|
||||
if (page) {
|
||||
await this.loadIndexPage(page)
|
||||
await this.loadIndexPage(page);
|
||||
} else {
|
||||
// No more pages to load
|
||||
this.loadMoreAutomatically = true
|
||||
this.hasMorePages = false
|
||||
this.loadMoreAutomatically = true;
|
||||
this.hasMorePages = false;
|
||||
}
|
||||
|
||||
done()
|
||||
done();
|
||||
},
|
||||
fetchFiles: async function() {
|
||||
this.loading = true;
|
||||
this.rows = []
|
||||
|
||||
const indexData = await this.getOrCreateIndex();
|
||||
|
||||
this.indexCursors = indexData.cursors.reverse()
|
||||
this.indexCursors = indexData.cursors.reverse();
|
||||
|
||||
await this.loadNextPage(0, () => {})
|
||||
await this.$refs.infScroll.setIndex(0) // First page is 0
|
||||
await this.loadNextPage(0, () => {
|
||||
});
|
||||
await this.$refs.infScroll.setIndex(0); // First page is 0
|
||||
|
||||
this.loadMoreAutomatically = false
|
||||
this.loadMoreAutomatically = false;
|
||||
|
||||
this.loading = false;
|
||||
},
|
||||
@@ -268,6 +282,17 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
},
|
||||
unmounted () {
|
||||
clearInterval(this.timeInterval)
|
||||
this.timeInterval = null
|
||||
},
|
||||
mounted () {
|
||||
const self = this
|
||||
|
||||
this.timeInterval = setInterval(() => {
|
||||
self.fetchFiles()
|
||||
}, 300000) // 5 minutes
|
||||
},
|
||||
created() {
|
||||
this.fetchFiles();
|
||||
},
|
||||
@@ -284,6 +309,7 @@ export default defineComponent({
|
||||
background-color: #f3f7f9;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.email-unread {
|
||||
font-weight: 500;
|
||||
}
|
||||
@@ -307,22 +333,31 @@ export default defineComponent({
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.email-list table , .email-list tbody {
|
||||
.email-list table, .email-list tbody, .email-list thead {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.email-list thead {
|
||||
th {
|
||||
border: 0;
|
||||
|
||||
&:hover {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.email-list td {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
||||
.email-list tr {
|
||||
.email-list tbody tr {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
|
||||
//width: 100%;
|
||||
//display: block;
|
||||
//width: 100%; //display: block;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 2px -2px gray;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div id="wrapper">
|
||||
<template v-if="$route.href?.startsWith('/auth')">
|
||||
<template v-if="$route.href?.startsWith('/v1.0/auth')">
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
<div class="d-none d-lg-flex align-items-center">
|
||||
<div class="alert m-0 text-white" style="background-color: rgb(26 188 156 / 50%);">
|
||||
New Dashboard V2 is now in beta <a href="/v2.0/" class="text-warning">try it out here!</a>
|
||||
New Dashboard V2 is now in beta <a href="/" class="text-warning">try it out here!</a>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="topbar-menu d-flex align-items-center">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createRouter, createWebHashHistory } from "vue-router";
|
||||
import StorageHomeView from '@/views/StorageHomeView'
|
||||
import EmailHomeView from "@/views/EmailHomeView.vue";
|
||||
import EmailDetailsView from "@/views/EmailDetailsView.vue";
|
||||
@@ -48,7 +48,7 @@ const routes = [
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
history: createWebHashHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
|
||||
@@ -68,11 +68,11 @@ export default createStore({
|
||||
if ((state.activeBucket === null && data.buckets.length > 0) || router.currentRoute.value.href.startsWith('/auth')) {
|
||||
const targetView = (location.pathname.startsWith('/email')) ? 'email-home' : 'storage-home'
|
||||
|
||||
const lastOpenTab = localStorage.getItem('lastOpenTab')
|
||||
if (lastOpenTab && location.pathname === '/') {
|
||||
router.push(JSON.parse(lastOpenTab))
|
||||
return
|
||||
}
|
||||
//const lastOpenTab = localStorage.getItem('lastOpenTab')
|
||||
//if (lastOpenTab && location.pathname === '/') {
|
||||
// router.push(JSON.parse(lastOpenTab))
|
||||
// return
|
||||
//}
|
||||
|
||||
router.push({ name: targetView, params: { bucket: data.buckets[0].name } })
|
||||
}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
module.exports = {}
|
||||
module.exports = {
|
||||
publicPath: '/v1.0/'
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ const baseConfig = {
|
||||
readonly: false,
|
||||
cors: true,
|
||||
showHiddenFiles: true,
|
||||
// dashboardUrl: "https://dashboard-v2.r2-explorer-dashboard.pages.dev/"
|
||||
dashboardUrl: "https://dev.r2-explorer-dashboard.pages.dev/"
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -12,3 +12,8 @@ preview_bucket_name = 'teste'
|
||||
binding = 'storage'
|
||||
bucket_name = 'storage'
|
||||
preview_bucket_name = 'storage'
|
||||
|
||||
[[r2_buckets]]
|
||||
binding = 'drive'
|
||||
bucket_name = 'drive'
|
||||
preview_bucket_name = 'drive'
|
||||
|
||||
Reference in New Issue
Block a user