Merge pull request 'patches v1.7.4' (#118) from develop into main
Reviewed-on: #118
This commit is contained in:
commit
720337c9c4
11 changed files with 208 additions and 52 deletions
52
package-lock.json
generated
52
package-lock.json
generated
|
@ -18,6 +18,7 @@
|
||||||
"@headlessui/vue": "^1.7.23",
|
"@headlessui/vue": "^1.7.23",
|
||||||
"@heroicons/vue": "^2.2.0",
|
"@heroicons/vue": "^2.2.0",
|
||||||
"@tailwindcss/vite": "^4.1.11",
|
"@tailwindcss/vite": "^4.1.11",
|
||||||
|
"@vueuse/core": "^13.5.0",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
"event-source-polyfill": "^1.0.31",
|
"event-source-polyfill": "^1.0.31",
|
||||||
"grapesjs": "^0.22.11",
|
"grapesjs": "^0.22.11",
|
||||||
|
@ -3967,6 +3968,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/web-bluetooth": {
|
||||||
|
"version": "0.0.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
|
||||||
|
"integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.36.0",
|
"version": "8.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.36.0.tgz",
|
||||||
|
@ -4613,6 +4620,44 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vueuse/core": {
|
||||||
|
"version": "13.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.5.0.tgz",
|
||||||
|
"integrity": "sha512-wV7z0eUpifKmvmN78UBZX8T7lMW53Nrk6JP5+6hbzrB9+cJ3jr//hUlhl9TZO/03bUkMK6gGkQpqOPWoabr72g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/web-bluetooth": "^0.0.21",
|
||||||
|
"@vueuse/metadata": "13.5.0",
|
||||||
|
"@vueuse/shared": "13.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/metadata": {
|
||||||
|
"version": "13.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.5.0.tgz",
|
||||||
|
"integrity": "sha512-euhItU3b0SqXxSy8u1XHxUCdQ8M++bsRs+TYhOLDU/OykS7KvJnyIFfep0XM5WjIFry9uAPlVSjmVHiqeshmkw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/shared": {
|
||||||
|
"version": "13.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.5.0.tgz",
|
||||||
|
"integrity": "sha512-K7GrQIxJ/ANtucxIXbQlUHdB0TPA8c+q5i+zbrjxuhJCnJ9GtBg75sBSnvmLSxHKPg2Yo8w62PWksl9kwH0Q8g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.15.0",
|
"version": "8.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
|
@ -6409,14 +6454,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.8",
|
||||||
"es-set-tostringtag": "^2.1.0",
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"description": "Feuerwehr/Verein Mitgliederverwaltung UI",
|
"description": "Feuerwehr/Verein Mitgliederverwaltung UI",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite --host",
|
||||||
"build": "run-p type-check \"build-only {@}\" --",
|
"build": "run-p type-check \"build-only {@}\" --",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"build-only": "vite build",
|
"build-only": "vite build",
|
||||||
|
@ -33,6 +33,7 @@
|
||||||
"@headlessui/vue": "^1.7.23",
|
"@headlessui/vue": "^1.7.23",
|
||||||
"@heroicons/vue": "^2.2.0",
|
"@heroicons/vue": "^2.2.0",
|
||||||
"@tailwindcss/vite": "^4.1.11",
|
"@tailwindcss/vite": "^4.1.11",
|
||||||
|
"@vueuse/core": "^13.5.0",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
"event-source-polyfill": "^1.0.31",
|
"event-source-polyfill": "^1.0.31",
|
||||||
"grapesjs": "^0.22.11",
|
"grapesjs": "^0.22.11",
|
||||||
|
|
34
src/App.vue
34
src/App.vue
|
@ -2,11 +2,11 @@
|
||||||
<Modal />
|
<Modal />
|
||||||
<ContextMenu />
|
<ContextMenu />
|
||||||
|
|
||||||
<Header @contextmenu.prevent />
|
<AppHeader />
|
||||||
<div class="grow overflow-x-hidden overflow-y-auto p-2 md:p-4" @contextmenu.prevent>
|
<div class="grow overflow-x-hidden overflow-y-auto p-2 md:p-4">
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</div>
|
</div>
|
||||||
<Footer @contextmenu.prevent />
|
<AppFooter />
|
||||||
<Notification />
|
<Notification />
|
||||||
|
|
||||||
<Teleport to="head">
|
<Teleport to="head">
|
||||||
|
@ -18,10 +18,11 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineAsyncComponent, defineComponent, markRaw } from "vue";
|
||||||
|
import { onLongPress } from "@vueuse/core";
|
||||||
import { RouterView } from "vue-router";
|
import { RouterView } from "vue-router";
|
||||||
import Header from "./components/Header.vue";
|
import AppHeader from "./components/Header.vue";
|
||||||
import Footer from "./components/Footer.vue";
|
import AppFooter from "./components/Footer.vue";
|
||||||
import { mapActions, mapState } from "pinia";
|
import { mapActions, mapState } from "pinia";
|
||||||
import { useAuthStore } from "./stores/auth";
|
import { useAuthStore } from "./stores/auth";
|
||||||
import { isAuthenticatedPromise } from "./router/authGuard";
|
import { isAuthenticatedPromise } from "./router/authGuard";
|
||||||
|
@ -31,6 +32,7 @@ import Notification from "./components/Notification.vue";
|
||||||
import { config } from "./config";
|
import { config } from "./config";
|
||||||
import { useConfigurationStore } from "@/stores/configuration";
|
import { useConfigurationStore } from "@/stores/configuration";
|
||||||
import { resetAllPiniaStores } from "@/helpers/piniaReset";
|
import { resetAllPiniaStores } from "@/helpers/piniaReset";
|
||||||
|
import { useContextMenuStore } from "./stores/context-menu";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -40,6 +42,11 @@ export default defineComponent({
|
||||||
...mapState(useConfigurationStore, ["clubName"]),
|
...mapState(useConfigurationStore, ["clubName"]),
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
document.body.addEventListener("contextmenu", (event) => {
|
||||||
|
this.handleContextMenu(event);
|
||||||
|
});
|
||||||
|
onLongPress(document.body, this.handleContextMenu);
|
||||||
|
|
||||||
resetAllPiniaStores();
|
resetAllPiniaStores();
|
||||||
this.configure();
|
this.configure();
|
||||||
|
|
||||||
|
@ -52,6 +59,21 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useConfigurationStore, ["configure"]),
|
...mapActions(useConfigurationStore, ["configure"]),
|
||||||
|
...mapActions(useContextMenuStore, ["openContextMenu"]),
|
||||||
|
handleContextMenu(e: MouseEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// TODO allow contextmenu on elements with special attribute with reduced selection
|
||||||
|
const target = e.target as HTMLElement | null;
|
||||||
|
if (!target) return;
|
||||||
|
|
||||||
|
if (["INPUT", "TEXTAREA", "P", "H1", "H2", "H3", "H4"].includes((target as HTMLElement).nodeName)) {
|
||||||
|
this.openContextMenu(e, {
|
||||||
|
component_ref: markRaw(defineAsyncComponent(() => import("@/components/CopyPasteContextMenu.vue"))),
|
||||||
|
data: ["INPUT", "TEXTAREA"].includes((e.target as HTMLElement).nodeName) ? "" : "nopaste",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
ref="contextMenu"
|
ref="contextMenu"
|
||||||
class="absolute flex flex-col gap-1 border border-gray-400 bg-white rounded-md select-none text-left shadow-md z-50 p-1"
|
class="absolute flex flex-col gap-1 border border-gray-400 bg-white rounded-md select-none text-left shadow-md z-[100] p-1"
|
||||||
v-show="show"
|
v-show="show"
|
||||||
:style="contextMenuStyle"
|
:style="contextMenuStyle"
|
||||||
@contextmenu.prevent
|
|
||||||
@click="closeContextMenu"
|
@click="closeContextMenu"
|
||||||
>
|
>
|
||||||
<component :is="component_ref" :data="data" />
|
<component :is="component_ref" :data="data" />
|
||||||
|
|
61
src/components/CopyPasteContextMenu.vue
Normal file
61
src/components/CopyPasteContextMenu.vue
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-row gap-2 cursor-pointer hover:bg-gray-300 p-1 rounded-md" @click="copy">
|
||||||
|
<DocumentDuplicateIcon class="w-5 h-5" />
|
||||||
|
<p>kopieren</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="data != 'nopaste'"
|
||||||
|
class="flex flex-row gap-2 cursor-pointer hover:bg-gray-300 p-1 rounded-md"
|
||||||
|
@click="paste"
|
||||||
|
>
|
||||||
|
<ClipboardDocumentIcon class="w-5 h-5" />
|
||||||
|
<p>einfügen</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import { ClipboardDocumentIcon, DocumentDuplicateIcon } from "@heroicons/vue/24/outline";
|
||||||
|
import { mapState } from "pinia";
|
||||||
|
import { useContextMenuStore } from "@/stores/context-menu";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
props: ["data"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedText: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useContextMenuStore, ["clickedOnEl"]),
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.selectedText =
|
||||||
|
document.getSelection()?.toString() || this.clickedOnEl.value || this.clickedOnEl.innerText || "";
|
||||||
|
|
||||||
|
let selection = document.getSelection()?.toString();
|
||||||
|
console.log(selection);
|
||||||
|
if (selection == "") {
|
||||||
|
console.log("jo");
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNode(this.clickedOnEl);
|
||||||
|
console.log(range);
|
||||||
|
window.getSelection()?.removeAllRanges();
|
||||||
|
window.getSelection()?.addRange(range);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
copy() {
|
||||||
|
navigator.clipboard.writeText(this.selectedText);
|
||||||
|
},
|
||||||
|
paste() {
|
||||||
|
const el = this.clickedOnEl;
|
||||||
|
navigator.clipboard.readText().then((e) => {
|
||||||
|
el.value = e;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -3,21 +3,15 @@
|
||||||
ref="contextMenu"
|
ref="contextMenu"
|
||||||
class="absolute inset-0 w-full h-full flex justify-center items-center bg-black/50 select-none z-50 p-2"
|
class="absolute inset-0 w-full h-full flex justify-center items-center bg-black/50 select-none z-50 p-2"
|
||||||
v-show="show"
|
v-show="show"
|
||||||
@contextmenu.prevent
|
|
||||||
>
|
>
|
||||||
<!-- @click="closeModal" -->
|
<component :is="component_ref" :data="data" class="p-4 bg-white rounded-lg max-h-[95%] overflow-y-auto" />
|
||||||
<component
|
|
||||||
:is="component_ref"
|
|
||||||
:data="data"
|
|
||||||
@click.stop
|
|
||||||
class="p-4 bg-white rounded-lg max-h-[95%] overflow-y-auto"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { mapState, mapActions } from "pinia";
|
import { mapState, mapActions } from "pinia";
|
||||||
import { useModalStore } from "@/stores/modal";
|
import { useModalStore } from "@/stores/modal";
|
||||||
|
import { useContextMenuStore } from "@/stores/context-menu";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -27,6 +21,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useModalStore, ["closeModal"]),
|
...mapActions(useModalStore, ["closeModal"]),
|
||||||
|
...mapActions(useContextMenuStore, ["closeContextMenu"]),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex relative">
|
<div class="flex relative">
|
||||||
<input type="text" :value="copyText" />
|
<input type="text" readonly :value="copyText" />
|
||||||
<ClipboardIcon
|
<ClipboardIcon
|
||||||
class="w-5 h-5 p-2 box-content absolute right-1 top-1/2 -translate-y-1/2 bg-white cursor-pointer"
|
class="w-5 h-5 p-2 box-content absolute right-1 top-1/2 -translate-y-1/2 bg-white cursor-pointer"
|
||||||
@click="copyToClipboard"
|
@click="copyToClipboard"
|
||||||
|
|
52
src/components/admin/management/version/VersionItem.vue
Normal file
52
src/components/admin/management/version/VersionItem.vue
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<p>
|
||||||
|
<span class="font-semibold text-lg">{{ version.title }}</span> vom
|
||||||
|
{{
|
||||||
|
new Date(version.isoDate).toLocaleDateString("de", {
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
<div class="versionDisplay flex flex-col" v-html="version['content:encoded']"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Release } from "@/viewmodels/version.models";
|
||||||
|
import { defineComponent, type PropType } from "vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
version: {
|
||||||
|
type: Object as PropType<Release>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
@reference "@/main.css";
|
||||||
|
|
||||||
|
.versionDisplay :deep() ul {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.versionDisplay :deep() ul li::before {
|
||||||
|
content: "-";
|
||||||
|
margin-right: 10px;
|
||||||
|
color: black;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.versionDisplay :deep() a {
|
||||||
|
@apply text-primary;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,6 +8,7 @@ export const useContextMenuStore = defineStore("context-menu", {
|
||||||
show: false,
|
show: false,
|
||||||
component_ref: null as any,
|
component_ref: null as any,
|
||||||
data: null as any,
|
data: null as any,
|
||||||
|
clickedOnEl: null as any,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
|
@ -16,16 +17,18 @@ export const useContextMenuStore = defineStore("context-menu", {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
openContextMenu(e: MouseEvent, content: { component_ref: any; data: any }) {
|
openContextMenu(e: MouseEvent, content: { component_ref: any; data?: any }) {
|
||||||
this.component_ref = content.component_ref;
|
this.component_ref = content.component_ref;
|
||||||
this.data = content.data;
|
this.data = content.data;
|
||||||
this.contextX = e.pageX;
|
this.contextX = e.pageX;
|
||||||
this.contextY = e.pageY;
|
this.contextY = e.pageY;
|
||||||
|
this.clickedOnEl = e.target;
|
||||||
this.show = true;
|
this.show = true;
|
||||||
},
|
},
|
||||||
closeContextMenu() {
|
closeContextMenu() {
|
||||||
this.component_ref = null;
|
this.component_ref = null;
|
||||||
this.data = null;
|
this.data = null;
|
||||||
|
this.clickedOnEl = null;
|
||||||
this.show = false;
|
this.show = false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
</small>
|
</small>
|
||||||
</h1>
|
</h1>
|
||||||
<p>
|
<p>
|
||||||
V{{ clientVersion }} ({{
|
{{ clientVersion }} ({{
|
||||||
new Date(clientVersionRelease).toLocaleDateString("de", {
|
new Date(clientVersionRelease).toLocaleDateString("de", {
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
|
@ -23,19 +23,7 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grow flex flex-col gap-4 overflow-y-scroll">
|
<div class="grow flex flex-col gap-4 overflow-y-scroll">
|
||||||
<div v-for="version in newerClientVersions">
|
<VersionItem v-for="version in newerClientVersions" :key="version.title" :version="version" />
|
||||||
<p>
|
|
||||||
<span class="font-semibold text-lg">V{{ version.title }}</span> vom
|
|
||||||
{{
|
|
||||||
new Date(version.isoDate).toLocaleDateString("de", {
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
year: "numeric",
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
<div class="flex flex-col" v-html="version['content:encoded']"></div>
|
|
||||||
</div>
|
|
||||||
<div v-if="newerClientVersions.length == 0" class="flex items-center justify-center">
|
<div v-if="newerClientVersions.length == 0" class="flex items-center justify-center">
|
||||||
<p>Der Client ist auf der neuesten Version.</p>
|
<p>Der Client ist auf der neuesten Version.</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,7 +38,7 @@
|
||||||
</small>
|
</small>
|
||||||
</h1>
|
</h1>
|
||||||
<p>
|
<p>
|
||||||
V{{ serverVersion }} ({{
|
{{ serverVersion }} ({{
|
||||||
new Date(serverVersionRelease).toLocaleDateString("de", {
|
new Date(serverVersionRelease).toLocaleDateString("de", {
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
|
@ -61,20 +49,8 @@
|
||||||
}})
|
}})
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grow flex flex-col gap-2 overflow-y-scroll">
|
<div class="grow flex flex-col gap-4 overflow-y-scroll">
|
||||||
<div v-for="version in newerServerVersions">
|
<VersionItem v-for="version in newerServerVersions" :key="version.title" :version="version" />
|
||||||
<p>
|
|
||||||
<span class="font-semibold text-lg">V{{ version.title }}</span> vom
|
|
||||||
{{
|
|
||||||
new Date(version.isoDate).toLocaleDateString("de", {
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
year: "numeric",
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
<div class="flex flex-col" v-html="version['content:encoded']"></div>
|
|
||||||
</div>
|
|
||||||
<div v-if="newerServerVersions.length == 0" class="flex items-center justify-center">
|
<div v-if="newerServerVersions.length == 0" class="flex items-center justify-center">
|
||||||
<p>Der Server ist auf der neuesten Version.</p>
|
<p>Der Server ist auf der neuesten Version.</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,6 +66,7 @@ import { defineComponent } from "vue";
|
||||||
import MainTemplate from "@/templates/Main.vue";
|
import MainTemplate from "@/templates/Main.vue";
|
||||||
import clientPackage from "../../../../../package.json";
|
import clientPackage from "../../../../../package.json";
|
||||||
import type { Releases } from "@/viewmodels/version.models";
|
import type { Releases } from "@/viewmodels/version.models";
|
||||||
|
import VersionItem from "@/components/admin/management/version/VersionItem.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
<div class="flex flex-row gap-2">
|
<div class="flex flex-row gap-2">
|
||||||
<button type="submit" primary :disabled="resetStatus == 'loading' || resetStatus == 'success'">
|
<button type="submit" primary :disabled="resetStatus == 'loading' || resetStatus == 'success'">
|
||||||
TOTP zurücksetzen
|
Zugangsdaten zurücksetzen
|
||||||
</button>
|
</button>
|
||||||
<Spinner v-if="resetStatus == 'loading'" class="my-auto" />
|
<Spinner v-if="resetStatus == 'loading'" class="my-auto" />
|
||||||
<SuccessCheckmark v-else-if="resetStatus == 'success'" />
|
<SuccessCheckmark v-else-if="resetStatus == 'success'" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue