Icons, remove devtools, update to combining logic

This commit is contained in:
KaasKop
2025-04-06 14:53:53 +02:00
parent 569bdba727
commit bba275d4a0
13 changed files with 193 additions and 39 deletions

View File

@@ -1,5 +1,5 @@
{ {
"description": "Adds a toolbar extension from whence you can create permanent or temporari aliasses", "description": "Adds a toolbar extension from whence you can create permanent or temporari aliases",
"manifest_version": 3, "manifest_version": 3,
"name": "Moossages", "name": "Moossages",
"version": "0.1", "version": "0.1",

23
package-lock.json generated
View File

@@ -8,6 +8,8 @@
"name": "popup", "name": "popup",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@heroicons/vue": "^2.2.0",
"ky": "^1.8.0",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-router": "^4.5.0" "vue-router": "^4.5.0"
}, },
@@ -918,6 +920,15 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@heroicons/vue": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@heroicons/vue/-/vue-2.2.0.tgz",
"integrity": "sha512-G3dbSxoeEKqbi/DFalhRxJU4mTXJn7GwZ7ae8NuEQzd1bqdd0jAbdaBZlHPcvPD2xI1iGzNVB4k20Un2AguYPw==",
"license": "MIT",
"peerDependencies": {
"vue": ">= 3"
}
},
"node_modules/@jridgewell/gen-mapping": { "node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8", "version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
@@ -2517,6 +2528,18 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/ky": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/ky/-/ky-1.8.0.tgz",
"integrity": "sha512-DoKGmG27nT8t/1F9gV8vNzggJ3mLAyD49J8tTMWHeZvS8qLc7GlyTieicYtFzvDznMe/q2u38peOjkWc5/pjvw==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sindresorhus/ky?sponsor=1"
}
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",

View File

@@ -12,6 +12,8 @@
"type-check": "vue-tsc --build" "type-check": "vue-tsc --build"
}, },
"dependencies": { "dependencies": {
"@heroicons/vue": "^2.2.0",
"ky": "^1.8.0",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-router": "^4.5.0" "vue-router": "^4.5.0"
}, },
@@ -24,7 +26,6 @@
"typescript": "~5.8.0", "typescript": "~5.8.0",
"vite": "^6.2.4", "vite": "^6.2.4",
"vite-plugin-static-copy": "^2.3.0", "vite-plugin-static-copy": "^2.3.0",
"vite-plugin-vue-devtools": "^7.7.2",
"vue-tsc": "^2.2.8" "vue-tsc": "^2.2.8"
} }
} }

View File

@@ -1,19 +1,31 @@
<template> <template>
<div class="alias-list"> <div class="alias-list">
<AliasListItem v-for="alias in mailcowAliases" :alias="alias" /> <SpinnerComponent v-if="loading" />
<AliasListItem v-for="alias in mailcowAliases" :alias="alias" v-else />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { onMounted, ref } from 'vue';
import Alias from "@/types/alias.ts";
import AliasListItem from '@/components/AliasListItem.vue'; import AliasListItem from '@/components/AliasListItem.vue';
import SpinnerComponent from '@/components/SpinnerComponent.vue';
import { getAliases } from '@/lib/mailcow';
const mailcowAliases = ref([ const mailcowAliases = ref()
new Alias("kees@kaas.com", new Date(), "haha nee") const loading = ref(true);
])
onMounted(async () => {
mailcowAliases.value = await getAliases();
loading.value = false;
})
</script> </script>
<style scoped></style> <style scoped>
.alias-list {
display: flex;
flex-direction: column;
align-items: stretch;
}
</style>

View File

