Skip to content

Commit b7dfe3a

Browse files
authored
Merge pull request #1 from coreyg142/tempGraveyard
2 parents 0975c7f + ebaf653 commit b7dfe3a

File tree

11 files changed

+247
-36
lines changed

11 files changed

+247
-36
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<template>
2+
<div class="queuebox">
3+
<h2>Murdered Pokemons</h2>
4+
<div class="queue">
5+
<TransitionGroup name="list" tag="ol" reversed>
6+
<li v-for="(key, val) in queue" :key="key" class="list-item">
7+
<QueueItemComponent
8+
:name="val"
9+
:showModTools="loggedIn"
10+
:buttonsToShow="['del']"
11+
/>
12+
</li>
13+
</TransitionGroup>
14+
<Transition name="emptyMsg"
15+
><p v-if="Object.keys(queue).length === 0" class="empty">
16+
The graveyard is empty.
17+
</p>
18+
</Transition>
19+
</div>
20+
</div>
21+
</template>
22+
23+
<script lang="ts">
24+
import { defineComponent } from "vue";
25+
import { state } from "@/socket";
26+
import store from "@/store";
27+
import QueueItemComponent from "./QueueItemComponent.vue";
28+
29+
export default defineComponent({
30+
name: "GraveComponent",
31+
32+
components: {
33+
QueueItemComponent,
34+
},
35+
computed: {
36+
queue() {
37+
return state.graveyard;
38+
},
39+
loggedIn() {
40+
return store.state.loggedIn;
41+
},
42+
},
43+
});
44+
</script>
45+
46+
<style scoped>
47+
.queue {
48+
text-align: left;
49+
list-style: decimal;
50+
position: relative;
51+
width: fit-content;
52+
max-width: 60vw;
53+
overflow-wrap: break-word;
54+
margin: 0 auto;
55+
}
56+
57+
.list-item {
58+
text-align: left;
59+
font-size: 1.5em;
60+
padding: 0.5em;
61+
transition: all 0.5s ease;
62+
}
63+
64+
.list-move, /* apply transition to moving elements */
65+
.list-enter-active,
66+
.list-leave-active {
67+
transition: all 0.5s ease;
68+
}
69+
70+
.list-enter-from,
71+
.list-leave-to {
72+
opacity: 0;
73+
transform: translateX(-30px);
74+
}
75+
76+
/* ensure leaving items are taken out of layout flow so that moving
77+
animations can be calculated correctly. */
78+
.list-leave-active {
79+
position: absolute;
80+
opacity: 0;
81+
}
82+
83+
.emptyMsg-enter-active,
84+
.emptyMsg-leave-active {
85+
transition: opacity 0.5s ease;
86+
}
87+
88+
.emptyMsg-enter-from,
89+
.emptyMsg-leave-to {
90+
opacity: 0;
91+
}
92+
93+
.empty {
94+
color: gray;
95+
font-style: italic;
96+
text-align: center;
97+
margin-top: 1em;
98+
}
99+
</style>

viewer-queue-frontend/src/components/PoppedComponent.vue

+8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
:name="item"
99
:showModTools="loggedIn"
1010
:buttonsToShow="['del']"
11+
:killed="isDeadInCurrentRun(item)"
1112
/>
1213
</li>
1314
</TransitionGroup>
@@ -38,6 +39,13 @@ export default defineComponent({
3839
return store.state.loggedIn;
3940
},
4041
},
42+
methods: {
43+
isDeadInCurrentRun(name: string) {
44+
return (
45+
Object.keys(state.graveyard).includes(name) && state.graveyard[name]
46+
);
47+
},
48+
},
4149
});
4250
</script>
4351

