mirror of
https://ceregatti.org/git/daniel/dayzdockerserver.git
synced 2025-05-06 14:21:18 +00:00
Add Pinia store so we can have disparate components.
Add Vueuse core library for useFetch. Get async requests working with the above. Start using Vue's Suspense feature. Make Status its own component. Start adding search results. Continued work on error modal. Add CORS headers to the backend. Remove error store, as we only have one store. Rename favicon.png to favicon.ico. Remove functions from scripts where they are not used. Move functions to where they are used. Lots of WIP.
This commit is contained in:
parent
fd1774cf1c
commit
4a6427f893
23 changed files with 359 additions and 196 deletions
|
@ -60,3 +60,22 @@ prompt_yn(){
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# List mods
|
||||||
|
list(){
|
||||||
|
X=1
|
||||||
|
C="${green}"
|
||||||
|
spaces=" "
|
||||||
|
echo "Installed mods:"
|
||||||
|
echo -e " ID Name URL Size"
|
||||||
|
echo "------------------------------------------------------------------------------------------------------------------------"
|
||||||
|
for dir in $(ls -tr ${WORKSHOP_DIR})
|
||||||
|
do
|
||||||
|
ID=${dir}
|
||||||
|
NAME=$(grep name "${WORKSHOP_DIR}/${dir}/meta.cpp" | cut -d '"' -f2 | sed -r 's/\s+//g')
|
||||||
|
SIZE=$(du -sh "${WORKSHOP_DIR}/${dir}" | awk '{print $1}')
|
||||||
|
printf "${C}%.3d %s %.30s %s https://steamcommunity.com/sharedfiles/filedetails/?id=%s %s${default}\n" ${X} ${ID} "${NAME}" "${spaces:${#NAME}+1}" ${ID} ${SIZE}
|
||||||
|
X=$((X+1))
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
|
@ -450,9 +450,6 @@ case "${C}" in
|
||||||
login)
|
login)
|
||||||
login "${@}"
|
login "${@}"
|
||||||
;;
|
;;
|
||||||
m|modupdate)
|
|
||||||
modupdate "${@}"
|
|
||||||
;;
|
|
||||||
n|rcon)
|
n|rcon)
|
||||||
rcon "${@}"
|
rcon "${@}"
|
||||||
;;
|
;;
|
||||||
|
@ -471,9 +468,6 @@ case "${C}" in
|
||||||
stop)
|
stop)
|
||||||
stop "${@}"
|
stop "${@}"
|
||||||
;;
|
;;
|
||||||
u|update)
|
|
||||||
update "${@}"
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
usage "$*"
|
usage "$*"
|
||||||
;;
|
;;
|
||||||
|
|
19
web/bin/dz
19
web/bin/dz
|
@ -364,25 +364,6 @@ check_mod_install(){
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# List mods
|
|
||||||
list(){
|
|
||||||
X=1
|
|
||||||
C="${green}"
|
|
||||||
spaces=" "
|
|
||||||
echo "Installed mods:"
|
|
||||||
echo -e " ID Name URL Size"
|
|
||||||
echo "------------------------------------------------------------------------------------------------------------------------"
|
|
||||||
for dir in $(ls -tr ${WORKSHOP_DIR})
|
|
||||||
do
|
|
||||||
ID=${dir}
|
|
||||||
NAME=$(grep name "${WORKSHOP_DIR}/${dir}/meta.cpp" | cut -d '"' -f2 | sed -r 's/\s+//g')
|
|
||||||
SIZE=$(du -sh "${WORKSHOP_DIR}/${dir}" | awk '{print $1}')
|
|
||||||
printf "${C}%.3d %s %.30s %s https://steamcommunity.com/sharedfiles/filedetails/?id=%s %s${default}\n" ${X} ${ID} "${NAME}" "${spaces:${#NAME}+1}" ${ID} ${SIZE}
|
|
||||||
X=$((X+1))
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
|
|
||||||
# Capture the first argument and shift it off so we can pass $@ to every function
|
# Capture the first argument and shift it off so we can pass $@ to every function
|
||||||
C=${1}
|
C=${1}
|
||||||
shift || {
|
shift || {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" href="/favicon.png">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>DayZ Docker Server</title>
|
<title>DayZ Docker Server</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
134
web/docroot/package-lock.json
generated
134
web/docroot/package-lock.json
generated
|
@ -9,6 +9,7 @@
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
|
"@vueuse/core": "^10.1.2",
|
||||||
"bootstrap": "^5.3.0",
|
"bootstrap": "^5.3.0",
|
||||||
"bootstrap-icons": "^1.10.5",
|
"bootstrap-icons": "^1.10.5",
|
||||||
"pinia": "^2.1.3",
|
"pinia": "^2.1.3",
|
||||||
|
@ -396,6 +397,11 @@
|
||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/web-bluetooth": {
|
||||||
|
"version": "0.0.17",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz",
|
||||||
|
"integrity": "sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA=="
|
||||||
|
},
|
||||||
"node_modules/@vitejs/plugin-vue": {
|
"node_modules/@vitejs/plugin-vue": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz",
|
||||||
|
@ -516,6 +522,89 @@
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
|
||||||
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@vueuse/core": {
|
||||||
|
"version": "10.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.1.2.tgz",
|
||||||
|
"integrity": "sha512-roNn8WuerI56A5uiTyF/TEYX0Y+VKlhZAF94unUfdhbDUI+NfwQMn4FUnUscIRUhv3344qvAghopU4bzLPNFlA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/web-bluetooth": "^0.0.17",
|
||||||
|
"@vueuse/metadata": "10.1.2",
|
||||||
|
"@vueuse/shared": "10.1.2",
|
||||||
|
"vue-demi": ">=0.14.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/core/node_modules/vue-demi": {
|
||||||
|
"version": "0.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
|
||||||
|
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"bin": {
|
||||||
|
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||||
|
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.0.0-rc.1",
|
||||||
|
"vue": "^3.0.0-0 || ^2.6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/metadata": {
|
||||||
|
"version": "10.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.1.2.tgz",
|
||||||
|
"integrity": "sha512-3mc5BqN9aU2SqBeBuWE7ne4OtXHoHKggNgxZR2K+zIW4YLsy6xoZ4/9vErQs6tvoKDX6QAqm3lvsrv0mczAwIQ==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/shared": {
|
||||||
|
"version": "10.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.1.2.tgz",
|
||||||
|
"integrity": "sha512-1uoUTPBlgyscK9v6ScGeVYDDzlPSFXBlxuK7SfrDGyUTBiznb3mNceqhwvZHjtDRELZEN79V5uWPTF1VDV8svA==",
|
||||||
|
"dependencies": {
|
||||||
|
"vue-demi": ">=0.14.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vueuse/shared/node_modules/vue-demi": {
|
||||||
|
"version": "0.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
|
||||||
|
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"bin": {
|
||||||
|
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||||
|
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.0.0-rc.1",
|
||||||
|
"vue": "^3.0.0-0 || ^2.6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bootstrap": {
|
"node_modules/bootstrap": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz",
|
||||||
|
@ -975,6 +1064,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
|
||||||
},
|
},
|
||||||
|
"@types/web-bluetooth": {
|
||||||
|
"version": "0.0.17",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz",
|
||||||
|
"integrity": "sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA=="
|
||||||
|
},
|
||||||
"@vitejs/plugin-vue": {
|
"@vitejs/plugin-vue": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz",
|
||||||
|
@ -1086,6 +1180,46 @@
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
|
||||||
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
||||||
},
|
},
|
||||||
|
"@vueuse/core": {
|
||||||
|
"version": "10.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.1.2.tgz",
|
||||||
|
"integrity": "sha512-roNn8WuerI56A5uiTyF/TEYX0Y+VKlhZAF94unUfdhbDUI+NfwQMn4FUnUscIRUhv3344qvAghopU4bzLPNFlA==",
|
||||||
|
"requires": {
|
||||||
|
"@types/web-bluetooth": "^0.0.17",
|
||||||
|
"@vueuse/metadata": "10.1.2",
|
||||||
|
"@vueuse/shared": "10.1.2",
|
||||||
|
"vue-demi": ">=0.14.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue-demi": {
|
||||||
|
"version": "0.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
|
||||||
|
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
|
||||||
|
"requires": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@vueuse/metadata": {
|
||||||
|
"version": "10.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.1.2.tgz",
|
||||||
|
"integrity": "sha512-3mc5BqN9aU2SqBeBuWE7ne4OtXHoHKggNgxZR2K+zIW4YLsy6xoZ4/9vErQs6tvoKDX6QAqm3lvsrv0mczAwIQ=="
|
||||||
|
},
|
||||||
|
"@vueuse/shared": {
|
||||||
|
"version": "10.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.1.2.tgz",
|
||||||
|
"integrity": "sha512-1uoUTPBlgyscK9v6ScGeVYDDzlPSFXBlxuK7SfrDGyUTBiznb3mNceqhwvZHjtDRELZEN79V5uWPTF1VDV8svA==",
|
||||||
|
"requires": {
|
||||||
|
"vue-demi": ">=0.14.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue-demi": {
|
||||||
|
"version": "0.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
|
||||||
|
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
|
||||||
|
"requires": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"bootstrap": {
|
"bootstrap": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz",
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
|
"@vueuse/core": "^10.1.2",
|
||||||
"bootstrap": "^5.3.0",
|
"bootstrap": "^5.3.0",
|
||||||
"bootstrap-icons": "^1.10.5",
|
"bootstrap-icons": "^1.10.5",
|
||||||
"pinia": "^2.1.3",
|
"pinia": "^2.1.3",
|
||||||
|
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
|
@ -5,9 +5,13 @@ import Header from '@/components/Header.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<Suspense>
|
||||||
|
<main>
|
||||||
<Error />
|
<Error />
|
||||||
<div class="container-fluid min-vh-100 d-flex flex-column bg-light">
|
<div class="container-fluid min-vh-100 d-flex flex-column bg-light">
|
||||||
<Header />
|
<Header />
|
||||||
<Body />
|
<Body />
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
</Suspense>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import Mods from "@/components/Mods.vue"
|
import Mods from '@/components/Mods.vue'
|
||||||
import Modinfo from "@/components/Modinfo.vue";
|
import ModInfo from '@/components/Modinfo.vue'
|
||||||
|
import SearchResults from "@/components/SearchResults.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="row flex-grow-1">
|
<div class="row flex-grow-1">
|
||||||
<div class="col-md-3 border">
|
|
||||||
<Mods />
|
<Mods />
|
||||||
<Modinfo />
|
<ModInfo />
|
||||||
</div>
|
<SearchResults />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted } from 'vue'
|
import { onMounted } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { useErrorStore } from '@/stores/error'
|
|
||||||
const { errorText } = storeToRefs(useErrorStore())
|
|
||||||
import { Modal } from 'bootstrap'
|
import { Modal } from 'bootstrap'
|
||||||
|
import { useAppStore } from '@/stores/app.js'
|
||||||
|
const store = useAppStore()
|
||||||
let modal = {}
|
let modal = {}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
modal = new Modal('#errorModal', {})
|
modal = new Modal('#errorModal', {})
|
||||||
|
@ -28,7 +27,7 @@ onMounted(() => {
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
{{ errorText }}
|
{{ store.errorText }}
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
|
|
@ -1,35 +1,28 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import Search from '@/components/Search.vue'
|
import Search from '@/components/Search.vue'
|
||||||
import { useFetch } from '@/fetch.js'
|
import Status from '@/components/Status.vue'
|
||||||
const { data, error } = useFetch('/status')
|
import { useFetch } from '@vueuse/core'
|
||||||
|
const { error, data: status } = await useFetch('http://bubba:8000/status').get().json()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="! error && data" class="row">
|
<div v-if="status" class="row">
|
||||||
<div class="col-3 text-center">
|
<div class="col-3 text-center">
|
||||||
<h1>DayZ Docker Server</h1>
|
<h1>DayZ Docker Server</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<button
|
<button
|
||||||
@click="installbase"
|
@click="installbase"
|
||||||
:class="'btn ' + (data.installed ? 'btn-danger' : 'btn-success')"
|
:class="'btn btn-sm ' + (status.installed ? 'btn-danger' : 'btn-success')"
|
||||||
>
|
>
|
||||||
Install Server Files
|
Install Server Files
|
||||||
</button>
|
</button>
|
||||||
<button @click="updatebase" class="btn btn-success">Update Server Files</button>
|
<button @click="updatebase" class="btn btn-sm btn-success">Update Server Files</button>
|
||||||
<button @click="updatemods" class="btn btn-success">Update Mods</button>
|
<button @click="updatemods" class="btn btn-sm btn-success">Update Mods</button>
|
||||||
<button @click="servers" class="btn btn-primary">Servers</button>
|
<button @click="servers" class="btn btn-sm btn-primary">Servers</button>
|
||||||
<button @click="listmods" class="btn btn-primary">Mods</button>
|
<button @click="listmods" class="btn btn-sm btn-primary">Mods</button>
|
||||||
</div>
|
</div>
|
||||||
<Search />
|
<Search />
|
||||||
<div class="col">
|
<Status :status="status" />
|
||||||
<div>
|
|
||||||
Server files installed:
|
|
||||||
<span class="bi bi-check h2 text-success" v-if="data.installed"></span>
|
|
||||||
<span class="bi bi-x h2 danger text-danger" v-else></span>
|
|
||||||
</div>
|
|
||||||
<div v-if="data.version !== ''">
|
|
||||||
Version: <span class="text-success font-weight-bold">{{ data.version }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import { useFetch } from "@vueuse/core"
|
||||||
import xmltree from '@/components/XmlTree.vue'
|
import xmlTree from '@/components/XmlTree.vue'
|
||||||
import { useFetch} from '@/fetch'
|
import { useAppStore } from '@/stores/app.js'
|
||||||
const modId = ref(null)
|
const store = useAppStore()
|
||||||
const modInfo = null
|
const { data, error } = useFetch(() => `http://bubba:8000/mod/${store.modId}`, {
|
||||||
const xmlInfo = null
|
immediate: false,
|
||||||
const url = computed(() => baseUrl + '/mod/' + modId.value)
|
refetch: true
|
||||||
const { data } = useFetch(url)
|
}).get().json()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="col-md-9 border">
|
<div class="col-md-9 border">
|
||||||
<div class="d-flex" v-if="data">
|
<div v-if="error" class="d-flex">Error: {{ error }}</div>
|
||||||
|
<div v-else-if="data" class="d-flex">
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<strong>{{ data.name }}</strong>
|
<strong>{{ data.name }}</strong>
|
||||||
|
@ -27,7 +29,7 @@ const { data } = useFetch(url)
|
||||||
<li v-for="info in data.customXML">
|
<li v-for="info in data.customXML">
|
||||||
<a
|
<a
|
||||||
:class="'simulink xmlfile ' + info.name"
|
:class="'simulink xmlfile ' + info.name"
|
||||||
@click="modInfo=nfo.name"
|
@click="store.modFile=info.name"
|
||||||
>
|
>
|
||||||
{{ info.name }}
|
{{ info.name }}
|
||||||
</a>
|
</a>
|
||||||
|
@ -36,8 +38,8 @@ const { data } = useFetch(url)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-1"></div>
|
<div class="col-1"></div>
|
||||||
<div>
|
<div v-if="store.modFile">
|
||||||
<xmltree v-if="xmlInfo" :xmlData="xmlInfo" />
|
<xml-tree :file="store.modFile" :mod-id="store.modId" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useFetch} from '@/fetch'
|
import { useFetch} from '@vueuse/core'
|
||||||
const { data } = useFetch('/mods')
|
import { useAppStore } from '@/stores/app.js'
|
||||||
const modId = null
|
const store = useAppStore()
|
||||||
|
const { data, error } = await useFetch('http://bubba:8000/mods').get().json()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div class="col-md-3 border">
|
||||||
<div v-if="data">
|
<div v-if="data">
|
||||||
<h4 class="text-center">Installed Mods</h4>
|
<h4 class="text-center">Installed Mods</h4>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Steam Link</th>
|
<th>Steam Link</th>
|
||||||
<th>Mod Info</th>
|
<th>Mod Name</th>
|
||||||
</tr>
|
</tr>
|
||||||
<template
|
<template
|
||||||
v-for="mod in data.mods"
|
v-for="mod in data.mods"
|
||||||
|
@ -25,10 +27,11 @@ const modId = null
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="simulink" @click="modId=mod.id">{{ mod.name }}</a>
|
<a class="simulink" @click="store.modId=parseInt(mod.id)">{{ mod.name }}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,52 +1,12 @@
|
||||||
<!--<script setup>-->
|
<script setup>
|
||||||
<!--import { ref, computed } from 'vue'-->
|
import { useAppStore } from '@/stores/app.js'
|
||||||
<!--import { useFetch} from '@/fetch'-->
|
const store = useAppStore()
|
||||||
<!--const baseUrl = 'http://bubba:8000/search/'-->
|
</script>
|
||||||
<!--const searchTerm = ref('')-->
|
|
||||||
<!--const url = computed(() => baseUrl + searchTerm.value)-->
|
|
||||||
<!--const { data, error } = useFetch(url)-->
|
|
||||||
<!--</script>-->
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="col form-control-lg text-center">
|
<div class="col form-control-lg text-center">
|
||||||
<form @submit.prevent="searchTerm=this">
|
<form @submit.prevent="(e) => store.searchText=e.target.search.value">
|
||||||
<input name="search" placeholder="Search mods..." autofocus>
|
<input name="search" placeholder="Search mods..." autofocus>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "Search",
|
|
||||||
methods: {
|
|
||||||
handleSubmit(e) {
|
|
||||||
e.preventDefault()
|
|
||||||
fetch(this.apihost + '/search/' + e.target.search.value)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(response => {
|
|
||||||
this.modInfo = ""
|
|
||||||
this.XMLInfo = ""
|
|
||||||
// const sortField = "time_updated"
|
|
||||||
const sortField = "lifetime_subscriptions"
|
|
||||||
response.response.publishedfiledetails.sort((a, b) =>
|
|
||||||
a[sortField] < b[sortField] ? 1 : -1
|
|
||||||
)
|
|
||||||
this.searchResults = response.response.publishedfiledetails
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
// Enable all tooltips
|
|
||||||
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
|
||||||
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
|
||||||
return new bootstrap.Tooltip(tooltipTriggerEl)
|
|
||||||
})
|
|
||||||
// Enable all alerts
|
|
||||||
// $('.alert').alert()
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error)
|
|
||||||
this.fetchError = error.message
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -1,7 +1,50 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
const searchResults = null
|
import { useFetch} from '@vueuse/core'
|
||||||
|
import { useAppStore } from '@/stores/app.js'
|
||||||
|
const store = useAppStore()
|
||||||
|
const { data: searchResults, error } = useFetch(() => `http://bubba:8000/search/${store.searchText}`, {
|
||||||
|
immediate: false,
|
||||||
|
refetch: true
|
||||||
|
}).get().json()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "SearchResults",
|
||||||
|
methods: {
|
||||||
|
handleSubmit(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
fetch(this.apihost + '/search/' + e.target.search.value)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(response => {
|
||||||
|
this.modInfo = ""
|
||||||
|
this.XMLInfo = ""
|
||||||
|
// const sortField = "time_updated"
|
||||||
|
const sortField = "lifetime_subscriptions"
|
||||||
|
response.response.publishedfiledetails.sort((a, b) =>
|
||||||
|
a[sortField] < b[sortField] ? 1 : -1
|
||||||
|
)
|
||||||
|
this.searchResults = response.response.publishedfiledetails
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// Enable all tooltips
|
||||||
|
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
||||||
|
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||||
|
return new bootstrap.Tooltip(tooltipTriggerEl)
|
||||||
|
})
|
||||||
|
// Enable all alerts
|
||||||
|
// $('.alert').alert()
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error)
|
||||||
|
this.fetchError = error.message
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="searchResults" class="d-flex">
|
<div v-if="searchResults" class="d-flex">
|
||||||
<table>
|
<table>
|
||||||
|
|
17
web/docroot/src/components/Status.vue
Normal file
17
web/docroot/src/components/Status.vue
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<script setup>
|
||||||
|
const { status } = defineProps(['status'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="col">
|
||||||
|
<div>
|
||||||
|
Server files installed:
|
||||||
|
<span v-if="status.installed" class="bi bi-check h2 text-success"></span>
|
||||||
|
<span v-else class="bi bi-x h2 danger text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div v-if="status.version">
|
||||||
|
Version: <span class="text-success fw-bold">{{ status.version }}</span>
|
||||||
|
<span class="text-success fw-bold">({{ status.appid }})</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -33,7 +33,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span v-if="elem.nodeType === 3">{{elem.data.trim()}}</span>
|
<span v-if="elem.nodeType === 3">{{elem.data.trim()}}</span>
|
||||||
<div v-for="child in children">
|
<div v-for="child in children">
|
||||||
<xmltree v-if="child.nodeType !== 8" :element="child" :d="depth" />
|
<xml-tree v-if="child.nodeType !== 8" :element="child" :d="depth" />
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
v-if="elem.nodeType === 1 && elem.children.length > 0"
|
v-if="elem.nodeType === 1 && elem.children.length > 0"
|
||||||
|
@ -45,8 +45,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { useFetch } from '@vueuse/core'
|
||||||
export default {
|
export default {
|
||||||
name: "xmltree",
|
name: "xmlTree",
|
||||||
props: {
|
props: {
|
||||||
d: {
|
d: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@ -56,7 +57,14 @@ export default {
|
||||||
type: [Element, Text],
|
type: [Element, Text],
|
||||||
default: undefined
|
default: undefined
|
||||||
},
|
},
|
||||||
xmlData: String
|
file: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
modId: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -72,13 +80,14 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
elem() {
|
async elem() {
|
||||||
this.depth = parseInt(this.d) + 1
|
this.depth = parseInt(this.d) + 1
|
||||||
if (this.element) {
|
if (this.element) {
|
||||||
return this.element
|
return this.element
|
||||||
} else {
|
} else if(this.file) {
|
||||||
|
const { data } = await useFetch(`http://bubba:8000/mod/${this.modId}/${this.file}`)
|
||||||
const parser = new DOMParser()
|
const parser = new DOMParser()
|
||||||
const xmlDoc = parser.parseFromString(this.xmlData, "text/xml")
|
const xmlDoc = parser.parseFromString(data, "text/xml")
|
||||||
return xmlDoc.documentElement
|
return xmlDoc.documentElement
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { ref, isRef, unref, watchEffect } from 'vue'
|
|
||||||
const baseUrl = 'http://bubba:8000'
|
|
||||||
|
|
||||||
export function useFetch(url) {
|
|
||||||
const data = ref(null)
|
|
||||||
const error = ref(null)
|
|
||||||
async function doFetch() {
|
|
||||||
data.value = null
|
|
||||||
error.value = null
|
|
||||||
const urlValue = unref(baseUrl + url)
|
|
||||||
try {
|
|
||||||
const res = await fetch(urlValue)
|
|
||||||
data.value = await res.json()
|
|
||||||
} catch (e) {
|
|
||||||
error.value = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isRef(url)) {
|
|
||||||
watchEffect(doFetch)
|
|
||||||
} else {
|
|
||||||
doFetch()
|
|
||||||
}
|
|
||||||
return { data, error, retry: doFetch }
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@ import './css/index.css'
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import { useErrorStore } from '@/stores/error.js'
|
import {useAppStore} from "@/stores/app";
|
||||||
|
|
||||||
// Create an instance of our Vue app
|
// Create an instance of our Vue app
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
@ -22,8 +22,8 @@ app.config.globalProperties.steamUrl = 'https://steamcommunity.com/sharedfiles/f
|
||||||
|
|
||||||
// A global error handler
|
// A global error handler
|
||||||
app.config.errorHandler = (err, instance, info) => {
|
app.config.errorHandler = (err, instance, info) => {
|
||||||
const errorStore = useErrorStore()
|
const store = useAppStore()
|
||||||
errorStore.errorText = err.message
|
store.errorText = err.message
|
||||||
console.error('GLOBAL ERROR HANDLER! ', err, instance, info)
|
console.error('GLOBAL ERROR HANDLER! ', err, instance, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
web/docroot/src/stores/app.js
Normal file
10
web/docroot/src/stores/app.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useAppStore = defineStore('app', {
|
||||||
|
state: () => ({
|
||||||
|
errorText: '',
|
||||||
|
modId: 0,
|
||||||
|
modFile: '',
|
||||||
|
searchText: ''
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,9 +0,0 @@
|
||||||
import { ref, watch } from 'vue'
|
|
||||||
import { defineStore } from 'pinia'
|
|
||||||
export const useErrorStore = defineStore('errors', () => {
|
|
||||||
const errorText = ref(null)
|
|
||||||
watch(errorText, (t) => {
|
|
||||||
console.log("errorText: " + t)
|
|
||||||
})
|
|
||||||
return { errorText }
|
|
||||||
})
|
|
|
@ -1,17 +1,17 @@
|
||||||
const template = `
|
const template = `
|
||||||
<div
|
<div
|
||||||
class="modal"
|
class="modal"
|
||||||
id="staticBackdrop"
|
id="errorModal"
|
||||||
data-bs-backdrop="static"
|
data-bs-backdrop="static"
|
||||||
data-bs-keyboard="false"
|
data-bs-keyboard="false"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
aria-labelledby="staticBackdropLabel"
|
aria-labelledby="errorModalLabel"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h1 class="modal-title fs-5" id="staticBackdropLabel">Error</h1>
|
<h1 class="modal-title fs-5" id="errorModalLabel">Error</h1>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
@ -295,7 +295,7 @@ export default {
|
||||||
if(response.error) {
|
if(response.error) {
|
||||||
this.fetchError = response.error
|
this.fetchError = response.error
|
||||||
// Since it's a modal, we have to manually show it...?
|
// Since it's a modal, we have to manually show it...?
|
||||||
const modal = new bootstrap.Modal(document.getElementById('staticBackdrop'))
|
const modal = new bootstrap.Modal(document.getElementById('errorModal'))
|
||||||
modal.show()
|
modal.show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
39
web/web.js
39
web/web.js
|
@ -14,6 +14,13 @@ import { spawn } from 'child_process'
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
res.append('Access-Control-Allow-Origin', ['*'])
|
||||||
|
res.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
|
||||||
|
res.append('Access-Control-Allow-Headers', 'Content-Type')
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The DayZ server Steam app ID. USE ONE OR THE OTHER!!
|
The DayZ server Steam app ID. USE ONE OR THE OTHER!!
|
||||||
|
|
||||||
|
@ -33,6 +40,15 @@ const server_appid = "1042420"
|
||||||
*/
|
*/
|
||||||
const client_appid = "221100"
|
const client_appid = "221100"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Denote if it's release or experimental
|
||||||
|
*/
|
||||||
|
const versions = {
|
||||||
|
"1042420": "Experimental",
|
||||||
|
"223350": "Release"
|
||||||
|
}
|
||||||
|
const appid_version = versions[server_appid]
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Base file locations
|
Base file locations
|
||||||
*/
|
*/
|
||||||
|
@ -106,13 +122,14 @@ const config = {
|
||||||
|
|
||||||
const getVersion = (installed) => {
|
const getVersion = (installed) => {
|
||||||
if(installed) {
|
if(installed) {
|
||||||
return "1.20.bogus"
|
return "1.21.bogus"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDirSize = (dirPath) => {
|
const getDirSize = (dirPath) => {
|
||||||
let size = 0
|
let size = 0
|
||||||
|
if (! fs.existsSync(dirPath)) return size
|
||||||
const files = fs.readdirSync(dirPath)
|
const files = fs.readdirSync(dirPath)
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
const filePath = path.join(dirPath, files[i])
|
const filePath = path.join(dirPath, files[i])
|
||||||
|
@ -144,6 +161,7 @@ const getModNameById = (id) => {
|
||||||
if(sym.indexOf(id) > -1) return file.name
|
if(sym.indexOf(id) > -1) return file.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMods = () => {
|
const getMods = () => {
|
||||||
|
@ -245,20 +263,29 @@ app.get('/updatemods', (req, res) => {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get the status of things:
|
Get the status of things:
|
||||||
If the base files are installed, the version of the server, a list of mods, etc.
|
If the base files are installed, the version of the server, the appid (If release or experimental)
|
||||||
*/
|
*/
|
||||||
app.get('/status', (req, res) => {
|
app.get('/status', (req, res) => {
|
||||||
// FIXME Async/await this stuff...
|
// FIXME Async/await this stuff...
|
||||||
const installed = fs.existsSync(config.installFile)
|
const installed = fs.existsSync(config.installFile)
|
||||||
const mods = getMods()
|
|
||||||
const version = getVersion(installed)
|
const version = getVersion(installed)
|
||||||
const ret = {
|
const ret = {
|
||||||
"appid": server_appid,
|
"appid": appid_version,
|
||||||
"installed": installed,
|
"installed": installed,
|
||||||
"version": version,
|
"version": version
|
||||||
|
}
|
||||||
|
ret.error = "This is a test error from the back end"
|
||||||
|
res.send(ret)
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get all mod metadata
|
||||||
|
*/
|
||||||
|
app.get('/mods', (req, res) => {
|
||||||
|
const mods = getMods()
|
||||||
|
const ret = {
|
||||||
"mods": mods
|
"mods": mods
|
||||||
}
|
}
|
||||||
// ret.error = "This is a test error from the back end"
|
|
||||||
res.send(ret)
|
res.send(ret)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue