Skip to content

Commit a2e91a6

Browse files
authored
Add session tagging feature (#815)
* Add session tag model, schema, migration and CRUD endpoints * Add front end configuration of session tags
1 parent 4d72aec commit a2e91a6

File tree

16 files changed

+2069
-89
lines changed

16 files changed

+2069
-89
lines changed

client/src/store/modules/show.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export default {
2020
micAllocations: [],
2121
noLeaderToast: null,
2222
scriptModes: [],
23+
sessionTags: [],
2324
},
2425
mutations: {
2526
SET_CAST_LIST(state, castList) {
@@ -45,6 +46,7 @@ export default {
4546
state.characterList = [];
4647
state.actList = [];
4748
state.sceneList = [];
49+
state.sessionTags = [];
4850
},
4951
SET_SESSIONS_LIST(state, sessions) {
5052
state.sessions = sessions;
@@ -70,6 +72,9 @@ export default {
7072
UPDATE_SCRIPT_MODES(state, modes) {
7173
state.scriptModes = modes;
7274
},
75+
SET_SESSION_TAGS(state, tags) {
76+
state.sessionTags = tags;
77+
},
7378
},
7479
actions: {
7580
async GET_CAST_LIST(context) {
@@ -572,6 +577,83 @@ export default {
572577
log.error('Unable to fetch script modes');
573578
}
574579
},
580+
async GET_SESSION_TAGS(context) {
581+
const response = await fetch(`${makeURL('/api/v1/show/session/tags')}`);
582+
if (response.ok) {
583+
const data = await response.json();
584+
context.commit('SET_SESSION_TAGS', data.tags);
585+
} else {
586+
log.error('Unable to get session tags');
587+
}
588+
},
589+
async ADD_SESSION_TAG(context, tag) {
590+
const response = await fetch(`${makeURL('/api/v1/show/session/tags')}`, {
591+
method: 'POST',
592+
headers: {
593+
'Content-Type': 'application/json',
594+
},
595+
body: JSON.stringify(tag),
596+
});
597+
if (response.ok) {
598+
context.dispatch('GET_SESSION_TAGS');
599+
Vue.$toast.success('Added new session tag!');
600+
} else {
601+
log.error('Unable to add session tag');
602+
Vue.$toast.error('Unable to add session tag');
603+
}
604+
},
605+
async UPDATE_SESSION_TAG(context, tag) {
606+
const response = await fetch(`${makeURL('/api/v1/show/session/tags')}`, {
607+
method: 'PATCH',
608+
headers: {
609+
'Content-Type': 'application/json',
610+
},
611+
body: JSON.stringify(tag),
612+
});
613+
if (response.ok) {
614+
context.dispatch('GET_SESSION_TAGS');
615+
Vue.$toast.success('Updated session tag!');
616+
} else {
617+
log.error('Unable to edit session tag');
618+
Vue.$toast.error('Unable to edit session tag');
619+
}
620+
},
621+
async DELETE_SESSION_TAG(context, tagId) {
622+
const response = await fetch(`${makeURL('/api/v1/show/session/tags')}?id=${tagId}`, {
623+
method: 'DELETE',
624+
headers: {
625+
'Content-Type': 'application/json',
626+
},
627+
});
628+
if (response.ok) {
629+
context.dispatch('GET_SESSION_TAGS');
630+
Vue.$toast.success('Deleted session tag!');
631+
} else {
632+
log.error('Unable to delete session tag');
633+
Vue.$toast.error('Unable to delete session tag');
634+
}
635+
},
636+
async UPDATE_SESSION_TAGS(context, { sessionId, tagIds }) {
637+
const response = await fetch(`${makeURL('/api/v1/show/sessions/assign-tags')}`, {
638+
method: 'PATCH',
639+
headers: {
640+
'Content-Type': 'application/json',
641+
},
642+
body: JSON.stringify({
643+
session_id: sessionId,
644+
tag_ids: tagIds,
645+
}),
646+
});
647+
if (response.ok) {
648+
await context.dispatch('GET_SHOW_SESSION_DATA');
649+
Vue.$toast.success('Updated session tags!');
650+
} else {
651+
const errorData = await response.json().catch(() => ({}));
652+
log.error('Unable to update session tags:', errorData);
653+
Vue.$toast.error(errorData.message || 'Unable to update session tags');
654+
throw new Error('Failed to update session tags');
655+
}
656+
},
575657
},
576658
getters: {
577659
CAST_LIST(state) {
@@ -755,5 +837,21 @@ export default {
755837
SCRIPT_MODES(state) {
756838
return state.scriptModes;
757839
},
840+
SESSION_TAGS(state) {
841+
return state.sessionTags;
842+
},
843+
SESSION_TAGS_DICT(state) {
844+
return Object.fromEntries(state.sessionTags.map((tag) => [tag.id, tag]));
845+
},
846+
SESSION_TAG_BY_ID: (state, getters) => (tagId) => {
847+
if (tagId == null) {
848+
return null;
849+
}
850+
const tagStr = tagId.toString();
851+
if (Object.keys(getters.SESSION_TAGS_DICT).includes(tagStr)) {
852+
return getters.SESSION_TAGS_DICT[tagStr];
853+
}
854+
return null;
855+
},
758856
},
759857
};

client/src/views/show/config/ConfigSessions.vue

Lines changed: 29 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -4,111 +4,53 @@
44
fluid
55
>
66
<b-row>
7-
<b-col>
8-
<h5>Sessions List</h5>
9-
<b-table
10-
id="acts-table"
11-
:items="SHOW_SESSIONS_LIST"
12-
:fields="sessionFields"
13-
show-empty
14-
>
15-
<template #cell(run_time)="data">
16-
<p v-if="data.item.end_date_time">
17-
{{ runTimeCalc(data.item.start_date_time, data.item.end_date_time) }}
18-
</p>
19-
</template>
20-
</b-table>
21-
</b-col>
22-
</b-row>
23-
<b-row>
24-
<b-col>
25-
<b-button-group v-if="IS_SHOW_EXECUTOR">
26-
<b-button
27-
variant="success"
28-
:disabled="CURRENT_SHOW_SESSION !== null || startingSession"
29-
@click.stop="startSession"
30-
>
31-
Start Session
32-
</b-button>
33-
<b-button
34-
variant="danger"
35-
:disabled="CURRENT_SHOW_SESSION === null || stoppingSession"
36-
@click.stop="stopSession"
7+
<b-col v-if="loaded">
8+
<b-tabs content-class="mt-3">
9+
<b-tab
10+
title="Sessions"
11+
active
3712
>
38-
Stop Session
39-
</b-button>
40-
</b-button-group>
13+
<session-list />
14+
</b-tab>
15+
<b-tab title="Tags">
16+
<session-tag-list />
17+
</b-tab>
18+
</b-tabs>
19+
</b-col>
20+
<b-col v-else>
21+
<div
22+
class="text-center center-spinner"
23+
>
24+
<b-spinner
25+
style="width: 10rem; height: 10rem;"
26+
variant="info"
27+
/>
28+
</div>
4129
</b-col>
4230
</b-row>
4331
</b-container>
4432
</template>
4533

4634
<script>
47-
import { mapGetters, mapActions } from 'vuex';
48-
import log from 'loglevel';
49-
50-
import { makeURL, msToTimerString } from '@/js/utils';
35+
import { mapActions } from 'vuex';
36+
import SessionList from '@/vue_components/show/config/sessions/SessionList.vue';
37+
import SessionTagList from '@/vue_components/show/config/sessions/SessionTagList.vue';
5138
5239
export default {
5340
name: 'ConfigSessions',
41+
components: { SessionTagList, SessionList },
5442
data() {
5543
return {
56-
sessionFields: [
57-
{ key: 'start_date_time', label: 'Start Date' },
58-
{ key: 'end_date_time', label: 'End Date' },
59-
{ key: 'run_time', label: 'Runtime' },
60-
],
61-
startingSession: false,
62-
stoppingSession: false,
44+
loaded: false,
6345
};
6446
},
65-
computed: {
66-
...mapGetters(['SHOW_SESSIONS_LIST', 'CURRENT_SHOW_SESSION', 'INTERNAL_UUID', 'IS_SHOW_EXECUTOR']),
67-
},
6847
async mounted() {
6948
await this.GET_SHOW_SESSION_DATA();
49+
await this.GET_SESSION_TAGS();
50+
this.loaded = true;
7051
},
7152
methods: {
72-
async startSession() {
73-
if (this.INTERNAL_UUID == null) {
74-
this.$toast.error('Unable to start new show session');
75-
return;
76-
}
77-
this.startingSession = true;
78-
const response = await fetch(`${makeURL('/api/v1/show/sessions/start')}`, {
79-
method: 'POST',
80-
body: JSON.stringify({
81-
session_id: this.INTERNAL_UUID,
82-
}),
83-
});
84-
if (response.ok) {
85-
this.$toast.success('Started new show session');
86-
} else {
87-
log.error('Unable to start new show session');
88-
this.$toast.error('Unable to start new show session');
89-
}
90-
this.startingSession = false;
91-
},
92-
async stopSession() {
93-
this.stoppingSession = true;
94-
const response = await fetch(`${makeURL('/api/v1/show/sessions/stop')}`, {
95-
method: 'POST',
96-
});
97-
if (response.ok) {
98-
this.$toast.success('Stopped show session');
99-
} else {
100-
log.error('Unable to stop show session');
101-
this.$toast.error('Unable to stop show session');
102-
}
103-
this.stoppingSession = false;
104-
},
105-
runTimeCalc(start, end) {
106-
const startDate = Date.parse(start);
107-
const endDate = Date.parse(end);
108-
const diff = endDate - startDate;
109-
return msToTimerString(diff);
110-
},
111-
...mapActions(['GET_SHOW_SESSION_DATA']),
53+
...mapActions(['GET_SHOW_SESSION_DATA', 'GET_SESSION_TAGS']),
11254
},
11355
};
11456
</script>

0 commit comments

Comments
 (0)