viewer-queue-frontend/src/components/QueueItemComponent.vue

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div style="display: inline-block">
3-
<span class="text">{{ name }}</span>
3+
<span class="text" :class="killedClass">{{ name }}</span>
44
<!-- <font-awesome-icon v-if="showModTools" icon="fa-solid fa-user-secret" /> -->
55
<span v-if="showModTools" class="modButton">
66
<font-awesome-icon
@@ -27,7 +27,7 @@ import axios from "axios";
2727
export default defineComponent({
2828
name: "QueueItemComponent",
2929
inject: ["apiUrl"],
30-
props: ["name", "showModTools", "buttonsToShow"],
30+
props: ["name", "showModTools", "buttonsToShow", "killed"],
3131
3232
computed: {
3333
loggedIn() {
@@ -39,6 +39,9 @@ export default defineComponent({
3939
showDel() {
4040
return this.buttonsToShow.includes("del");
4141
},
42+
killedClass() {
43+
return this.killed ? "killed" : "";
44+
},
4245
},
4346
methods: {
4447
async popName() {
@@ -81,6 +84,10 @@ export default defineComponent({
8184
margin-left: 0.1em;
8285
}
8386
87+
.killed {
88+
text-decoration: line-through;
89+
}
90+
8491
.green {
8592
color: #00ff00;
8693
}

viewer-queue-frontend/src/socket.ts

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const state = reactive({
77
connected: false,
88
queuedNames: [] as string[],
99
poppedNames: [] as string[],
10+
graveyard: {} as { [key: string]: boolean },
1011
});
1112

1213
export const socket = io(apiUrl);
@@ -19,9 +20,14 @@ socket.on("name-popped", (...args) => {
1920
state.queuedNames = state.queuedNames.filter((name) => name !== args[0]);
2021
});
2122

23+
socket.on("name-killed", (...args) => {
24+
state.graveyard[args[0]] = true;
25+
});
26+
2227
socket.on("refresh-lists", (...args) => {
2328
state.queuedNames = args[0];
2429
state.poppedNames = args[1];
30+
state.graveyard = args[2];
2531
});
2632

2733
socket.on("connect", async () => {
@@ -30,6 +36,7 @@ socket.on("connect", async () => {
3036
const response = await axios.get(apiUrl + "/queue");
3137
state.queuedNames = response.data.lists.queued;
3238
state.poppedNames = response.data.lists.popped;
39+
state.graveyard = response.data.lists.graveyard;
3340

3441
const loggedIn = storeState.state.loggedIn;
3542
if (loggedIn) {

viewer-queue-frontend/src/store/index.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const store = createStore({
55
loggedIn: false,
66
accessKey: "",
77
logInTime: -1,
8-
queuedOrPrev: true,
8+
activeList: 0,
99
},
1010
getters: {},
1111
mutations: {
@@ -18,8 +18,8 @@ const store = createStore({
1818
setLogInTime(state, logInTime: number) {
1919
state.logInTime = logInTime;
2020
},
21-
setQueuedOrPrev(state, queuedOrPrev: boolean) {
22-
state.queuedOrPrev = queuedOrPrev;
21+
setActiveList(state, activeList: number) {
22+
state.activeList = activeList;
2323
},
2424
},
2525
actions: {
@@ -34,8 +34,8 @@ const store = createStore({
3434
commit("setLoggedIn", false);
3535
commit("setLogInTime", -1);
3636
},
37-
setQueuedOrPrev({ commit }, queuedOrPrev: boolean) {
38-
commit("setQueuedOrPrev", queuedOrPrev);
37+
setActiveList({ commit }, activeList: number) {
38+
commit("setActiveList", activeList);
3939
},
4040
},
4141
modules: {},

viewer-queue-frontend/src/views/QueueView.vue

+45-21
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
role="button"
2424
tabindex="0"
2525
class="queueBtn btn"
26-
v-on:click="toggleQueue"
27-
v-on:keypress.enter="toggleQueue"
28-
:class="{ btnActive: queuedOrPrev }"
26+
v-on:click="setActiveList(0)"
27+
v-on:keypress.enter="setActiveList(0)"
28+
:class="{ btnActive: activeList === 0 }"
2929
>
3030
<span>Pooled</span>
3131
</span>
@@ -34,12 +34,23 @@
3434
role="button"
3535
tabindex="0"
3636
class="btn"
37-
v-on:click="togglePrev"
38-
v-on:keypress.enter="togglePrev"
39-
:class="{ btnActive: !queuedOrPrev }"
37+
v-on:click="setActiveList(1)"
38+
v-on:keypress.enter="setActiveList(1)"
39+
:class="{ btnActive: activeList === 1 }"
4040
>
4141
<span>Current run</span>
4242
</span>
43+
<!-- <span> | </span>
44+
<span
45+
role="button"
46+
tabindex="0"
47+
class="btn"
48+
v-on:click="setActiveList(2)"
49+
v-on:keypress.enter="setActiveList(2)"
50+
:class="{ btnActive: activeList === 2 }"
51+
>
52+
<span>Graveyard</span>
53+
</span> -->
4354
<div v-if="loggedIn">
4455
<br />
4556
<span
@@ -67,6 +78,7 @@ import { mapActions } from "vuex";
6778
import QueueComponent from "@/components/QueueComponent.vue";
6879
import PoppedComponent from "@/components/PoppedComponent.vue";
6980
import QueueItemComponent from "@/components/QueueItemComponent.vue";
81+
import GraveComponent from "@/components/GraveComponent.vue";
7082
import AddNameModal from "@/components/AddNameModal.vue";
7183
import store from "@/store";
7284
import { state as socketState } from "@/socket";
@@ -78,6 +90,7 @@ export default defineComponent({
7890
components: {
7991
QueueComponent,
8092
PoppedComponent,
93+
GraveComponent,
8194
QueueItemComponent,
8295
AddNameModal,
8396
},
@@ -98,15 +111,27 @@ export default defineComponent({
98111
return store.state.loggedIn;
99112
},
100113
dynamicComponent() {
101-
if (this.queuedOrPrev) return QueueComponent;
102-
return PoppedComponent;
114+
// if (this.activeList) return QueueComponent;
115+
// return PoppedComponent;
116+
switch (this.activeList) {
117+
case 0:
118+
return QueueComponent;
119+
case 1:
120+
return PoppedComponent;
121+
case 2:
122+
return GraveComponent;
123+
default:
124+
return QueueComponent;
125+
}
103126
},
104-
queuedOrPrev() {
105-
return store.state.queuedOrPrev;
127+
activeList() {
128+
return store.state.activeList;
106129
},
107130
listAnimationDirection() {
108-
if (store.state.queuedOrPrev) return "slideXR";
109-
return "slideXL";
131+
if (store.state.activeList === 0) return "slideXR";
132+
else if (store.state.activeList === 1) return "slideXL";
133+
// else if (store.state.activeList === 2) return "slideXL";
134+
else return "slideXR";
110135
},
111136
mostRecentNameMsg() {
112137
return socketState.poppedNames.length
@@ -125,13 +150,7 @@ export default defineComponent({
125150
},
126151
},
127152
methods: {
128-
...mapActions(["setQueuedOrPrev"]),
129-
toggleQueue() {
130-
this.setQueuedOrPrev(true);
131-
},
132-
togglePrev() {
133-
this.setQueuedOrPrev(false);
134-
},
153+
...mapActions(["setActiveList"]),
135154
closeModal() {
136155
this.showAddModal = false;
137156
},
@@ -187,7 +206,10 @@ export default defineComponent({
187206
.slideXL-leave-active,
188207
.slideY-move,
189208
.slideY-enter-active,
190-
.slideY-leave-active {
209+
.slideY-leave-active,
210+
.slideYImm-move,
211+
.slideYImm-enter-active,
212+
.slideYImm-leave-active {
191213
transition: all 0.6s ease;
192214
}
193215
@@ -202,12 +224,14 @@ export default defineComponent({
202224
}
203225
204226
.slideXR-leave-active,
205-
.slideXL-leave-active {
227+
.slideXL-leave-active,
228+
.slideYImm-leave-active {
206229
position: absolute;
207230
transition: none;
208231
opacity: 0;
209232
}
210233
234+
.slideYImm-enter-from,
211235
.slideY-enter-from {
212236
opacity: 0;
213237
transform: translateY(30px);

viewer-queue-webserver/src/routes/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export { default as authenticate } from "./authenticate.js";
88
export { default as verifyAuth } from "./verifyauth.js";
99
export { default as removeName } from "./remove.js";
1010
export { default as clearQueues } from "./clearQueues.js";
11+
export { default as killName } from "./kill.js";
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import dotenv from "dotenv";
2+
import { Request, Response } from "express";
3+
import { Server } from "socket.io";
4+
import { killName as kill } from "../utils/names.js";
5+
import AuthKeyManager from "../utils/authKeyManager.js";
6+
dotenv.config();
7+
8+
export default async function killName(req: Request, res: Response, io: Server) {
9+
const method = req.method;
10+
const key = method === "PATCH" ? req.headers?.api_auth : req.query?.key;
11+
const name = req.query?.name;
12+
const ip = req.headers?.["cf-connecting-ip"] || req.socket.remoteAddress;
13+
const verified =
14+
typeof key === "string" && typeof ip === "string" ? AuthKeyManager.verifyKey(key, ip) : { valid: false };
15+
16+
if ((method === "GET" && key === process.env.WRITE_KEY) || (method === "PATCH" && verified.valid)) {
17+
let result;
18+
if (name && typeof name === "string") {
19+
result = await kill(name);
20+
} else {
21+
res.status(400).json({ error: "No name provided" });
22+
return;
23+
}
24+
if (result.error) {
25+
res.status(400).json({ error: result.error });
26+
return;
27+
}
28+
res.status(200).json({ result: result.result, name: result.name });
29+
io.emit("name-killed", result.name);
30+
} else {
31+
res.status(401).json({ error: "Unauthorized" });
32+
return;
33+
}
34+
}

0 commit comments

Comments
 (0)