Skip to content

Commit

Permalink
Merge pull request #41 from G4brym/open-app-on-last-tab
Browse files Browse the repository at this point in the history
Fix PWA refresh issues and reopen the app on the last opened tab
  • Loading branch information
G4brym authored Sep 23, 2023
2 parents e4ca0c7 + 15366a4 commit 8c1cfbc
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 100 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Read this in other languages: [Español](READMEes.md), [Português](READMEpt.md)

## Features

- PWA support (install this app on your phone)
- [Email Explorer](https://r2explorer.dev/guides/setup-email-explorer/) (using Cloudflare Email Routing)
- [Basic Auth](https://r2explorer.dev/getting-started/security/#basic-auth)
- [Cloudflare Access Authentication](https://r2explorer.dev/getting-started/security/)
Expand Down
37 changes: 25 additions & 12 deletions packages/dashboard/src/components/BucketExplorerWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,29 @@
</template>

<script>
import FolderTree from "@/components/FolderTree.vue";
import EventBus from "@/EventBus";
import FolderTree from '@/components/FolderTree.vue'
import EventBus from '@/EventBus'
import router from '@/router'
export default {
components: {FolderTree},
components: { FolderTree },
methods: {
changeToStorage() {
changeToStorage () {
this.$store.commit('changeTab', 'storage')
this.$router.push({name: 'storage-home', params: {bucket: this.$route.params.bucket}})
this.$router.push({ name: 'storage-home', params: { bucket: this.$route.params.bucket } })
localStorage.setItem('lastOpenTab', JSON.stringify({ name: 'storage-home', params: { bucket: this.$route.params.bucket } }))
},
changeToEmail() {
changeToEmail () {
this.$store.commit('changeTab', 'email')
this.$router.push({name: 'email-folder', params: {bucket: this.$route.params.bucket, folder: 'inbox'}})
this.$router.push({ name: 'email-folder', params: { bucket: this.$route.params.bucket, folder: 'inbox' } })
localStorage.setItem('lastOpenTab', JSON.stringify({ name: 'email-home', params: { bucket: this.$route.params.bucket } }))
}
},
async created() {
async created () {
if (this.$route.params.bucket) {
this.$store.commit('changeBucket', this.$route.params.bucket)
if (this.$route.params.folder) {
if (this.$route.params.folder !== 'IA==') { // IA== is empty space
if (this.$route.params.folder !== 'IA==') { // IA== is empty space
if (this.$store.state.activeTab === 'email') {
await this.$store.dispatch('navigate', this.$route.params.folder)
await this.$store.dispatch('refreshObjects')
Expand All @@ -63,7 +65,6 @@ export default {
if (this.$route.params.file) {
EventBus.$emit('openFile', decodeURIComponent(escape(atob(this.$route.params.file))))
}
} else {
this.$store.dispatch('refreshObjects')
}
Expand All @@ -76,10 +77,22 @@ export default {
this.$store.commit('changeBucket', bucket)
this.$store.dispatch('refreshObjects')
this.$store.commit('toggleMobileSidebar', false)
const lastOpenTab = localStorage.getItem('lastOpenTab')
if (lastOpenTab) {
const parsed = JSON.parse(lastOpenTab)
localStorage.setItem('lastOpenTab', JSON.stringify({
...parsed,
params: {
...parsed.params,
bucket
}
}))
}
}
}
)
},
}
}
</script>

Expand Down
2 changes: 1 addition & 1 deletion packages/dashboard/src/components/storage/Folders.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default {
this.$store.dispatch('navigate', folder.Prefix)
}
},
created () {
mounted () {
this.$watch(
() => this.$route.params.folder,
(newFolder, oldFolder) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/dashboard/src/registerServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ if (process.env.NODE_ENV === 'production') {
console.log('New content is downloading.')
},
updated () {
console.log('New content is available; please refresh.')
console.log('New content is available; refreshing...')
window.location.reload(true)
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
Expand Down
185 changes: 101 additions & 84 deletions packages/dashboard/src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { createStore } from "vuex";
import axios from "axios";
import repo from "@/api";
import router from "@/router";
import { createStore } from 'vuex'
import axios from 'axios'
import repo from '@/api'
import router from '@/router'

export default createStore({
state: {
user: {
username: "[email protected]"
username: '[email protected]'
},
config: {},
activeBucket: null,
currentFolder: "",
currentFolder: '',
files: [],
folders: [],
buckets: [],
Expand All @@ -20,164 +20,181 @@ export default createStore({
mobileSidebar: false,
serverVersion: null,
serverVersionInt: 0,
activeTab: "storage",
activeTab: 'storage',
serverUrl: null,
loginMethod: null,
loginMethod: null
},
getters: {},
mutations: {
setServerUrl(state, serverUrl) {
state.serverUrl = serverUrl;
setServerUrl (state, serverUrl) {
state.serverUrl = serverUrl
},
loadObjects(state, payload) {
state.files = payload.files;
state.folders = payload.folders;
loadObjects (state, payload) {
state.files = payload.files
state.folders = payload.folders
},
toggleMobileSidebar(state, payload) {
toggleMobileSidebar (state, payload) {
if (payload !== true && payload !== false) {
state.mobileSidebar = !state.mobileSidebar;
state.mobileSidebar = !state.mobileSidebar
} else {
state.mobileSidebar = payload;
state.mobileSidebar = payload
}
},
changeBucket(state, payload) {
state.activeBucket = payload;
if (this.state.activeTab === "email") {
state.currentFolder = "inbox";
changeBucket (state, payload) {
state.activeBucket = payload
if (this.state.activeTab === 'email') {
state.currentFolder = 'inbox'
} else {
state.currentFolder = "";
state.currentFolder = ''
}
},
changeTab(state, payload) {
changeTab (state, payload) {
if (payload === state.activeTab) {
return;
return
}

state.activeTab = payload;
state.currentFolder = "";
state.activeTab = payload
state.currentFolder = ''

// state.files = []
// state.folders = []
},
goTo(state, folder) {
state.currentFolder = folder;
goTo (state, folder) {
state.currentFolder = folder
},
loadUserDisks(state, data) {
state.buckets = data.buckets;
loadUserDisks (state, data) {
state.buckets = data.buckets

if ((state.activeBucket === null && data.buckets.length > 0) || router.currentRoute.value.href.startsWith('/auth')) {
const targetView = (location.pathname.startsWith('/email')) ? 'email-home' : 'storage-home'

router.push({ name: targetView, params: { bucket: data.buckets[0].name } });
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 } })
}
},
loadServerConfigs(state, data) {
state.user = data.user;
state.config = data.config;
state.serverVersion = data.version;
state.serverVersionInt = parseInt(data.version.replace("v", "").replaceAll(".", ""));
loadServerConfigs (state, data) {
state.user = data.user
state.config = data.config
state.serverVersion = data.version
state.serverVersionInt = parseInt(data.version.replace('v', '').replaceAll('.', ''))
},
changeToastMessage(state, { message, spin }) {
state.toastMessage = message;
state.toastSpin = spin || false;
changeToastMessage (state, { message, spin }) {
state.toastMessage = message
state.toastSpin = spin || false
},
addUploadingFiles(state, filenames) {
addUploadingFiles (state, filenames) {
for (const filename of filenames) {
state.uploadingFiles[filename] = {};
state.uploadingFiles[filename] = {}
}
},
clearUploadingFiles(state) {
state.uploadingFiles = {};
clearUploadingFiles (state) {
state.uploadingFiles = {}
},
setUploadProgress(state, { filename, progress }) {
setUploadProgress (state, { filename, progress }) {
if (state.uploadingFiles[filename] === undefined) {
return;
return
}

state.uploadingFiles[filename].progress = Math.ceil(progress);
state.uploadingFiles[filename].progress = Math.ceil(progress)
}
},
actions: {
makeToast(context, { message, timeout, spin }) {
context.commit("changeToastMessage", {
makeToast (context, { message, timeout, spin }) {
context.commit('changeToastMessage', {
message, spin
});
})

if (timeout !== null && timeout !== undefined) {
setTimeout(() => {
context.commit("changeToastMessage", {
context.commit('changeToastMessage', {
message: null, spin: false
});
}, timeout);
})
}, timeout)
}
},
async navigate(context, folder) {
if (folder === "/") {
folder = "";
async navigate (context, folder) {
if (folder === '/') {
folder = ''
}
context.commit("goTo", folder);
await context.dispatch("refreshObjects");
context.commit('goTo', folder)
await context.dispatch('refreshObjects')
},
navigateToHash(context, folder) {
folder = decodeURIComponent(escape(atob(folder)));
context.dispatch("navigate", folder);
navigateToHash (context, folder) {
folder = decodeURIComponent(escape(atob(folder)))
context.dispatch('navigate', folder)
},
addUploadingFiles(context, filenames) {
context.commit("addUploadingFiles", filenames);
addUploadingFiles (context, filenames) {
context.commit('addUploadingFiles', filenames)
},
clearUploadingFiles(context, filenames) {
context.commit("clearUploadingFiles");
clearUploadingFiles (context, filenames) {
context.commit('clearUploadingFiles')
},
setUploadProgress(context, { filename, progress }) {
context.commit("setUploadProgress", { filename, progress });
setUploadProgress (context, { filename, progress }) {
context.commit('setUploadProgress', { filename, progress })
},
loadUserDisks({ commit }) {
axios.get("/api/buckets").then((response) => {
commit("loadUserDisks", response.data);
});
loadUserDisks ({ commit }) {
axios.get('/api/buckets').then((response) => {
commit('loadUserDisks', response.data)
})
},
async tryLogin(context, data) {
async tryLogin (context, data) {
const token = 'Basic ' + btoa(data.username + ':' + data.password)
let result

try {
result = await axios.get('/api/server/config', {
headers: {
Authorization: token
},
validateStatus: function (status) {
return status >= 200 && status < 300
}
})
} catch (e) {}
} catch (e) {
console.log(e)
if (e.response.status === 302) {
const nextUrl = e.response.headers.Location
if (nextUrl) {
window.location.replace(nextUrl)
}
}
}

if (result?.status === 200) {
axios.defaults.headers.common.Authorization = token
localStorage.setItem('basicAuth', token)

context.state.loginMethod = "basic"
context.commit("loadServerConfigs", result.data);
context.state.loginMethod = 'basic'
context.commit('loadServerConfigs', result.data)
context.dispatch('loadUserDisks')
} else {
return 'Invalid username or password'
}
},
async checkBasicAuthStorage(context) {
async checkBasicAuthStorage (context) {
const token = localStorage.getItem('basicAuth')
if (token) {
axios.defaults.headers.common.Authorization = token
context.state.loginMethod = "basic"
context.state.loginMethod = 'basic'
}
},
loadServerConfigs({ commit }) {
axios.get("/api/server/config").then((response) => {
commit("loadServerConfigs", response.data);
}).catch(function(error) {
loadServerConfigs ({ commit }) {
axios.get('/api/server/config').then((response) => {
commit('loadServerConfigs', response.data)
}).catch(function (error) {
if (error.response?.status === 401) {
router.push({ name: "login"});
router.push({ name: 'login' })
}
});
})
},
async refreshObjects({ commit }) {
await commit("loadObjects", await repo.listObjects());
async refreshObjects ({ commit }) {
await commit('loadObjects', await repo.listObjects())
}
},
modules: {}
});
})
5 changes: 4 additions & 1 deletion packages/dashboard/vue.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ module.exports = {
url: '/storage',
icons: [{ src: '/img/icons/android-chrome-192x192.png', sizes: '192x192' }]
}
]
],
workboxOptions: {
skipWaiting: true
}

// configure the workbox plugin
// workboxPluginMode: "InjectManifest",
Expand Down
Loading

0 comments on commit 8c1cfbc

Please sign in to comment.