Skip to content

Commit

Permalink
Add http and custom metadata edit
Browse files Browse the repository at this point in the history
  • Loading branch information
G4brym committed Dec 19, 2024
1 parent 78044e1 commit 8677325
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 10 deletions.
5 changes: 3 additions & 2 deletions packages/dashboard/src/appUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,15 @@ export const apiHandler = {
newKey: encode(newKey),
});
},
updateMetadata: async (bucket, key, metadata) => {
updateMetadata: async (bucket, key, customMetadata, httpMetadata = {}) => {
let prefix = "";
if (key.includes("/")) {
prefix = key.replace(key.split("/").pop(), "");
}

const resp = await api.post(`/buckets/${bucket}/${encode(key)}`, {
customMetadata: metadata,
customMetadata: customMetadata,
httpMetadata: httpMetadata,
});

if (resp.status === 200) {
Expand Down
86 changes: 86 additions & 0 deletions packages/dashboard/src/components/files/FileOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,44 @@
</q-card-actions>
</q-card>
</q-dialog>

<q-dialog v-model="updateMetadataModal" @hide="reset">
<q-card style="min-width: 300px;">
<q-card-section class="row column" v-if="row">
<h6 class="q-mt-none q-mb-sm flex">HTTP Metadata <q-btn class="q-mr-none q-ml-auto" round size="sm" color="primary" icon="add" @click="updateHttpMetadata.push({key: '', value: ''})" /></h6>
<div class="flex row" v-for="(val, index) in updateHttpMetadata" :key="index">
<div>
<q-input v-model="updateHttpMetadata[index].key" label="Key" />
</div>
<div>
<q-input v-model="updateHttpMetadata[index].value" label="Value" />
</div>
<div class="flex">
<q-btn class="q-my-auto" round size="sm" color="orange" icon="remove" @click="updateHttpMetadata.splice(index, 1)" />
</div>
</div>

<h6 class="q-mt-xl q-mb-sm flex">Custom Metadata <q-btn class="q-mr-none q-ml-auto" round size="sm" color="primary" icon="add" @click="updateCustomMetadata.push({key: '', value: ''})" /></h6>
<div class="flex row" v-for="(val, index) in updateCustomMetadata" :key="index">
<div>
<q-input v-model="updateCustomMetadata[index].key" label="Key" />
</div>
<div>
<q-input v-model="updateCustomMetadata[index].value" label="Value" />
</div>
<div class="flex">
<q-btn class="q-my-auto" round size="sm" color="orange" icon="remove" @click="updateCustomMetadata.splice(index, 1)" />
</div>
</div>

</q-card-section>

<q-card-actions align="right">
<q-btn flat label="Cancel" color="primary" v-close-popup />
<q-btn flat label="Update Metadata" color="orange" :loading="loading" @click="updateConfirm" />
</q-card-actions>
</q-card>
</q-dialog>
</template>

<script>
Expand All @@ -45,9 +83,12 @@ export default defineComponent({
deleteFolderContents: [],
deleteModal: false,
renameModal: false,
updateMetadataModal: false,
deleteFolderInnerFilesCount: null,
newFolderName: "",
renameInput: "",
updateCustomMetadata: [],
updateHttpMetadata: [],
loading: false,
}),
methods: {
Expand All @@ -69,6 +110,24 @@ export default defineComponent({
// console.log(row)
this.renameInput = row.name;
},
updateMetadataObject: async function (row) {
this.updateMetadataModal = true;
this.row = row;
if (row.httpMetadata) {
this.updateHttpMetadata = Object.entries(row.httpMetadata).map(
([key, value]) => {
return { key: key, value: value };
},
);
}
if (row.customMetadata) {
this.updateCustomMetadata = Object.entries(row.customMetadata).map(
([key, value]) => {
return { key: key, value: value };
},
);
}
},
renameConfirm: async function () {
if (this.renameInput.length === 0) {
return;
Expand All @@ -91,6 +150,30 @@ export default defineComponent({
timeout: 2500, // we will timeout it in 2.5s
});
},
updateConfirm: async function () {
this.loading = true;
await apiHandler.updateMetadata(
this.selectedBucket,
this.row.key,
this.updateCustomMetadata.reduce(
(a, v) => ({ ...a, [v.key]: v.value }),
{},
),
this.updateHttpMetadata.reduce(
(a, v) => ({ ...a, [v.key]: v.value }),
{},
),
);
this.$bus.emit("fetchFiles");
this.reset();
this.q.notify({
group: false,
icon: "done", // we add an icon
spinner: false, // we reset the spinner setting so the icon can be displayed
message: "File Updated!",
timeout: 2500, // we will timeout it in 2.5s
});
},
deleteConfirm: async function () {
if (this.row.type === "folder") {
// When deleting folders, first must copy the objects, because the popup close forces a reset on properties
Expand Down Expand Up @@ -145,7 +228,10 @@ export default defineComponent({
this.loading = false;
this.deleteModal = false;
this.renameModal = false;
this.updateMetadataModal = false;
this.renameInput = "";
this.updateCustomMetadata = [];
this.updateHttpMetadata = [];
this.row = null;
this.deleteFolderInnerFilesCount = null;
this.deleteFolderContents = [];
Expand Down
17 changes: 12 additions & 5 deletions packages/dashboard/src/components/main/LeftSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,18 @@ export default defineComponent({
const resp = await fetch(
"https://api.github.com/repos/G4brym/R2-Explorer/releases/latest",
);
const parsed = await resp.json();
const latestVersion = parsed.tag_name.replace("v", "");
if (this.isUpdateAvailable(this.mainStore.version, latestVersion)) {
this.latestVersion = latestVersion;
this.updateAvailable = true;
if (!resp.ok) {
console.log("Unable to retrieve latest r2-explorer updates :(");
console.log(
"Manually check them here: https://github.com/G4brym/R2-Explorer/releases",
);
} else {
const parsed = await resp.json();
const latestVersion = parsed.tag_name.replace("v", "");
if (this.isUpdateAvailable(this.mainStore.version, latestVersion)) {
this.latestVersion = latestVersion;
this.updateAvailable = true;
}
}
},
setup() {
Expand Down
6 changes: 6 additions & 0 deletions packages/dashboard/src/pages/files/FileContextMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<q-item clickable v-close-popup @click="renameObject" v-if="prop.row.type === 'file'">
<q-item-section>Rename</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="updateMetadataObject" v-if="prop.row.type === 'file'">
<q-item-section>Update Metadata</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="shareObject">
<q-item-section>Get sharable link</q-item-section>
</q-item>
Expand Down Expand Up @@ -45,6 +48,9 @@ export default {
renameObject: function () {
this.$emit("renameObject", this.prop.row);
},
updateMetadataObject: function () {
this.$emit("updateMetadataObject", this.prop.row);
},
openObject: function () {
this.$emit("openObject", this.prop.row);
},
Expand Down
4 changes: 2 additions & 2 deletions packages/dashboard/src/pages/files/FilesFolderPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@
touch-position
context-menu
>
<FileContextMenu :prop="prop" @openObject="openObject" @deleteObject="$refs.options.deleteObject" @renameObject="$refs.options.renameObject" />
<FileContextMenu :prop="prop" @openObject="openObject" @deleteObject="$refs.options.deleteObject" @renameObject="$refs.options.renameObject" @updateMetadataObject="$refs.options.updateMetadataObject" />
</q-menu>
</template>

<template v-slot:body-cell-options="prop">
<td class="text-right">
<q-btn round flat icon="more_vert" size="sm">
<q-menu>
<FileContextMenu :prop="prop" @openObject="openObject" @deleteObject="$refs.options.deleteObject" @renameObject="$refs.options.renameObject" />
<FileContextMenu :prop="prop" @openObject="openObject" @deleteObject="$refs.options.deleteObject" @renameObject="$refs.options.renameObject" @updateMetadataObject="$refs.options.updateMetadataObject" />
</q-menu>
</q-btn>
</td>
Expand Down
2 changes: 1 addition & 1 deletion packages/worker/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "r2-explorer",
"version": "1.1.0",
"version": "1.1.1",
"description": "A Google Drive Interface for your Cloudflare R2 Buckets",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
Expand Down
2 changes: 2 additions & 0 deletions packages/worker/src/modules/buckets/putMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class PutMetadata extends OpenAPIRoute {
schema: z
.object({
customMetadata: z.record(z.string(), z.any()),
httpMetadata: z.record(z.string(), z.any()),
})
.openapi("Object metadata"),
},
Expand All @@ -43,6 +44,7 @@ export class PutMetadata extends OpenAPIRoute {
const object = await bucket.get(filePath);
return await bucket.put(filePath, object.body, {
customMetadata: data.body.customMetadata,
httpMetadata: data.body.httpMetadata,
});
}
}

0 comments on commit 8677325

Please sign in to comment.