Skip to main content
Deno 2 is finally here 🎉️
Learn more

denoKvAdmin

denoKvAdmin

A web interface for Deno KV Admin

import denoKvAdmin from "https://deno.land/x/deno_kv_admin@0.0.4/mod.ts";

Deno.serve(async (req: Request) => {
    if (new URL(req.url).pathname.startsWith("/kv")) return denoKvAdmin(req)
    return new Response("Hello World")
});

Demo https://kv-api.deno.dev/kv

Screenshots

image

Frontend
<!-- Use preprocessors via the lang attribute! e.g. <template lang="pug"> -->
<template>
  <div id="app">
    <header>
      <form @submit.prevent="set(key, value)">
        <input v-model="key" placeholder="key" title="separate by comma ," />
        <input v-model="value" placeholder="value as JSON" />
        <button :disabled="!isJSON(value)">Set</button>
      </form>
      <button v-show="entries.length" @click="deleteAll">Delete All</button>
    </header>
    <table v-show="entries.length">
      <thead>
        <tr>
          <th>Key</th>
          <th>Value as JSON</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="entry in entries">
          <td><input v-model="entry.key" size="50" /></td>
          <td><input v-model="entry.value" size="50" /></td>
          <td>
            <button
              :disabled="!isJSON(entry.value)"
              @click="set(entry.key, entry.value)"
            >
              Update
            </button>
          </td>
          <td><button @click="_delete(entry)">Delete</button></td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      entries: [],
      key: "",
      value: "",
      prefix:
        location.hostname === "cdpn.io"
          ? "https://kv-api.deno.dev/kv"
          : location.pathname
    };
  },
  async mounted() {
    this.entries = await fetch(this.prefix + "/list").then((r) => r.json());
    console.log(this.entries);
    this.entries = this.entries.map(({ key, value }) => ({
      key: key.join(),
      value: JSON.stringify(value)
    }));
    console.log(this.entries);
  },
  methods: {
    _delete(entry) {
      this.entries = this.entries.filter((e) => e.key !== entry.key);
      fetch(this.prefix + "?key=" + entry.key, {
        method: "DELETE"
      });
    },
    set(key, value) {
      fetch(this.prefix + "?key=" + key, {
        method: "POST",
        body: value
      });
      console.log(this.entries, key);
      const index = this.entries.findIndex((e) => e.key === key);
      if (index !== -1) {
        this.entries.splice(index, 1, { key, value });
      } else {
        this.entries.push({ key, value });
      }
    },
    deleteAll() {
      this.entries.forEach(this._delete);
    },
    isJSON(json) {
      try {
        JSON.parse(json);
        return true;
      } catch (e) {
        return false;
      }
    }
  }
};
</script>

<!-- Use preprocessors via the lang attribute! e.g. <style lang="scss"> -->
<style>
#app {
  margin: 0 auto;
  max-width: 960px;
  margin-top: 64px;
}

header {
  display: flex;
  justify-content: center;
  gap: 16px;
}

table {
  margin: 32px auto;
}

tbody tr:hover {
  background: lightgreen;
}
</style>