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:
Daniel Ceregatti 2023-06-11 18:20:14 -07:00
parent fd1774cf1c
commit 4a6427f893
23 changed files with 359 additions and 196 deletions

View file

@ -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
}

View file

@ -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 "$*"
;;

View file

@ -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 || {

View file

@ -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>

View file

@ -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",

View file

@ -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",

View file

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View 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>

View file

@ -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
}
},

View file

@ -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 }
}

View file

@ -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)
}

View file

@ -0,0 +1,10 @@
import { defineStore } from 'pinia'
export const useAppStore = defineStore('app', {
state: () => ({
errorText: '',
modId: 0,
modFile: '',
searchText: ''
})
})

View file

@ -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 }
})

View file

@ -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()
}
})

View file

@ -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)
})