Minor Improvements

This commit is contained in:
Andreas Dinauer 2026-04-18 22:21:50 +02:00
parent 3b7cfd7ef1
commit 26102a9041
10 changed files with 236 additions and 52 deletions

View File

@ -10,7 +10,9 @@
<NuxtLink class="link left-center" :class="{ active: useRoute().fullPath.startsWith('/settings') }" to="/settings"><UiIcon>settings</UiIcon>Settings</NuxtLink>
<a class="link left-center" :href="useRuntimeConfig().public.logoutUrl"><UiIcon>logout</UiIcon> Log Out</a>
</div>
<NuxtPage></NuxtPage>
<div class="page-content">
<NuxtPage></NuxtPage>
</div>
</div>
<PopupTemplate v-if="popup" :heading="popup.config.heading" :size="popup.config.size">
<component :is="popup.component"></component>
@ -41,10 +43,11 @@ onMounted(() => {
width: 100%;
min-height: 100%;
}
.page > * {
padding: 1rem;
.page-content {
padding: 2rem;
}
.sidebar {
padding: 1rem;
background-color: var(--tile-color);
border-right: 1px solid #cddaff;
display: grid;

View File

@ -96,7 +96,6 @@
gap: 1rem;
}
.content-xl {
display: grid;
gap: 2rem;
}

View File

@ -20,6 +20,7 @@ html, body, #__nuxt {
html {
--tile-color: #eef6ff;
--primary-color: #3c74ff;
--danger-color: #e10808;
}
h3 {

View File

@ -0,0 +1,54 @@
<template>
<div class="content-l">
<h2>Dependency</h2>
<div class="tile-m" v-for="dependency in [formatDependency(version)]">
<Codebox :content="dependency"></Codebox>
</div>
<div class="col-2">
<div class="content-m">
<h2>Files</h2>
<p class="tile-m pointer" v-if="version.jars" v-for="jar in version.jars" @click="Download.download(jar.url)">{{ jar.filename }}</p>
<a class="tile-m" v-if="version.pom" :href="'/api/maven2/' + version.pom.url" target="_blank">{{ version.pom.filename }}</a>
</div>
<div class="content-m danger-zone" style="align-self: start">
<h2>Danger Zone</h2>
<div>
<UiButton class="delete">Delete Version</UiButton>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {Download} from "~/utils/Download";
import Codebox from "~/components/artifact/Codebox.vue";
import type {Version} from "~/components/artifact/Artifact";
defineProps<{
version: Version
}>();
const formatDependency = (version: Version) => {
const template = [
"<dependency>",
"\t<groupId>" + version.groupId + "</groupId>",
"\t<artifactId>" + version.artifactId + "</artifactId>",
"\t<version>" + version.version + "</version>",
"</dependency>"
]
return template.join("\n");
};
</script>
<style scoped>
.delete {
background-color: var(--danger-color);
}
.danger-zone {
background-color: #ffeae7;
padding: 1rem;
border-radius: 0.25rem;
border: 1px solid #ffb5b5;
}
</style>

View File

@ -1,6 +1,7 @@
<template>
<div class="codebox">
<p v-html="content"></p>
<div style="position: relative">
<div @click="copy(content)" class="copy center"><UiIcon>content_copy</UiIcon></div>
<p class="code" v-text="content"></p>
</div>
</template>
@ -8,13 +9,31 @@
defineProps<{
content: string
}>()
function copy(content: string)
{
navigator.clipboard.writeText(content)
}
</script>
<style scoped>
.codebox * {
.code {
font-family: "Roboto Mono", monospace;
font-optical-sizing: auto;
white-space: preserve;
tab-size: 2;
}
.copy {
height: 2rem;
width: 2rem;
position: absolute;
background-color: var(--primary-color);
right: 0;
border-radius: 0.25rem;
cursor: pointer;
user-select: none;
}
.copy * {
color: white;
}
</style>

View File

@ -1,33 +1,23 @@
<template>
<div v-if="artifact" class="content-l">
<div v-if="artifact" class="content-xl">
<h1>Artifact</h1>
<div class="col-2">
<p class="tile-m">{{ artifact.groupId }}</p>
<p class="tile-m">{{ artifact.artifactId }}</p>
</div>
<div class="artifact-page">
<div class="content-m" v-if="selectedVersion">
<h2>Dependency</h2>
<div class="tile-m" v-if="dependency">
<Codebox :content="dependency"></Codebox>
</div>
<div class="content-m">
<h2>Files</h2>
<p class="tile-m" v-if="selectedVersion.jars" v-for="jar in selectedVersion.jars" @click="Download.download(jar.url)">{{ jar.filename }}</p>
<a class="tile-m" v-if="selectedVersion.pom" :href="'/api/maven2/' + selectedVersion.pom.url" target="_blank">{{ selectedVersion.pom.filename }}</a>
</div>
<div class="content-m">
<h2>Actions</h2>
<div>
<UiButton @click="del" class="delete">Delete</UiButton>
</div>
</div>
</div>
<VersionComponent :version="selectedVersion" v-if="selectedVersion"></VersionComponent>
<div class="content-m">
<h2>Versions</h2>
<p class="tile-m pointer" v-for="version in artifact.versions" :class="{ active: (selectedVersion != null && version.id === selectedVersion.id) }" @click="() => { selectedVersion = version }">{{ version.version }}</p>
</div>
</div>
<div class="content-m danger-zone">
<h2>Danger Zone</h2>
<div>
<UiButton @click="del" class="delete">Delete Artifact</UiButton>
</div>
</div>
</div>
</template>
@ -42,11 +32,7 @@ onMounted(() => {
const id = useRoute().params.id as string;
Artifact.getById(id, (_artifact: Artifact) => {
artifact.value = _artifact;
const _version = _artifact.versions.at(0);
if (_version != null)
{
selectedVersion.value = _version;
}
selectedVersion.value = _artifact.versions.at(0);
})
})
@ -57,21 +43,6 @@ function del()
useRouter().push("/artifacts");
})
}
const dependency = computed(() => {
if (selectedVersion.value)
{
const template = [
"<dependency>",
"\t<groupId>" + selectedVersion.value.groupId + "</groupId>",
"\t<artifactId>" + selectedVersion.value.artifactId + "</artifactId>",
"\t<version>" + selectedVersion.value.version + "</version>",
"</dependency>"
]
return template.join("\n").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
return undefined;
});
</script>
<style scoped>
@ -86,6 +57,12 @@ const dependency = computed(() => {
border: none;
}
.delete {
background-color: #e63515;
background-color: var(--danger-color);
}
.danger-zone {
background-color: #ffeae7;
padding: 1rem;
border-radius: 0.25rem;
border: 1px solid #ffb5b5;
}
</style>

View File

@ -2,11 +2,18 @@
<div class="content-l" v-if="group">
<h1>Group: {{group.groupId}}</h1>
<ArtifactList :artifacts="group.artifacts"></ArtifactList>
<div class="content-m">
<h2>Danger Zone</h2>
<div>
<UiButton class="delete-button" @click="del(group)">Delete</UiButton>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {Group} from "~/components/group/Group";
import {useDelete} from "~/utils/HttpUtils";
const group: Ref<Group | undefined> = ref();
@ -16,8 +23,17 @@ onMounted(() => {
group.value = _group;
})
})
function del(group: Group)
{
useDelete("/api/groups/" + group.id, () => {
useRouter().push("/groups");
})
}
</script>
<style scoped>
.delete-button {
background-color: var(--danger-color);
}
</style>

View File

@ -1,6 +1,16 @@
<template>
<div class="content-l">
<h1>Home</h1>
<h1>Hello, Andreas Dinauer</h1>
<div class="col-2">
<div class="tile-m spaced-center">
<p>Total Groups</p>
<p v-if="groups.data"><b>{{groups.data.length}}</b></p>
</div>
<div class="tile-m spaced-center">
<p>Total Artifacts</p>
<p v-if="artifacts.data"><b>{{artifacts.data.length}}</b></p>
</div>
</div>
<h2>Recent Events</h2>
<EventList></EventList>
</div>
@ -8,6 +18,11 @@
<script setup lang="ts">
import EventList from "~/components/events/EventList.vue";
import type {Group} from "~/components/group/Group";
import type {Artifact} from "~/components/artifact/Artifact";
const groups = useGet<Group[]>("/api/groups");
const artifacts = useGet<Artifact[]>("/api/artifacts");
</script>
<style scoped>

View File

@ -10,10 +10,6 @@
<h3>E-Mail</h3>
<p>andreas.j.dinauer@gmail.com</p>
</div>
<div class="tile-m">
<h3>Password</h3>
<p>************</p>
</div>
</div>
<h1>Access Tokens</h1>
<div v-if="tokens">

104
app/utils/HttpUtils.ts Normal file
View File

@ -0,0 +1,104 @@
import axios, {AxiosError} from "axios";
export class PostRequestState
{
loading?: boolean = true;
}
export function usePost<R, P>(path: string, body?: P, onSuccess?: (response: R) => void, onError?: () => {})
{
const state = ref(new PostRequestState());
axios.post<R>(path, body)
.then((response) => {
console.log("jfdsl");
if (onSuccess)
{
onSuccess(response.data);
}
state.value.loading = false;
})
.catch(() => {
if (onError)
{
onError();
}
state.value.loading = false;
});
return state;
}
export class GetRequestState<R>
{
constructor(
public loading: boolean,
public data?: R,
public error?: AxiosError
) {}
}
export function useGet<R>(path: string)
{
const state = ref(new GetRequestState<R>(true, undefined, undefined));
axios.get<R>(path)
.then((response) => {
state.value = new GetRequestState<R>(false, response.data, undefined);
})
.catch((error) => {
state.value = new GetRequestState<R>(false, undefined, error);
});
return state;
}
export class DeleteRequestState
{
constructor(
public loading: boolean
) {}
}
export function useDelete<R>(path: string, onSuccess?: () => void, onError?: () => {})
{
const state = ref(new DeleteRequestState(true));
axios.delete(path)
.then(() => {
if (onSuccess)
{
onSuccess();
}
state.value = new DeleteRequestState(false);
})
.catch(() => {
if (onError)
{
onError();
}
state.value = new DeleteRequestState(false);
});
return state;
}
export class PutRequestState
{
loading?: boolean = true;
}
export function usePut<R, P>(path: string, body?: P, onSuccess?: (response: R) => void, onError?: () => {})
{
const state = ref(new PutRequestState());
axios.put<R>(path, body)
.then((response) => {
if (onSuccess)
{
onSuccess(response.data);
}
state.value.loading = false;
})
.catch(() => {
if (onError)
{
onError();
}
state.value.loading = false;
});
return state;
}