From e439e183db06c429dc48522ab75e2e7ce2d690bb Mon Sep 17 00:00:00 2001 From: Gabriel Massadas Date: Wed, 30 Aug 2023 21:49:39 +0100 Subject: [PATCH] Fix small issues --- README.md | 1 + packages/dashboard/src/api.js | 20 ++++++++++++++----- .../dashboard/src/components/FilePreview.vue | 8 ++++++++ .../src/components/email/EmailDetails.vue | 3 ++- .../src/components/email/EmailList.vue | 3 +-- packages/dashboard/src/main.js | 2 +- packages/dashboard/src/preview.js | 10 ++++++++++ packages/dashboard/src/store/index.js | 5 +---- .../api/{renameObject.ts => moveObject.ts} | 8 ++++---- .../src/buckets/api/multipart/createUpload.ts | 11 ++++++++-- worker/src/buckets/api/putObject.ts | 11 ++++++++-- worker/src/buckets/router.ts | 4 ++-- worker/src/dashbord.ts | 18 +++++++++++------ worker/src/interfaces.ts | 1 + 14 files changed, 76 insertions(+), 29 deletions(-) rename worker/src/buckets/api/{renameObject.ts => moveObject.ts} (85%) diff --git a/README.md b/README.md index e4a30ef..36d124c 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ wrangler publish - Image thumbnail's using Cloudflare workers - Tooltip when hovering a file with absolute time in "x days time ago" format - Automatically load more files, when the bottom is reached (current limit is 1000 files) +- bundle bootstrap icons instead of importing ## Known issues diff --git a/packages/dashboard/src/api.js b/packages/dashboard/src/api.js index 04338a8..63abd1c 100644 --- a/packages/dashboard/src/api.js +++ b/packages/dashboard/src/api.js @@ -51,7 +51,7 @@ const apiHandler = { ) }, renameObject: (oldName, newName) => { - return axios.post(`/api/buckets/${store.state.activeBucket}/rename`, { + return axios.post(`/api/buckets/${store.state.activeBucket}/move`, { oldKey: encodeKey(oldName, store.state.currentFolder), newKey: encodeKey(newName, store.state.currentFolder), }) @@ -59,7 +59,10 @@ const apiHandler = { multipartCreate: (file, folder) => { return axios.post(`/api/buckets/${store.state.activeBucket}/multipart/create`, null, { params: { - key: encodeKey(file.name, folder) + key: encodeKey(file.name, folder), + httpMetadata: encodeKey(JSON.stringify({ + contentType: file.type + })) } }) }, @@ -86,8 +89,16 @@ const apiHandler = { }, uploadObjects: (file, folder, callback) => { folder = folder || store.state.currentFolder + console.log(file) + console.log(file.type) - return axios.post(`/api/buckets/${store.state.activeBucket}/upload?key=${encodeKey(file.name, folder)}`, file, { + return axios.post(`/api/buckets/${store.state.activeBucket}/upload`, file, { + params: { + key: encodeKey(file.name, folder), + httpMetadata: encodeKey(JSON.stringify({ + contentType: file.type + })) + }, headers: { 'Content-Type': 'multipart/form-data', }, @@ -97,11 +108,10 @@ const apiHandler = { listObjects: async () => { const prefix = getCurrentFolder() - const response = await axios.get(`/api/buckets/${store.state.activeBucket}`, { + const response = await axios.get(`/api/buckets/${store.state.activeBucket}?include=customMetadata&include=httpMetadata`, { params: { delimiter: '/', prefix: encodeKey(prefix), - include: 'customMetadata' } }) diff --git a/packages/dashboard/src/components/FilePreview.vue b/packages/dashboard/src/components/FilePreview.vue index eb8edb3..959cb52 100644 --- a/packages/dashboard/src/components/FilePreview.vue +++ b/packages/dashboard/src/components/FilePreview.vue @@ -44,6 +44,14 @@
+ + + + diff --git a/packages/dashboard/src/components/email/EmailDetails.vue b/packages/dashboard/src/components/email/EmailDetails.vue index 7aa4530..7433b27 100644 --- a/packages/dashboard/src/components/email/EmailDetails.vue +++ b/packages/dashboard/src/components/email/EmailDetails.vue @@ -96,8 +96,9 @@ export default { for (const file of this.$store.state.files) { if (file.hash === this.$route.params.file) { apiHandler.downloadFile(file).then(response => { + const filename = file.key.split('.json')[0] for (const att of response.data.attachments) { - att.downloadUrl = `${self.$store.state.serverUrl}/api/buckets/${self.$store.state.activeBucket}/${btoa(unescape(encodeURIComponent(`${file.key}/${att.filename}`)))}` + att.downloadUrl = `${self.$store.state.serverUrl}/api/buckets/${self.$store.state.activeBucket}/${btoa(unescape(encodeURIComponent(`${filename}/${att.filename}`)))}` } self.file = response.data }) diff --git a/packages/dashboard/src/components/email/EmailList.vue b/packages/dashboard/src/components/email/EmailList.vue index 17c9dbe..4fea268 100644 --- a/packages/dashboard/src/components/email/EmailList.vue +++ b/packages/dashboard/src/components/email/EmailList.vue @@ -35,7 +35,7 @@

This bucket don't have any emails yet!

Learn how to setup the Email Explorer in the official documentation

- https://r2explorer.dev + https://r2explorer.dev
@@ -70,7 +70,6 @@ export default { this.$watch( () => this.$route.params.folder, (newFolder) => { - console.log(newFolder) if (this.$store.state.activeTab === 'email') { this.$store.dispatch('refreshObjects') } diff --git a/packages/dashboard/src/main.js b/packages/dashboard/src/main.js index 2015634..5bdebd6 100644 --- a/packages/dashboard/src/main.js +++ b/packages/dashboard/src/main.js @@ -18,7 +18,7 @@ require('bootstrap/js/dist/modal') let url = window.location.origin if (process.env.NODE_ENV === 'development') { - axios.defaults.baseURL = 'https://my-r2-explorer.g4brym.workers.dev' + axios.defaults.baseURL = 'http://localhost:8787' } store.commit('setServerUrl', url) diff --git a/packages/dashboard/src/preview.js b/packages/dashboard/src/preview.js index bcb8cbd..41eff8c 100644 --- a/packages/dashboard/src/preview.js +++ b/packages/dashboard/src/preview.js @@ -33,6 +33,16 @@ const PreviewConfigs = [ extensions: ['csv'], type: 'csv', downloadType: 'text' + }, + { + extensions: ['json'], + type: 'json', + downloadType: 'text' + }, + { + extensions: ['html'], + type: 'html', + downloadType: 'text' } ] diff --git a/packages/dashboard/src/store/index.js b/packages/dashboard/src/store/index.js index d692d36..196d881 100644 --- a/packages/dashboard/src/store/index.js +++ b/packages/dashboard/src/store/index.js @@ -60,10 +60,7 @@ export default createStore({ } }, loadServerConfigs (state, data) { - state.user = { - username: "test@example.com" - } - // state.user = data.user + state.user = data.user state.config = data.config state.serverVersion = data.version }, diff --git a/worker/src/buckets/api/renameObject.ts b/worker/src/buckets/api/moveObject.ts similarity index 85% rename from worker/src/buckets/api/renameObject.ts rename to worker/src/buckets/api/moveObject.ts index 6dfdd34..a419185 100644 --- a/worker/src/buckets/api/renameObject.ts +++ b/worker/src/buckets/api/moveObject.ts @@ -3,11 +3,11 @@ import {Context} from "../../interfaces"; import {OpenAPIRouteSchema} from "@cloudflare/itty-router-openapi/dist/src/types"; import {z} from "zod"; -export class RenameObject extends OpenAPIRoute { +export class MoveObject extends OpenAPIRoute { static schema: OpenAPIRouteSchema = { - operationId: 'post-bucket-rename-object', + operationId: 'post-bucket-move-object', tags: ['Buckets'], - summary: 'Rename object', + summary: 'Move object', parameters: { bucket: Path(String), }, @@ -30,7 +30,7 @@ export class RenameObject extends OpenAPIRoute { const newKey = decodeURIComponent(escape(atob(data.body.newKey))) const object = await bucket.get(oldKey) - const resp = await bucket.put(newKey, object.body, {customMetadata: object.customMetadata}) + const resp = await bucket.put(newKey, object.body, {customMetadata: object.customMetadata, httpMetadata: object.httpMetadata}) await bucket.delete(oldKey) diff --git a/worker/src/buckets/api/multipart/createUpload.ts b/worker/src/buckets/api/multipart/createUpload.ts index bd97f2a..8be9476 100644 --- a/worker/src/buckets/api/multipart/createUpload.ts +++ b/worker/src/buckets/api/multipart/createUpload.ts @@ -12,6 +12,7 @@ export class CreateUpload extends OpenAPIRoute { bucket: Path(String), key: Query(z.string().optional().describe('base64 encoded file key')), customMetadata: Query(z.string().optional().describe('base64 encoded json string')), + httpMetadata: Query(z.string().optional().describe('base64 encoded json string')), } } @@ -26,12 +27,18 @@ export class CreateUpload extends OpenAPIRoute { const bucket = env[data.params.bucket] const key = decodeURIComponent(escape(atob(data.query.key))) + let customMetadata = undefined if (data.query.customMetadata) { - customMetadata = decodeURIComponent(escape(atob(data.query.key))) + customMetadata = JSON.parse(decodeURIComponent(escape(atob(data.query.customMetadata)))) } - const multipartUpload = await bucket.createMultipartUpload(key, {customMetadata: customMetadata}); + let httpMetadata = undefined + if (data.query.httpMetadata) { + httpMetadata = JSON.parse(decodeURIComponent(escape(atob(data.query.httpMetadata)))) + } + + const multipartUpload = await bucket.createMultipartUpload(key, {customMetadata: customMetadata, httpMetadata: httpMetadata}); return { uploadId: multipartUpload.uploadId, diff --git a/worker/src/buckets/api/putObject.ts b/worker/src/buckets/api/putObject.ts index 93d72a2..96775ea 100644 --- a/worker/src/buckets/api/putObject.ts +++ b/worker/src/buckets/api/putObject.ts @@ -12,6 +12,7 @@ export class PutObject extends OpenAPIRoute { bucket: Path(String), key: Query(z.string().optional().describe('base64 encoded file key')), customMetadata: Query(z.string().optional().describe('base64 encoded json string')), + httpMetadata: Query(z.string().optional().describe('base64 encoded json string')), }, } @@ -26,11 +27,17 @@ export class PutObject extends OpenAPIRoute { const bucket = env[data.params.bucket] let key = decodeURIComponent(escape(atob(data.query.key))) + let customMetadata = undefined if (data.query.customMetadata) { - customMetadata = decodeURIComponent(escape(atob(data.query.key))) + customMetadata = JSON.parse(decodeURIComponent(escape(atob(data.query.customMetadata)))) } - return await bucket.put(key, request.body, {customMetadata: customMetadata}) + let httpMetadata = undefined + if (data.query.httpMetadata) { + httpMetadata = JSON.parse(decodeURIComponent(escape(atob(data.query.httpMetadata)))) + } + + return await bucket.put(key, request.body, {customMetadata: customMetadata, httpMetadata: httpMetadata}) } } diff --git a/worker/src/buckets/router.ts b/worker/src/buckets/router.ts index 2ea9b9c..179a7cf 100644 --- a/worker/src/buckets/router.ts +++ b/worker/src/buckets/router.ts @@ -1,7 +1,7 @@ import {config} from "../settings"; import {ListBuckets} from "./api/listBuckets"; import {ListObjects} from "./api/listObjects"; -import {RenameObject} from "./api/renameObject"; +import {MoveObject} from "./api/moveObject"; import {CreateFolder} from "./api/createFolder"; import {PutObject} from "./api/putObject"; import {DeleteObject} from "./api/deleteObject"; @@ -22,7 +22,7 @@ export const bucketsRouter = OpenAPIRouter({ bucketsRouter.get('', ListBuckets) bucketsRouter.get('/:bucket', ListObjects) -bucketsRouter.post('/:bucket/rename', RenameObject) +bucketsRouter.post('/:bucket/move', MoveObject) bucketsRouter.post('/:bucket/folder', CreateFolder) bucketsRouter.post('/:bucket/upload', PutObject) bucketsRouter.post('/:bucket/multipart/create', CreateUpload) diff --git a/worker/src/dashbord.ts b/worker/src/dashbord.ts index ef4dc23..bc4e7b1 100644 --- a/worker/src/dashbord.ts +++ b/worker/src/dashbord.ts @@ -1,4 +1,6 @@ -export async function dashboardProxy(request: any, env: any, context: any) { +import {Context} from "./interfaces"; + +export async function dashboardProxy(request: any, env: any, context: Context) { // Initialize the default cache //@ts-ignore const cache = caches.default @@ -10,10 +12,14 @@ export async function dashboardProxy(request: any, env: any, context: any) { path = "/" } - // use .match() to see if we have a cache hit, if so return the caches response early - let result = await cache.match(request) - if (result) { - return result + let result + + if (context.config.cacheAssets !== false) { + // use .match() to see if we have a cache hit, if so return the caches response early + result = await cache.match(request) + if (result) { + return result + } } let dashboardUrl = 'https://demo.r2explorer.dev' @@ -41,7 +47,7 @@ export async function dashboardProxy(request: any, env: any, context: any) { }, }) - if (response.status !== 200) { + if (response.status === 200 && context.config.cacheAssets !== false) { // before returning the response we put a clone of our response object into the cache so it can be resolved later context.executionContext.waitUntil(cache.put(request, result.clone())) } diff --git a/worker/src/interfaces.ts b/worker/src/interfaces.ts index 1f75439..e3d230f 100644 --- a/worker/src/interfaces.ts +++ b/worker/src/interfaces.ts @@ -12,6 +12,7 @@ export interface R2ExplorerConfig { targetBucket: string }, showHiddenFiles?: string + cacheAssets?: boolean // basicAuth?: BasicAuth | BasicAuth[] // TODO }