Servers console performance improvements (#3007)
* feat: init selecting paper+purpur on purchase flow Signed-off-by: Evan Song <theevansong@gmail.com> * feat: properly implement Paper/Purpur in Platform Signed-off-by: Evan Song <theevansong@gmail.com> * chore: correct wording Signed-off-by: Evan Song <theevansong@gmail.com> * feat: redo platform modal Signed-off-by: Evan Song <theevansong@gmail.com> * Switch to HCaptcha for Auth-related captchas (#2945) * Switch to HCaptcha for Auth-related captchas * run fmt * fix hcaptcha not loading * fix: more robust loader dropdown logic Signed-off-by: Evan Song <theevansong@gmail.com> * fix: handle "not yet supported" install err Signed-off-by: Evan Song <theevansong@gmail.com> * chore: fix icon kerfuffles Signed-off-by: Evan Song <theevansong@gmail.com> * chore: improve vanilla install modal title Signed-off-by: Evan Song <theevansong@gmail.com> * fix: spacing Signed-off-by: Evan Song <theevansong@gmail.com> * feat: usePyroConsole store instead of passing a prop to prevent bulk panel refreshing * chore: improve no loader state Signed-off-by: Evan Song <theevansong@gmail.com> * fix: type error Signed-off-by: Evan Song <theevansong@gmail.com> * chore: adjust mod version modal title Signed-off-by: Evan Song <theevansong@gmail.com> * chore: adjust modpack warning copy Signed-off-by: Evan Song <theevansong@gmail.com> * feat: vanilla empty state in content page Signed-off-by: Evan Song <theevansong@gmail.com> * chore: adjust copy Signed-off-by: Evan Song <theevansong@gmail.com> * chore: update icon Signed-off-by: Evan Song <theevansong@gmail.com> * fix: loader type Signed-off-by: Evan Song <theevansong@gmail.com> * fix: loader type Signed-off-by: Evan Song <theevansong@gmail.com> * feat: always show dropdown if possible Signed-off-by: Evan Song <theevansong@gmail.com> * chore: improve spacing Signed-off-by: Evan Song <theevansong@gmail.com> * chore: appear disabled Signed-off-by: Evan Song <theevansong@gmail.com> * h Signed-off-by: Evan Song <theevansong@gmail.com> * chore: if reinstalling, show it on the modal title Signed-off-by: Evan Song <theevansong@gmail.com> * feat: put it in the dropdown, they said Signed-off-by: Evan Song <theevansong@gmail.com> * chore: adjust style Signed-off-by: Evan Song <theevansong@gmail.com> * chore: sort paper-purpur versions desc Signed-off-by: Evan Song <theevansong@gmail.com> * fix: do not consider backup limit in reinstall prompt Signed-off-by: Evan Song <theevansong@gmail.com> * feat: backup locking, plugin support * fix: content type error Signed-off-by: Evan Song <theevansong@gmail.com> * fix: casing Signed-off-by: Evan Song <theevansong@gmail.com> * fix: plugins pt 2 * feat: backups, mrpack * fix: type errors come on Signed-off-by: Evan Song <theevansong@gmail.com> * fix: spacing Signed-off-by: Evan Song <theevansong@gmail.com> * fix: type maxing * chore: show copy button on allocation rows Signed-off-by: Evan Song <theevansong@gmail.com> * feat: suspend improvement --------- Signed-off-by: Evan Song <theevansong@gmail.com> Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com> Co-authored-by: Jai A <jaiagr+gpg@pm.me> Co-authored-by: TheWander02 <48934424+thewander02@users.noreply.github.com>
This commit is contained in:
parent
742c0edd9e
commit
6ec1dcf088
@ -136,15 +136,18 @@
|
||||
<script setup lang="ts">
|
||||
import { RightArrowIcon } from "@modrinth/assets";
|
||||
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from "vue";
|
||||
import { usePyroConsole } from "~/store/console.ts";
|
||||
|
||||
const { $cosmetics } = useNuxtApp();
|
||||
const cosmetics = $cosmetics;
|
||||
|
||||
const props = defineProps<{
|
||||
consoleOutput: string[];
|
||||
fullScreen: boolean;
|
||||
}>();
|
||||
|
||||
const pyroConsole = usePyroConsole();
|
||||
const consoleOutput = pyroConsole.output;
|
||||
|
||||
const scrollContainer = ref<HTMLElement | null>(null);
|
||||
const itemHeights = ref<number[]>([]);
|
||||
const averageItemHeight = ref(36);
|
||||
@ -170,7 +173,7 @@ const handleScrollEvent = () => {
|
||||
const totalHeight = computed(
|
||||
() =>
|
||||
itemHeights.value.reduce((sum, height) => sum + height, 0) ||
|
||||
props.consoleOutput.length * averageItemHeight.value,
|
||||
consoleOutput.value.length * averageItemHeight.value,
|
||||
);
|
||||
|
||||
watch(totalHeight, () => {
|
||||
@ -223,7 +226,7 @@ const visibleStartIndex = computed(() => {
|
||||
let index = 0;
|
||||
let offset = 0;
|
||||
while (
|
||||
index < props.consoleOutput.length &&
|
||||
index < consoleOutput.value.length &&
|
||||
offset < scrollTop.value - bufferSize * averageItemHeight.value
|
||||
) {
|
||||
offset += itemHeights.value[index] || averageItemHeight.value;
|
||||
@ -236,17 +239,17 @@ const visibleEndIndex = computed(() => {
|
||||
let index = visibleStartIndex.value;
|
||||
let offset = getItemOffset(index);
|
||||
while (
|
||||
index < props.consoleOutput.length &&
|
||||
index < consoleOutput.value.length &&
|
||||
offset < scrollTop.value + clientHeight.value + bufferSize * averageItemHeight.value
|
||||
) {
|
||||
offset += itemHeights.value[index] || averageItemHeight.value;
|
||||
index++;
|
||||
}
|
||||
return Math.min(props.consoleOutput.length - 1, index);
|
||||
return Math.min(consoleOutput.value.length - 1, index);
|
||||
});
|
||||
|
||||
const visibleItems = computed(() =>
|
||||
props.consoleOutput.slice(visibleStartIndex.value, visibleEndIndex.value + 1),
|
||||
consoleOutput.value.slice(visibleStartIndex.value, visibleEndIndex.value + 1),
|
||||
);
|
||||
|
||||
const offsetY = computed(() => getItemOffset(visibleStartIndex.value));
|
||||
@ -280,7 +283,7 @@ const updateItemHeights = async () => {
|
||||
const index = visibleStartIndex.value + idx;
|
||||
const height = el.getBoundingClientRect().height;
|
||||
itemHeights.value[index] = height;
|
||||
const content = props.consoleOutput[index];
|
||||
const content = consoleOutput.value[index];
|
||||
if (content) {
|
||||
cachedHeights.value.set(content, height);
|
||||
}
|
||||
@ -457,7 +460,7 @@ const initializeTerminal = async () => {
|
||||
|
||||
updateClientHeight();
|
||||
|
||||
const initialHeights = props.consoleOutput.map(
|
||||
const initialHeights = consoleOutput.value.map(
|
||||
(content) => cachedHeights.value.get(content) || averageItemHeight.value,
|
||||
);
|
||||
itemHeights.value = initialHeights;
|
||||
@ -487,7 +490,7 @@ onUnmounted(() => {
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.consoleOutput,
|
||||
() => consoleOutput.value,
|
||||
async (newOutput) => {
|
||||
const newItemsCount = newOutput.length - itemHeights.value.length;
|
||||
|
||||
|
@ -276,7 +276,6 @@
|
||||
:stats="stats"
|
||||
:server-power-state="serverPowerState"
|
||||
:power-state-details="powerStateDetails"
|
||||
:console-output="throttledConsoleOutput"
|
||||
:socket="socket"
|
||||
:server="server"
|
||||
@reinstall="onReinstall"
|
||||
@ -302,9 +301,9 @@ import {
|
||||
} from "@modrinth/assets";
|
||||
import DOMPurify from "dompurify";
|
||||
import { ButtonStyled } from "@modrinth/ui";
|
||||
import { refThrottled } from "@vueuse/core";
|
||||
import { Intercom, shutdown } from "@intercom/messenger-js-sdk";
|
||||
import type { ServerState, Stats, WSEvent, WSInstallationResultEvent } from "~/types/servers";
|
||||
import { usePyroConsole } from "~/store/console.ts";
|
||||
|
||||
const socket = ref<WebSocket | null>(null);
|
||||
const isReconnecting = ref(false);
|
||||
@ -357,9 +356,8 @@ const serverData = computed(() => server.general);
|
||||
const error = ref<Error | null>(null);
|
||||
const isConnected = ref(false);
|
||||
const isWSAuthIncorrect = ref(false);
|
||||
const maxConsoleOutput = 5000;
|
||||
const consoleOutput = ref<string[]>([]);
|
||||
const throttledConsoleOutput = refThrottled(consoleOutput, 200);
|
||||
const pyroConsole = usePyroConsole();
|
||||
console.log("||||||||||||||||||||||| console", pyroConsole.output);
|
||||
const cpuData = ref<number[]>([]);
|
||||
const ramData = ref<number[]>([]);
|
||||
const isActioning = ref(false);
|
||||
@ -439,7 +437,7 @@ const connectWebSocket = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
consoleOutput.value = [];
|
||||
pyroConsole.clear();
|
||||
socket.value?.send(JSON.stringify({ event: "auth", jwt: wsAuth.value?.token }));
|
||||
isConnected.value = true;
|
||||
isReconnecting.value = false;
|
||||
@ -447,7 +445,7 @@ const connectWebSocket = () => {
|
||||
|
||||
if (firstConnect.value) {
|
||||
for (let i = 0; i < initialConsoleMessage.length; i++) {
|
||||
consoleOutput.value.push(initialConsoleMessage[i]);
|
||||
pyroConsole.addLine(initialConsoleMessage[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -470,9 +468,7 @@ const connectWebSocket = () => {
|
||||
|
||||
socket.value.onclose = () => {
|
||||
if (isMounted.value) {
|
||||
consoleOutput.value.push(
|
||||
"\nSomething went wrong with the connection, we're reconnecting...",
|
||||
);
|
||||
pyroConsole.addLine("\nSomething went wrong with the connection, we're reconnecting...");
|
||||
isConnected.value = false;
|
||||
scheduleReconnect();
|
||||
}
|
||||
@ -530,10 +526,7 @@ const handleWebSocketMessage = (data: WSEvent) => {
|
||||
case "log":
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const log = data.message.split("\n").filter((l) => l.trim());
|
||||
if (consoleOutput.value.length > maxConsoleOutput) {
|
||||
consoleOutput.value.shift();
|
||||
}
|
||||
consoleOutput.value.push(...log);
|
||||
pyroConsole.addLines(log);
|
||||
break;
|
||||
case "stats":
|
||||
updateStats(data);
|
||||
@ -623,7 +616,7 @@ const onReinstall = (potentialArgs: any) => {
|
||||
// serverData.value.loader_version = potentialArgs.lVersion;
|
||||
// serverData.value.mc_version = potentialArgs.mVersion;
|
||||
// if (potentialArgs?.loader) {
|
||||
// console.log("setting loader to", potentialArgs.loader);
|
||||
// console.log("setting loadeconsole
|
||||
// serverData.value.loader = potentialArgs.loader;
|
||||
// }
|
||||
// if (potentialArgs?.lVersion) {
|
||||
|
@ -88,7 +88,7 @@
|
||||
<UiServersPanelServerStatus :state="serverPowerState" />
|
||||
</div>
|
||||
</div>
|
||||
<UiServersPanelTerminal :console-output="consoleOutput" :full-screen="fullScreen">
|
||||
<UiServersPanelTerminal :full-screen="fullScreen">
|
||||
<div class="relative w-full px-4 pt-4">
|
||||
<ul
|
||||
v-if="suggestions.length"
|
||||
@ -192,7 +192,6 @@ type ServerProps = {
|
||||
isConnected: boolean;
|
||||
isWsAuthIncorrect: boolean;
|
||||
stats: Stats;
|
||||
consoleOutput: string[];
|
||||
serverPowerState: ServerState;
|
||||
powerStateDetails?: {
|
||||
oom_killed?: boolean;
|
||||
|
68
apps/frontend/src/store/console.ts
Normal file
68
apps/frontend/src/store/console.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { createGlobalState } from "@vueuse/core";
|
||||
import { type Ref, ref } from "vue";
|
||||
|
||||
/**
|
||||
* Maximum number of console output lines to store
|
||||
* @type {number}
|
||||
*/
|
||||
const maxLines = 5000;
|
||||
|
||||
/**
|
||||
* Provides a global console output state management system
|
||||
* Allows adding, storing, and clearing console output with a maximum line limit
|
||||
*
|
||||
* @returns {Object} Console state management methods and reactive state
|
||||
* @property {Ref<string[]>} consoleOutput - Reactive array of console output lines
|
||||
* @property {function(string): void} addConsoleOutput - Method to add a new console output line
|
||||
* @property {function(): void} clear - Method to clear all console output
|
||||
*/
|
||||
export const usePyroConsole = createGlobalState(() => {
|
||||
/**
|
||||
* Reactive array storing console output lines
|
||||
* @type {Ref<string[]>}
|
||||
*/
|
||||
const output: Ref<string[]> = ref<string[]>([]);
|
||||
|
||||
/**
|
||||
* Adds a new output line to the console output
|
||||
* Automatically removes the oldest line if max output is exceeded
|
||||
*
|
||||
* @param {string} line - The console output line to add
|
||||
*/
|
||||
const addLine = (line: string): void => {
|
||||
output.value.push(line);
|
||||
|
||||
if (output.value.length > maxLines) {
|
||||
output.value.shift();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds multiple output lines to the console output
|
||||
* Automatically removes the oldest lines if max output is exceeded
|
||||
*
|
||||
* @param {string[]} lines - The console output lines to add
|
||||
* @returns {void}
|
||||
*/
|
||||
const addLines = (lines: string[]): void => {
|
||||
output.value.push(...lines);
|
||||
|
||||
if (output.value.length > maxLines) {
|
||||
output.value.splice(0, output.value.length - maxLines);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears all console output lines
|
||||
*/
|
||||
const clear = (): void => {
|
||||
output.value = [];
|
||||
};
|
||||
|
||||
return {
|
||||
output,
|
||||
addLine,
|
||||
addLines,
|
||||
clear,
|
||||
};
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user