I dont even remember

This commit is contained in:
iamBadgers
2026-07-18 18:40:58 -07:00
parent b34aa722e4
commit 0ade9df7bc
8 changed files with 156 additions and 155 deletions

View File

@@ -6,7 +6,7 @@ import InputText from 'primevue/inputtext'
import Button from 'primevue/button' import Button from 'primevue/button'
import Card from 'primevue/card' import Card from 'primevue/card'
import Select from 'primevue/select' import Select from 'primevue/select'
import FloatLabel from 'primevue/floatlabel'; import FloatLabel from 'primevue/floatlabel'
const router = useRouter() const router = useRouter()
const table_name = ref() const table_name = ref()
@@ -60,7 +60,12 @@ function clear() {
</FloatLabel> </FloatLabel>
<FloatLabel variant="on"> <FloatLabel variant="on">
<Select id="table_version" class="button-box w-full" v-model="version" :options="availableVersion"></Select> <Select
id="table_version"
class="button-box w-full"
v-model="version"
:options="availableVersion"
></Select>
<label for="table_version">Foundry Version</label> <label for="table_version">Foundry Version</label>
</FloatLabel> </FloatLabel>
</div> </div>

View File

@@ -1,5 +1,5 @@
<template> <template>
<Form v-if="!userData.authenticated" v-slot="$form" @submit="onFormSubmit"> <Form v-if="userData === null || !userData.authenticated" v-slot="$form" @submit="onFormSubmit">
<div class="flex flex-column"> <div class="flex flex-column">
<InputText name="username" type="text" placeholder="Username" fluid /> <InputText name="username" type="text" placeholder="Username" fluid />
<Password name="password" placeholder="Password" :feedback="false" fluid /> <Password name="password" placeholder="Password" :feedback="false" fluid />
@@ -7,7 +7,7 @@
</div> </div>
</Form> </Form>
<div v-if="userData.authenticated"> <div v-if="userData !== null && userData.authenticated">
<div>Logged in as: {{ userData.is_admin ? 'Admin' : '' }} {{ userData.username }}</div> <div>Logged in as: {{ userData.is_admin ? 'Admin' : '' }} {{ userData.username }}</div>
<Form v-slot="$form" @submit="onResetPassword"> <Form v-slot="$form" @submit="onResetPassword">
<Password name="password" placeholder="Password" :feedback="false" fluid /> <Password name="password" placeholder="Password" :feedback="false" fluid />

View File

@@ -42,15 +42,14 @@ onMounted(() => {
function tableLink() { function tableLink() {
if (!selectedTableRef.value) { if (!selectedTableRef.value) {
linkVisible.value = false linkVisible.value = false
return "" return ''
} }
linkVisible.value = true linkVisible.value = true
return 'http://' + hostname.value + "/" + selectedTableRef.value.table_link return 'http://' + hostname.value + '/' + selectedTableRef.value.table_link
} }
function displayUsername(): string { function displayUsername(): string {
const authenticated = userRef.value.authenticated if (userRef.value !== null && userRef.value.authenticated) {
if (authenticated) {
return userRef.value.username return userRef.value.username
} }
return 'Login' return 'Login'

View File

@@ -1,19 +1,20 @@
<template> <template>
<ConfirmDialog></ConfirmDialog> <ConfirmDialog></ConfirmDialog>
<div class="flex flex-row"> <div class="flex flex-row" v-if="activeTable">
<Card class="detailCard flex"> <Card class="detailCard flex">
<template #title> <template #title>
{{ table.table_name }} {{ activeTable.table_name }}
</template> </template>
<template #subtitle> <template #subtitle>
<div> <div>
Status: Status:
<Chip :class="table.active ? 'active' : 'inactive'" :label="table.active ? 'active' : 'inactive'" /> <Chip :class="activeTable.active ? 'active' : 'inactive'"
:label="activeTable.active ? 'active' : 'inactive'" />
</div> </div>
</template> </template>
<template #content> <template #content>
<div :class="table.active ? 'active-foundry-stats' : 'inactive-foundry-stats'"> <div :class="activeTable.active ? 'active-foundry-stats' : 'inactive-foundry-stats'">
<div>Table Status: {{ foundryStatus.active }}</div> <div>Table Status: {{ foundryStatus.active }}</div>
<div>World: {{ foundryStatus.world }}</div> <div>World: {{ foundryStatus.world }}</div>
<div>Users: {{ foundryStatus.users }}</div> <div>Users: {{ foundryStatus.users }}</div>
@@ -21,18 +22,18 @@
</template> </template>
<template #footer> <template #footer>
<div> <div>
<Button class="button-box" label="Start" @click="startTable(activeTable!)" /> <Button class="button-box" label="Start" @click="startTable(activeTable)" />
<Button class="button-box" label="Stop" @click="stopTable(activeTable!)" /> <Button class="button-box" label="Stop" @click="stopTable(activeTable)" />
</div> </div>
<div> <div>
<Button class="button-box" label="Hard Start" @click="hardStartTable(activeTable!)" /> <Button class="button-box" label="Hard Start" @click="hardStartTable(activeTable)" />
<Button class="button-box" label="Delete" @click="protectedDelete()" /> <Button class="button-box" label="Delete" @click="protectedDelete()" />
</div> </div>
</template> </template>
</Card> </Card>
<Form :key="forceReset" ref="edit-form" :initialValues="activeTable!" @submit="save"> <Form :key="forceReset" ref="edit-form" :initialValues="activeTable!" @submit="save">
<Card class="detailCard flex"> <Card class="detailCard">
<template #title> Edit Details </template> <template #title> Edit Details </template>
<template #content> <template #content>
<div class="flex flex-column"> <div class="flex flex-column">
@@ -45,8 +46,8 @@
<label>Table Link</label> <label>Table Link</label>
</FloatLabel> </FloatLabel>
<FloatLabel variant="on"> <FloatLabel variant="on">
<Select class="button-box" name="version" :options="availableVersion"></Select> <Select class="button-box" name="version" placeholder="11" :options="availableVersion"></Select>
<label>Table Link</label> <label>Version</label>
</FloatLabel> </FloatLabel>
</div> </div>
</template> </template>
@@ -95,9 +96,10 @@ import Card from 'primevue/card'
import Chip from 'primevue/chip' import Chip from 'primevue/chip'
import Select from 'primevue/select' import Select from 'primevue/select'
import ConfirmDialog from 'primevue/confirmdialog' import ConfirmDialog from 'primevue/confirmdialog'
import FloatLabel from 'primevue/floatlabel'; import FloatLabel from 'primevue/floatlabel'
import { import {
getFoundryStatus,
useSelectedTable, useSelectedTable,
loadSelectedTable, loadSelectedTable,
clearSelectedTable, clearSelectedTable,
@@ -107,8 +109,9 @@ import {
updateTable, updateTable,
deleteTable, deleteTable,
} from './game_tables' } from './game_tables'
import { useUserData } from './user'
import type { GameTable } from './game_tables' import type { GameTable, FoundryStatus } from './game_tables'
import type { Ref } from 'vue' import type { Ref } from 'vue'
const hostname = ref() const hostname = ref()
@@ -116,44 +119,28 @@ const route = useRoute()
const router = useRouter() const router = useRouter()
const confirm = useConfirm() const confirm = useConfirm()
const table = reactive({ const activeUser = useUserData()
table_name: 'default',
table_link: 'default',
active: 0,
version: 0,
})
const activeTable: Ref<GameTable | null> = useSelectedTable() const activeTable: Ref<GameTable | null> = useSelectedTable()
const forceReset = ref(0) const forceReset = ref(0)
const foundryStatus = reactive({ const foundryStatus: Ref<FoundryStatus> = ref({
running: false, running: false,
active: false, active: false,
world: '', world: '',
users: 0, users: 0,
}) })
const currentUser = ref({
username: 'None',
authenticated: 'False',
is_admin: 'False',
})
const availableVersion = ref([11, 12]) const availableVersion = ref([11, 12])
var interval: number var interval: number
onMounted(() => { onMounted(() => {
interval = setInterval(() => { interval = setInterval(() => {
readTable()
readFoundryStatus() readFoundryStatus()
}, 2000) }, 2000)
loadTable()
loadSelectedTable(+route.params.id!) loadSelectedTable(+route.params.id!)
axios.get('/api/auth/user').then((resp) => (currentUser.value = resp.data))
hostname.value = location.host hostname.value = location.host
}) })
@@ -162,64 +149,34 @@ onUnmounted(() => {
clearSelectedTable() clearSelectedTable()
}) })
function readTable() {
axios.get(`/api/tables/${route.params.id}`).then((resp) => {
table.table_name = resp.data.table_name
table.table_link = resp.data.table_link
table.active = resp.data.active
})
}
function readFoundryStatus() {
if (activeTable.value) {
axios.get(`http://${activeTable.value.table_link}.${hostname.value}/api/status`).then((resp) => {
if (resp.status == 200) {
foundryStatus.running = resp.data.version
foundryStatus.active = resp.data.active
foundryStatus.world = resp.data.world
foundryStatus.users = resp.data.users
} else {
foundryStatus.running = false
foundryStatus.active = false
foundryStatus.world = 'Not Loaded'
foundryStatus.users = 0
}
})
}
}
watch(activeTable, () => { watch(activeTable, () => {
forceReset.value++ forceReset.value++
}) })
async function readFoundryStatus() {
if (activeTable.value) {
foundryStatus.value = (await getFoundryStatus(activeTable.value)) || {
running: false,
active: false,
world: 'Potato',
users: 0,
}
}
}
function protectedDelete() { function protectedDelete() {
if (activeTable.value) { if (activeTable.value) {
confirm.require({ confirm.require({
header: `Delete ${table.table_name}?`, header: `Delete ${activeTable.value.table_name}?`,
message: "This will delete the table and all of it's data", message: "This will delete the table and all of it's data",
accept: () => { accept: () => {
deleteTable(activeTable.value!) deleteTable(activeTable.value)
router.push('/') router.push('/')
}, },
}) })
} }
} }
function loadTable() {
axios
.get(`/api/tables/${route.params.id}`)
.then((resp) => {
table.table_name = resp.data.table_name
table.table_link = resp.data.table_link
table.active = resp.data.active
return axios.get(`/${table.table_link}/api/status`)
})
.then((resp) => {
foundryStatus.active = resp.data.active
foundryStatus.world = resp.data.world
foundryStatus.users = resp.data.users
})
}
function save(form: any) { function save(form: any) {
if (activeTable.value) { if (activeTable.value) {
updateTable(activeTable.value.id, { updateTable(activeTable.value.id, {
@@ -228,20 +185,20 @@ function save(form: any) {
table_link: form.values.table_link, table_link: form.values.table_link,
active: activeTable.value.active, active: activeTable.value.active,
version: form.values.version, version: form.values.version,
user_id: activeTable.value.user_id user_id: activeTable.value.user_id,
}) })
} }
} }
function isTableLoading() { function isTableLoading() {
return table.active && !foundryStatus.running return activeTable.value !== null && activeTable.value.active && !foundryStatus.value.running
} }
function isTableInactive() { function isTableInactive() {
return !table.active return activeTable.value !== null && !activeTable.value.active
} }
function isTableReady() { function isTableReady() {
return table.active && foundryStatus.running return activeTable.value !== null && activeTable.value.active && foundryStatus.value.running
} }
</script> </script>

View File

@@ -8,7 +8,10 @@
<Column field="table_link" header="Table Link"> <Column field="table_link" header="Table Link">
<template #body="slotProps"> <template #body="slotProps">
<a v-if="slotProps.data.active" :href="'http://' + hostname + '/' + slotProps.data.table_link""> <a
v-if="slotProps.data.active"
:href="'http://' + hostname + '/' + slotProps.data.table_link"
>
http://{{ hostname }}/{{ slotProps.data.table_link }} http://{{ hostname }}/{{ slotProps.data.table_link }}
</a> </a>
<div v-if="!slotProps.data.active"> <div v-if="!slotProps.data.active">
@@ -19,7 +22,11 @@
<Column header="Actions" v-if="showClose"> <Column header="Actions" v-if="showClose">
<template #body="slotProps"> <template #body="slotProps">
<Button label="Close" @click="stopTable(slotProps.data)" :disabled="!isTableOwner(slotProps.data)" /> <Button
label="Close"
@click="stopTable(slotProps.data)"
:disabled="!isTableOwner(slotProps.data)"
/>
</template> </template>
</Column> </Column>
@@ -27,8 +34,12 @@
<template #body="slotProps"> <template #body="slotProps">
<div class="flex flex-row"> <div class="flex flex-row">
<span class="flex"></span> <span class="flex"></span>
<SplitButton label="Start" @click="startTable(slotProps.data)" :model="buildButtonModel(slotProps.data)" <SplitButton
:disabled="!isTableOwner(slotProps.data)" /> label="Start"
@click="startTable(slotProps.data)"
:model="buildButtonModel(slotProps.data)"
:disabled="!isTableOwner(slotProps.data)"
/>
</div> </div>
</template> </template>
</Column> </Column>
@@ -49,12 +60,7 @@ import ConfirmDialog from 'primevue/confirmdialog'
import { useConfirm } from 'primevue/useconfirm' import { useConfirm } from 'primevue/useconfirm'
import { useUserData } from './user' import { useUserData } from './user'
import { import { startTable, hardStartTable, stopTable, deleteTable } from './game_tables'
startTable,
hardStartTable,
stopTable,
deleteTable,
} from './game_tables'
import type { GameTable } from './game_tables' import type { GameTable } from './game_tables'
@@ -105,6 +111,6 @@ function buildButtonModel(table: any) {
} }
function isTableOwner(gameTable: GameTable): boolean { function isTableOwner(gameTable: GameTable): boolean {
return user.value.is_admin || gameTable.user_id == user.value.id return user.value !== null && (user.value.is_admin || gameTable.user_id == user.value.id)
} }
</script> </script>

View File

@@ -1,13 +1,29 @@
<script setup lang="ts"> <template>
import { useActiveTables, useAllTables } from './game_tables' <Card class="ActiveTables">
<template #title>
<h2>Active Tables</h2>
</template>
import TableList from './TableList.vue' <template #content>
import Button from 'primevue/button' <TableList :show-close="true" :game-tables="activeTables" />
import Card from 'primevue/card' </template>
</Card>
const allTables = useAllTables() <Card class="AllTables">
const activeTables = useActiveTables() <template #title>
</script> <h2>All Tables</h2>
</template>
<template #content>
<TableList :show-full-actions="true" :game-tables="allTables" />
<div class="button-box flex justify-content-end">
<router-link to="/new">
<Button :disabled="userData == null" label="New Table" />
</router-link>
</div>
</template>
</Card>
</template>
<style> <style>
@import 'primeflex/primeflex.css'; @import 'primeflex/primeflex.css';
@@ -42,29 +58,15 @@ const activeTables = useActiveTables()
} }
</style> </style>
<template> <script setup lang="ts">
<Card class="ActiveTables"> import { useActiveTables, useAllTables } from './game_tables'
<template #title> import { useUserData } from './user'
<h2>Active Tables</h2>
</template>
<template #content> import TableList from './TableList.vue'
<TableList :show-close="true" :game-tables="activeTables" /> import Button from 'primevue/button'
</template> import Card from 'primevue/card'
</Card>
<Card class="AllTables"> const allTables = useAllTables()
<template #title> const activeTables = useActiveTables()
<h2>All Tables</h2> const userData = useUserData()
</template> </script>
<template #content>
<TableList :show-full-actions="true" :game-tables="allTables" />
<div class="button-box flex justify-content-end">
<router-link to="/new">
<Button label="New Table" />
</router-link>
</div>
</template>
</Card>
</template>

View File

@@ -11,6 +11,13 @@ export interface GameTable {
user_id: number user_id: number
} }
export interface FoundryStatus {
running: boolean
active: boolean
world: string
users: number
}
let $selectedTable: Ref<GameTable | null> | undefined let $selectedTable: Ref<GameTable | null> | undefined
let $activeTables: Ref<Array<GameTable>> | undefined let $activeTables: Ref<Array<GameTable>> | undefined
let $allTables: Ref<Array<GameTable>> | undefined let $allTables: Ref<Array<GameTable>> | undefined
@@ -28,8 +35,7 @@ export function useAllTables(): Ref<Array<GameTable>> {
} }
export function useSelectedTable(): Ref<GameTable | null> { export function useSelectedTable(): Ref<GameTable | null> {
if (!$selectedTable) if (!$selectedTable) $selectedTable = ref(null)
$selectedTable = ref(null)
return $selectedTable return $selectedTable
} }
@@ -43,31 +49,35 @@ export function loadAllTables(): void {
} }
export function loadSelectedTable(tableId: number = 0): void { export function loadSelectedTable(tableId: number = 0): void {
if ($selectedTable && $selectedTable.value) { if ($selectedTable && $selectedTable.value && tableId === 0) {
let id = tableId || $selectedTable.value.id axios
axios.get(`/api/tables/${id}`).then((resp) => ($selectedTable!.value = resp.data)) .get(`/api/tables/${$selectedTable.value.id}`)
.then((resp) => ($selectedTable!.value = resp.data))
} else if (tableId !== 0) {
axios.get(`/api/tables/${tableId}`).then((resp) => ($selectedTable!.value = resp.data))
} }
} }
export function clearSelectedTable(): void { export function clearSelectedTable(): void {
if ($selectedTable) { if ($selectedTable) {
$selectedTable.value = { $selectedTable.value = null
id: 0,
table_name: 'None',
table_link: 'None',
active: false,
version: 0,
user_id: 0,
}
} }
} }
export async function startTable(gameTable: GameTable): Promise<void> { export async function startTable(gameTable: GameTable | null): Promise<void> {
if (gameTable === null) {
return
}
await axios await axios
.post(`/api/tables/${gameTable.id}:start`, { hard: 'False' }) .post(`/api/tables/${gameTable.id}:start`, { hard: 'False' })
.then(() => loadAllTables()) .then(() => loadAllTables())
.then(() => loadActiveTables()) .then(() => loadActiveTables())
.then(() => loadSelectedTable()) .then(() => loadSelectedTable())
.catch(e => {
console.log(e)
console.log(e.response)
})
for (let retries = 0; retries < 10; retries++) { for (let retries = 0; retries < 10; retries++) {
try { try {
@@ -75,10 +85,9 @@ export async function startTable(gameTable: GameTable): Promise<void> {
console.log('loaded') console.log('loaded')
return return
} catch { } catch {
await new Promise(f => setTimeout(f, 1000)) await new Promise((f) => setTimeout(f, 1000))
} }
} }
} }
export function hardStartTable(gameTable: GameTable): void { export function hardStartTable(gameTable: GameTable): void {
@@ -114,10 +123,26 @@ export function updateTable(tableId: number, updatedTable: GameTable): void {
.then(() => loadSelectedTable()) .then(() => loadSelectedTable())
} }
export function deleteTable(gameTable: GameTable): void { export function deleteTable(gameTable: GameTable | null): void {
if (gameTable !== null) {
axios axios
.delete(`/api/tables/${gameTable.id}`) .delete(`/api/tables/${gameTable.id}`)
.then(() => loadAllTables()) .then(() => loadAllTables())
.then(() => loadActiveTables()) .then(() => loadActiveTables())
.then(() => loadSelectedTable()) .then(() => loadSelectedTable())
} }
}
export async function getFoundryStatus(gameTable: GameTable): Promise<FoundryStatus | null> {
return axios.get(`http://${location.host}/${gameTable.table_link}/api/status`).then((resp) => {
if (typeof resp.data !== 'string') {
return {
running: resp.data.version,
active: resp.data.active,
world: resp.data.world,
users: resp.data.users,
}
}
return null
})
}

View File

@@ -9,17 +9,21 @@ export interface User {
authenticated: boolean authenticated: boolean
} }
const $current_user = ref({ id: 0, username: 'username', is_admin: false, authenticated: false }) const $current_user: Ref<User | null> = ref(null)
function loadCurrentUser(): void { function loadCurrentUser(): void {
axios.get('/api/auth/user').then((resp) => { axios.get('/api/auth/user').then((resp) => {
$current_user.value = resp.data $current_user.value = resp.data
}).catch(() => {
$current_user.value = null
}) })
} }
export function useUserData(): Ref<User> { export function useUserData(): Ref<User | null> {
onMounted(() => { onMounted(() => {
if ($current_user.value === null) {
loadCurrentUser() loadCurrentUser()
}
}) })
return readonly($current_user) return readonly($current_user)
@@ -32,7 +36,7 @@ export function login(username: string, password: string): void {
} }
export function logout(): void { export function logout(): void {
if ($current_user.value.authenticated) { if ($current_user.value && $current_user.value.authenticated) {
axios.post('/api/auth/logout').then((resp) => { axios.post('/api/auth/logout').then((resp) => {
$current_user.value = resp.data $current_user.value = resp.data
}) })
@@ -40,6 +44,9 @@ export function logout(): void {
} }
export function resetPassword(password: string): void { export function resetPassword(password: string): void {
if ($current_user.value === null) {
return
}
axios.post(`/api/auth/user/${$current_user.value.id}`, { axios.post(`/api/auth/user/${$current_user.value.id}`, {
username: $current_user.value.username, username: $current_user.value.username,
password, password,