@@ -1,13 +1,62 @@
<template> <template>
{{ props.alias }} <div class="alias-list-item">
<div class="alias-list-item-addresses">
{{ props.alias.address }}
<span>
{{ props.alias.goto }}
</span>
</div>
<div class="alias-list-item-end">
{{ getValidity }}
<ClipboardIcon @click="copyAddress" class="icon" />
</div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type Alias from "@/types/alias.ts"; import type { Alias } from "@/types/alias.ts";
import { computed } from "vue";
import { ClipboardIcon } from "@heroicons/vue/24/outline";
const props = defineProps<{ const props = defineProps<{
alias: Alias alias: Alias
}>(); }>();
const getValidity = computed(() => {
if (!props.alias.validity) {
return "Unlimited"
}
let validityDate = new Date(props.alias.validity * 1000);
return `${validityDate.getDate()}-${validityDate.getMonth() + 1}-${validityDate.getFullYear()} ${validityDate.getHours()}:${validityDate.getMinutes()}:${validityDate.getSeconds()}`
})
const copyAddress = async () => {
await navigator.clipboard.writeText(props.alias.address);
}
</script> </script>
<style></style> <style scoped>
.alias-list-item {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid black;
}
.alias-list-item-addresses {
display: flex;
flex-direction: column;
span {
color: rgb(107, 114, 128)
}
}
.alias-list-item-end {
display: flex;
flex-direction: row;
align-items: center;
height: 100%;
}
</style>

View File

@@ -0,0 +1,20 @@
<template>
<div class="header">
<h2>Aliases</h2>
<PlusIcon class="icon" />
</div>
</template>
<script setup lang="ts">
import { PlusIcon } from '@heroicons/vue/24/outline';
</script>
<style scoped>
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
</style>

View File

@@ -0,0 +1,28 @@
<template>
<div class="spinner"></div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.spinner {
width: 40px;
height: 40px;
border-radius: 50%;
border: 4px solid #ccc;
border-top-color: #333;
animation: spin 0.8s linear infinite;
align-self: center;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>

6
src/css/main.css Normal file
View File

@@ -0,0 +1,6 @@
.icon {
width: 2em;
height: 2em;
cursor: pointer;
}

View File

@@ -1,3 +1,24 @@
class Mailcow { import type { Aliases } from "@/types/alias";
apiUrl: string = "kaas"; import ky from "ky";
export const getAliases = async (): Promise<Aliases> => {
let aliases: Aliases = [];
let domainAliases = await ky("http://mail.example.com/api/v1/get/alias/all", {
headers: {
"X-Api-Key": "06144A-E4FD48-6E8373-7FF408-DE84A7"
}
}).json<Aliases>();
if (domainAliases instanceof Array) {
aliases = aliases.concat(domainAliases);
}
let temporaryAliases = await ky("http://mail.example.com/api/v1/get/time_limited_aliases/kaas@example.com", {
headers: {
"X-Api-Key": "06144A-E4FD48-6E8373-7FF408-DE84A7"
}
}).json<Aliases>();
if (temporaryAliases instanceof Array) {
aliases = aliases.concat(temporaryAliases);
}
return aliases;
} }

View File

@@ -1,3 +1,4 @@
import './css/main.css'
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router.ts' import router from './router.ts'

View File

@@ -1,24 +1,17 @@
// export default class Alias { export type Aliases = Alias[]
// address: string;
// expiration: Date;
// description: string;
//
// constructor(address: string, expiration: Date, description: string) {
// this.address = address;
// this.expiration = expiration;
// this.description = description;
// }
// }
//
export default class Alias { export interface Alias {
address: string; active: string
expiration: Date; address: string
description: string; created: string
domain: string
constructor(address: string, expiration: Date, description: string) { goto: string
this.address = address; id: number
this.expiration = expiration; in_primary_domain: string
this.description = description; is_catch_all: number
} modified?: any
}; private_comment?: any
public_comment?: any
// Only if its a temporary alias
validity?: number
}

View File

@@ -1,8 +1,10 @@
<template> <template>
<HeaderBar />
<AliasList /> <AliasList />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import HeaderBar from '@/components/HeaderBar.vue';
import AliasList from '@/components/AliasList.vue'; import AliasList from '@/components/AliasList.vue';
</script> </script>

View File

@@ -2,13 +2,11 @@ import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import { viteStaticCopy } from 'vite-plugin-static-copy' import { viteStaticCopy } from 'vite-plugin-static-copy'
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
vue(), vue(),
vueDevTools(),
viteStaticCopy({ viteStaticCopy({
targets: [ targets: [
{ {