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
|
||||
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 "${@}"
|
||||
;;
|
||||
m|modupdate)
|
||||
modupdate "${@}"
|
||||
;;
|
||||
n|rcon)
|
||||
rcon "${@}"
|
||||
;;
|
||||
|
@ -471,9 +468,6 @@ case "${C}" in
|
|||
stop)
|
||||
stop "${@}"
|
||||
;;
|
||||
u|update)
|
||||
update "${@}"
|
||||
;;
|
||||
*)
|
||||
usage "$*"
|
||||
;;
|
||||
|
|
19
web/bin/dz
19
web/bin/dz
|
@ -364,25 +364,6 @@ check_mod_install(){
|
|||
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
|
||||
C=${1}
|
||||
shift || {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<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">
|
||||
<title>DayZ Docker Server</title>
|
||||
</head>
|
||||
|
|
134
web/docroot/package-lock.json
generated
134
web/docroot/package-lock.json
generated
|
@ -9,6 +9,7 @@
|
|||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"bootstrap": "^5.3.0",
|
||||
"bootstrap-icons": "^1.10.5",
|
||||
"pinia": "^2.1.3",
|
||||
|
@ -396,6 +397,11 @@
|
|||
"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": {
|
||||
"version": "4.2.3",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "5.3.0",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "4.2.3",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz",
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"bootstrap": "^5.3.0",
|
||||
"bootstrap-icons": "^1.10.5",
|
||||
"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>
|
||||
|
||||
<template>
|
||||
<Suspense>
|
||||
<main>
|
||||
<Error />
|
||||
<div class="container-fluid min-vh-100 d-flex flex-column bg-light">
|
||||
<Header />
|
||||
<Body />
|
||||
</div>
|
||||
</main>
|
||||
</Suspense>
|
||||
</template>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<script setup>
|
||||
import Mods from "@/components/Mods.vue"
|
||||
import Modinfo from "@/components/Modinfo.vue";
|
||||
import Mods from '@/components/Mods.vue'
|
||||
import ModInfo from '@/components/Modinfo.vue'
|
||||
import SearchResults from "@/components/SearchResults.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row flex-grow-1">
|
||||
<div class="col-md-3 border">
|
||||
<Mods />
|
||||
<Modinfo />
|
||||
</div>
|
||||
<ModInfo />
|
||||
<SearchResults />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useErrorStore } from '@/stores/error'
|
||||
const { errorText } = storeToRefs(useErrorStore())
|
||||
import { Modal } from 'bootstrap'
|
||||
import { useAppStore } from '@/stores/app.js'
|
||||
const store = useAppStore()
|
||||
let modal = {}
|
||||
onMounted(() => {
|
||||
modal = new Modal('#errorModal', {})
|
||||
|
@ -28,7 +27,7 @@ onMounted(() => {
|
|||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ errorText }}
|
||||
{{ store.errorText }}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
|
|
|
@ -1,35 +1,28 @@
|
|||
<script setup>
|
||||
import Search from '@/components/Search.vue'
|
||||
import { useFetch } from '@/fetch.js'
|
||||
const { data, error } = useFetch('/status')
|
||||
import Status from '@/components/Status.vue'
|
||||
import { useFetch } from '@vueuse/core'
|
||||
const { error, data: status } = await useFetch('http://bubba:8000/status').get().json()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="! error && data" class="row">
|
||||
<div v-if="status" class="row">
|
||||
<div class="col-3 text-center">
|
||||
<h1>DayZ Docker Server</h1>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<button
|
||||
@click="installbase"
|
||||
:class="'btn ' + (data.installed ? 'btn-danger' : 'btn-success')"
|
||||
:class="'btn btn-sm ' + (status.installed ? 'btn-danger' : 'btn-success')"
|
||||
>
|
||||
Install Server Files
|
||||
</button>
|
||||
<button @click="updatebase" class="btn btn-success">Update Server Files</button>
|
||||
<button @click="updatemods" class="btn btn-success">Update Mods</button>
|
||||
<button @click="servers" class="btn btn-primary">Servers</button>
|
||||
<button @click="listmods" class="btn btn-primary">Mods</button>
|
||||
<button @click="updatebase" class="btn btn-sm btn-success">Update Server Files</button>
|
||||
<button @click="updatemods" class="btn btn-sm btn-success">Update Mods</button>
|
||||
<button @click="servers" class="btn btn-sm btn-primary">Servers</button>
|
||||
<button @click="listmods" class="btn btn-sm btn-primary">Mods</button>
|
||||
</div>
|
||||
<Search />
|
||||
<div class="col">
|
||||
<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>
|
||||
<Status :status="status" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import xmltree from '@/components/XmlTree.vue'
|
||||
import { useFetch} from '@/fetch'
|
||||
const modId = ref(null)
|
||||
const modInfo = null
|
||||
const xmlInfo = null
|
||||
const url = computed(() => baseUrl + '/mod/' + modId.value)
|
||||
const { data } = useFetch(url)
|
||||
import { useFetch } from "@vueuse/core"
|
||||
import xmlTree from '@/components/XmlTree.vue'
|
||||
import { useAppStore } from '@/stores/app.js'
|
||||
const store = useAppStore()
|
||||
const { data, error } = useFetch(() => `http://bubba:8000/mod/${store.modId}`, {
|
||||
immediate: false,
|
||||
refetch: true
|
||||
}).get().json()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<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>
|
||||
<strong>{{ data.name }}</strong>
|
||||
|
@ -27,7 +29,7 @@ const { data } = useFetch(url)
|
|||
<li v-for="info in data.customXML">
|
||||
<a
|
||||
:class="'simulink xmlfile ' + info.name"
|
||||
@click="modInfo=nfo.name"
|
||||
@click="store.modFile=info.name"
|
||||
>
|
||||
{{ info.name }}
|
||||
</a>
|
||||
|
@ -36,8 +38,8 @@ const { data } = useFetch(url)
|
|||
</div>
|
||||
</div>
|
||||
<div class="col-1"></div>
|
||||
<div>
|
||||
<xmltree v-if="xmlInfo" :xmlData="xmlInfo" />
|
||||
<div v-if="store.modFile">
|
||||
<xml-tree :file="store.modFile" :mod-id="store.modId" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
<script setup>
|
||||
import { useFetch} from '@/fetch'
|
||||
const { data } = useFetch('/mods')
|
||||
const modId = null
|
||||
import { useFetch} from '@vueuse/core'
|
||||
import { useAppStore } from '@/stores/app.js'
|
||||
const store = useAppStore()
|
||||
const { data, error } = await useFetch('http://bubba:8000/mods').get().json()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="col-md-3 border">
|
||||
<div v-if="data">
|
||||
<h4 class="text-center">Installed Mods</h4>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Steam Link</th>
|
||||
<th>Mod Info</th>
|
||||
<th>Mod Name</th>
|
||||
</tr>
|
||||
<template
|
||||
v-for="mod in data.mods"
|
||||
|
@ -25,10 +27,11 @@ const modId = null
|
|||
</a>
|
||||
</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>
|
||||
</tr>
|
||||
</template>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,52 +1,12 @@
|
|||
<!--<script setup>-->
|
||||
<!--import { ref, computed } from 'vue'-->
|
||||
<!--import { useFetch} from '@/fetch'-->
|
||||
<!--const baseUrl = 'http://bubba:8000/search/'-->
|
||||
<!--const searchTerm = ref('')-->
|
||||
<!--const url = computed(() => baseUrl + searchTerm.value)-->
|
||||
<!--const { data, error } = useFetch(url)-->
|
||||
<!--</script>-->
|
||||
<script setup>
|
||||
import { useAppStore } from '@/stores/app.js'
|
||||
const store = useAppStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
</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>
|
||||
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>
|
||||
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>
|
||||
<div v-if="searchResults" class="d-flex">
|
||||
<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 v-if="elem.nodeType === 3">{{elem.data.trim()}}</span>
|
||||
<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>
|
||||
<span
|
||||
v-if="elem.nodeType === 1 && elem.children.length > 0"
|
||||
|
@ -45,8 +45,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { useFetch } from '@vueuse/core'
|
||||
export default {
|
||||
name: "xmltree",
|
||||
name: "xmlTree",
|
||||
props: {
|
||||
d: {
|
||||
type: Number,
|
||||
|
@ -56,7 +57,14 @@ export default {
|
|||
type: [Element, Text],
|
||||
default: undefined
|
||||
},
|
||||
xmlData: String
|
||||
file: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
modId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -72,13 +80,14 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
elem() {
|
||||
async elem() {
|
||||
this.depth = parseInt(this.d) + 1
|
||||
if (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 xmlDoc = parser.parseFromString(this.xmlData, "text/xml")
|
||||
const xmlDoc = parser.parseFromString(data, "text/xml")
|
||||
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 { createPinia } from 'pinia'
|
||||
import App from './App.vue'
|
||||
import { useErrorStore } from '@/stores/error.js'
|
||||
import {useAppStore} from "@/stores/app";
|
||||
|
||||
// Create an instance of our Vue app
|
||||
const app = createApp(App)
|
||||
|
@ -22,8 +22,8 @@ app.config.globalProperties.steamUrl = 'https://steamcommunity.com/sharedfiles/f
|
|||
|
||||
// A global error handler
|
||||
app.config.errorHandler = (err, instance, info) => {
|
||||
const errorStore = useErrorStore()
|
||||
errorStore.errorText = err.message
|
||||
const store = useAppStore()
|
||||
store.errorText = err.message
|
||||
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 = `
|
||||
<div
|
||||
class="modal"
|
||||
id="staticBackdrop"
|
||||
id="errorModal"
|
||||
data-bs-backdrop="static"
|
||||
data-bs-keyboard="false"
|
||||
tabindex="-1"
|
||||
aria-labelledby="staticBackdropLabel"
|
||||
aria-labelledby="errorModalLabel"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<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>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
@ -295,7 +295,7 @@ export default {
|
|||
if(response.error) {
|
||||
this.fetchError = response.error
|
||||
// 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()
|
||||
}
|
||||
})
|
||||
|
|
39
web/web.js
39
web/web.js
|
@ -14,6 +14,13 @@ import { spawn } from 'child_process'
|
|||
|
||||
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!!
|
||||
|
||||
|
@ -33,6 +40,15 @@ const server_appid = "1042420"
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
@ -106,13 +122,14 @@ const config = {
|
|||
|
||||
const getVersion = (installed) => {
|
||||
if(installed) {
|
||||
return "1.20.bogus"
|
||||
return "1.21.bogus"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
const getDirSize = (dirPath) => {
|
||||
let size = 0
|
||||
if (! fs.existsSync(dirPath)) return size
|
||||
const files = fs.readdirSync(dirPath)
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const filePath = path.join(dirPath, files[i])
|
||||
|
@ -144,6 +161,7 @@ const getModNameById = (id) => {
|
|||
if(sym.indexOf(id) > -1) return file.name
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
const getMods = () => {
|
||||
|
@ -245,20 +263,29 @@ app.get('/updatemods', (req, res) => {
|
|||
|
||||
/*
|
||||
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) => {
|
||||
// FIXME Async/await this stuff...
|
||||
const installed = fs.existsSync(config.installFile)
|
||||
const mods = getMods()
|
||||
const version = getVersion(installed)
|
||||
const ret = {
|
||||
"appid": server_appid,
|
||||
"appid": appid_version,
|
||||
"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
|
||||
}
|
||||
// ret.error = "This is a test error from the back end"
|
||||
res.send(ret)
|
||||
})
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue