chg: [app] Performance improvements

This commit is contained in:
Sami Mokaddem 2024-07-02 09:23:08 +02:00
parent feb3db0dec
commit 0fe9d9183a
9 changed files with 891 additions and 835 deletions

778
dist/assets/index-BL0Loedz.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/index.html vendored
View file

@ -5,7 +5,7 @@
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title> <title>Vite App</title>
<script type="module" crossorigin src="/assets/index-D76yy8_K.js"></script> <script type="module" crossorigin src="/assets/index-BL0Loedz.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CvXX7jiP.css"> <link rel="stylesheet" crossorigin href="/assets/index-CvXX7jiP.css">
</head> </head>
<body> <body>

View file

@ -9,6 +9,7 @@ from urllib.parse import parse_qs
VERBOSE_MODE = False VERBOSE_MODE = False
NOTIFICATION_COUNT = 1
def set_verbose_mode(enabled: bool): def set_verbose_mode(enabled: bool):
@ -107,6 +108,9 @@ def is_api_request(data: dict) -> bool:
def get_notification_message(data: dict) -> dict: def get_notification_message(data: dict) -> dict:
global NOTIFICATION_COUNT
id = NOTIFICATION_COUNT
NOTIFICATION_COUNT += 1
user = db.USER_ID_TO_EMAIL_MAPPING.get(int(data['user_id']), '?') user = db.USER_ID_TO_EMAIL_MAPPING.get(int(data['user_id']), '?')
time = data['created'].split(' ')[1].split('.')[0] time = data['created'].split(' ')[1].split('.')[0]
url = data['url'] url = data['url']
@ -117,6 +121,7 @@ def get_notification_message(data: dict) -> dict:
http_method = 'DELETE' if (http_method == 'POST' or http_method == 'PUT') and action == 'delete' else http_method # small override for UI http_method = 'DELETE' if (http_method == 'POST' or http_method == 'PUT') and action == 'delete' else http_method # small override for UI
payload = get_request_post_body(data) payload = get_request_post_body(data)
return { return {
'id': id,
'user': user, 'user': user,
'time': time, 'time': time,
'url': url, 'url': url,

7
package-lock.json generated
View file

@ -13,6 +13,7 @@
"@fortawesome/free-regular-svg-icons": "^6.5.2", "@fortawesome/free-regular-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/vue-fontawesome": "^3.0.8", "@fortawesome/vue-fontawesome": "^3.0.8",
"lodash.throttle": "^4.1.1",
"vue": "^3.4.29" "vue": "^3.4.29"
}, },
"devDependencies": { "devDependencies": {
@ -2353,6 +2354,12 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true "dev": true
}, },
"node_modules/lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
"license": "MIT"
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "10.2.2", "version": "10.2.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",

View file

@ -16,6 +16,7 @@
"@fortawesome/free-regular-svg-icons": "^6.5.2", "@fortawesome/free-regular-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/vue-fontawesome": "^3.0.8", "@fortawesome/vue-fontawesome": "^3.0.8",
"lodash.throttle": "^4.1.1",
"vue": "^3.4.29" "vue": "^3.4.29"
}, },
"devDependencies": { "devDependencies": {

View file

@ -1,6 +1,6 @@
<script setup> <script setup>
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { exercises, selected_exercises, diagnostic, resetAllExerciseProgress, resetLiveLoggs, changeExerciseSelection, fetchDiagnostic } from "@/socket"; import { exercises, selected_exercises, diagnostic, resetAllExerciseProgress, resetLiveLogs, changeExerciseSelection, throttledGetDiangostic } from "@/socket";
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { faScrewdriverWrench, faTrash, faSuitcaseMedical, faGraduationCap, faBan } from '@fortawesome/free-solid-svg-icons' import { faScrewdriverWrench, faTrash, faSuitcaseMedical, faGraduationCap, faBan } from '@fortawesome/free-solid-svg-icons'
@ -17,7 +17,7 @@
function showTheModal() { function showTheModal() {
admin_modal.value.showModal() admin_modal.value.showModal()
fetchDiagnostic() throttledGetDiangostic()
} }
</script> </script>
@ -52,7 +52,7 @@
Reset All Exercises Reset All Exercises
</button> </button>
<button <button
@click="resetLiveLoggs()" @click="resetLiveLogs()"
class="h-10 min-h-10 px-2 py-1 font-semibold bg-amber-600 text-slate-200 hover:bg-amber-700 btn btn-sm" class="h-10 min-h-10 px-2 py-1 font-semibold bg-amber-600 text-slate-200 hover:bg-amber-700 btn btn-sm"
> >
<FontAwesomeIcon :icon="faBan" class=""></FontAwesomeIcon> <FontAwesomeIcon :icon="faBan" class=""></FontAwesomeIcon>

View file

@ -79,7 +79,7 @@
</td> </td>
</tr> </tr>
<template v-else> <template v-else>
<tr v-for="(notification, index) in notifications" :key="index"> <tr v-for="notification in notifications" :key="notification.id">
<td <td
class="border-b border-slate-100 dark:border-slate-700 text-slate-600 dark:text-slate-400 p-1 pl-2 w-12 whitespace-nowrap" class="border-b border-slate-100 dark:border-slate-700 text-slate-600 dark:text-slate-400 p-1 pl-2 w-12 whitespace-nowrap"
> >

View file

@ -1,5 +1,6 @@
import { reactive, computed } from "vue"; import { reactive, computed } from "vue";
import { io } from "socket.io-client"; import { io } from "socket.io-client";
import throttle from 'lodash.throttle'
// "undefined" means the URL will be computed from the `window.location` object // "undefined" means the URL will be computed from the `window.location` object
const URL = process.env.NODE_ENV === "production" ? undefined : "http://localhost:3000"; const URL = process.env.NODE_ENV === "production" ? undefined : "http://localhost:3000";
@ -18,7 +19,16 @@ const initial_state = {
const state = reactive({ ...initial_state }); const state = reactive({ ...initial_state });
const connectionState = reactive({ const connectionState = reactive({
connected: false connected: false
}) })
const socket = io(URL, {
autoConnect: true
});
/* Public */
/* ------ */
export const exercises = computed(() => state.exercises) export const exercises = computed(() => state.exercises)
export const selected_exercises = computed(() => state.selected_exercises) export const selected_exercises = computed(() => state.selected_exercises)
@ -36,25 +46,10 @@ export function resetState() {
} }
export function fullReload() { export function fullReload() {
socket.emit("get_exercises", (all_exercises) => { getExercises()
state.exercises = all_exercises getSelectedExercises()
}) getNotifications()
socket.emit("get_selected_exercises", (all_selected_exercises) => { getProgress()
state.selected_exercises = all_selected_exercises
})
socket.emit("get_notifications", (all_notifications) => {
state.notificationEvents = all_notifications
})
socket.emit("get_progress", (all_progress) => {
state.progresses = all_progress
})
}
export function fetchDiagnostic() {
state.diagnostic = {}
socket.emit("get_diagnostic", (diagnostic) => {
state.diagnostic = diagnostic
})
} }
export function setCompletedState(completed, user_id, exec_uuid, task_uuid) { export function setCompletedState(completed, user_id, exec_uuid, task_uuid) {
@ -63,28 +58,15 @@ export function setCompletedState(completed, user_id, exec_uuid, task_uuid) {
exercise_uuid: exec_uuid, exercise_uuid: exec_uuid,
task_uuid: task_uuid, task_uuid: task_uuid,
} }
const event_name = !completed ? "mark_task_completed": "mark_task_incomplete" sendCompletedState(completed, payload)
socket.emit(event_name, payload, () => {
socket.emit("get_progress", (all_progress) => {
state.progresses = all_progress
})
})
} }
export function resetAllExerciseProgress() { export function resetAllExerciseProgress() {
socket.emit("reset_all_exercise_progress", () => { sendResetAllExerciseProgress()
socket.emit("get_progress", (all_progress) => {
state.progresses = all_progress
})
})
} }
export function resetLiveLoggs() { export function resetLiveLogs() {
socket.emit("reset_notifications", () => { sendResetLiveLogs()
socket.emit("get_notifications", (all_notifications) => {
state.notificationEvents = all_notifications
})
})
} }
export function changeExerciseSelection(exec_uuid, state_enabled) { export function changeExerciseSelection(exec_uuid, state_enabled) {
@ -92,24 +74,89 @@ export function changeExerciseSelection(exec_uuid, state_enabled) {
exercise_uuid: exec_uuid, exercise_uuid: exec_uuid,
selected: state_enabled, selected: state_enabled,
} }
socket.emit("change_exercise_selection", payload, () => { sendChangeExerciseSelection(payload)
socket.emit("get_selected_exercises", (all_selected_exercises) => {
state.selected_exercises = all_selected_exercises
})
})
} }
export function toggleVerboseMode(enabled) { export function toggleVerboseMode(enabled) {
sendToggleVerboseMode(enabled)
}
export function throttledGetProgress() {
return throttle(getProgress, 200)
}
export function throttledGetDiangostic() {
return throttle(getDiangostic, 1000)
}
/* Private */
/* ------- */
function getExercises() {
socket.emit("get_exercises", (all_exercises) => {
state.exercises = all_exercises
})
}
function getSelectedExercises() {
socket.emit("get_selected_exercises", (all_selected_exercises) => {
state.selected_exercises = all_selected_exercises
})
}
function getNotifications() {
socket.emit("get_notifications", (all_notifications) => {
state.notificationEvents = all_notifications
})
}
function getProgress() {
socket.emit("get_progress", (all_progress) => {
state.progresses = all_progress
})
}
function getDiangostic() {
state.diagnostic = {}
socket.emit("get_diagnostic", (diagnostic) => {
state.diagnostic = diagnostic
})
}
function sendCompletedState(completed, payload) {
const event_name = !completed ? "mark_task_completed": "mark_task_incomplete"
socket.emit(event_name, payload, () => {
getProgress()
})
}
function sendResetAllExerciseProgress() {
socket.emit("reset_all_exercise_progress", () => {
getProgress()
})
}
function sendResetLiveLogs() {
socket.emit("reset_notifications", () => {
getNotifications()
})
}
function sendChangeExerciseSelection(payload) {
socket.emit("change_exercise_selection", payload, () => {
getSelectedExercises()
})
}
function sendToggleVerboseMode(enabled) {
const payload = { const payload = {
verbose: enabled verbose: enabled
} }
socket.emit("toggle_verbose_mode", payload, () => {}) socket.emit("toggle_verbose_mode", payload, () => {})
} }
/* Event listener */
const socket = io(URL, {
autoConnect: true
});
socket.on("connect", () => { socket.on("connect", () => {
connectionState.connected = true; connectionState.connected = true;
@ -128,15 +175,11 @@ socket.on("notification", (message) => {
}); });
socket.on("new_user", (new_user) => { socket.on("new_user", (new_user) => {
socket.emit("get_progress", (all_progress) => { throttledGetProgress()
state.progresses = all_progress
})
}); });
socket.on("refresh_score", (new_user) => { socket.on("refresh_score", (new_user) => {
socket.emit("get_progress", (all_progress) => { throttledGetProgress()
state.progresses = all_progress
})
}); });
function addLimited(target, message, maxCount) { function addLimited(target, message, maxCount) {