Files
AstralRinth/apps/frontend/src/store/console.ts
Evan Song a75538c093 Modrinth Servers Mega Features & Bug Fix-a-thon (#3222)
* fix(content): changing mod versions works again

* chore(assets): update pyro logo

* fix(properties): deprecate fetchconfigfile

* Revert "fix(content): changing mod versions works again"

This reverts commit d7c0d1196f8c1850fd7ccbc1644941c6db4dc306.

* feat(files): ability to sort via column click

* chore(startup): update clunky wording

* feat(serverListing): server icons SSR friendly

* fix(servers): if archon fails, display err in listing

* chore(serverlisting): use pyroserver hook to init icon

* chore(servers): much more graceful reinstall

* fix(servers): tw warn

* fix(platform): correctly react when pack reinstalled

* fix(serversroot): explicitly import navigateTo

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(serverlabels): show skeleton instead of hiding

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat(platform): install-aware controls

Signed-off-by: Evan Song <theevansong@gmail.com>

* refactor!(platform): rewrite platform page

* fix(platform): regression in autoselecting loader

* chore(platform): prefer version over project modification date

* fix(platform): permanent hang after initial mount

* chore(platform): do not silently fail and hang if modpack fails loading

* oops: remove hardcoded error causer

* fix(platform): switch modpack btn while installing doesnt need class

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(platform): adjust styling in version modal

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(platform): prevent changing project card style

Signed-off-by: Evan Song <theevansong@gmail.com>

* refactor(pyrodropdown): rewrite

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(pyrodropdown): do nopt use deprecated substr

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: clean

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(network): sentence case

Signed-off-by: Evan Song <theevansong@gmail.com>

* refactor(terminal): initial batch

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): fulllog over fullscreen

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): fullscreen conflict with body scroll

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat(terminal): init drag select

* feat(terminal): shift click support

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(terminal): double lines limit

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat(terminal): copy button

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(terminal): protip style

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(terminal): improve styles

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat(terminal): regex search

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(terminal): move icons to icons dir

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(terminal): improve drag select autoscroll inertia

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): cancel selection on right click

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): progblur and stb btn disappearing

Signed-off-by: Evan Song <theevansong@gmail.com>

* refactor(serverstats): power efficiency

* fix(subdomainlabel): correct tooltip terminology

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat(preferences): users hide subdomain label

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(servers): clean

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(terminal): deselect lines on escape

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(serversidebar): type err

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(fileitem): vue server render type

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): disable pointer events on lines if scrolling

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): search result counts style

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): plural

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(terminal): clean

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat(terminal): view selection

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat(terminal): show actively selected lines in scrollbar

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminallog): btn color

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: clean

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(gamelabel): align to text

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(gamelabel): align to text

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(listing): remove deadcode

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(serverlisting): deprecated process.server

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(platform): correctly disable button

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(backups): do not allow backup creation during server installation

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(platform): flush stale currentversion data on successful install

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(gamelabel): fix gap

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(network): vaporize uppercase

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(info): vaporize uppercase

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(backups): style unification

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(backups): finalize style change

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(servers): catch pyro servers fetch errors during ssr

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(serverstats): ram as bytes graph now works

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(platform): unify attempts and refresh interval

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): input

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat(servers): installing ticket + update available notice back in platform

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(terminal): dont add bg to scroll track

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): preserve whitespace

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(serversroot): unnest blurred icon query

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(serverstats): clamp memory usage to 100% no matter what

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat(terminal): allow copy of single lines, show btn

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(terminal): animate copy>view transition

Signed-off-by: Evan Song <theevansong@gmail.com>

* init: search improvements

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: lint

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: change log modal title

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: hide fullscreen when selecting and cancel selection on clickout

Signed-off-by: Evan Song <theevansong@gmail.com>

* refactor(terminal): more reliable jumpToLine

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat: search results separator

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: remove buggy isScrollable check

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: style

Signed-off-by: Evan Song <theevansong@gmail.com>

* refactor: correctly store pos to make jump reliable

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: disparity between search/log dragselect

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: prevent propagation of click events when clicking on jump btn

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: switch selection strategies depending on terminal mode

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: smarter esc handling

Signed-off-by: Evan Song <theevansong@gmail.com>

* finalize

Signed-off-by: Evan Song <theevansong@gmail.com>

* run fix

* fix: ensure lines between cannot be selected

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: increase initial log batch to 256

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): click on scroll track should take user to new scroll position

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(terminal): update aria label for view selected logs btn

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: clean

Signed-off-by: Evan Song <theevansong@gmail.com>

---------

Signed-off-by: Evan Song <theevansong@gmail.com>
2025-02-10 07:39:13 -08:00

165 lines
4.3 KiB
TypeScript

import { createGlobalState } from "@vueuse/core";
import { type Ref, shallowRef } from "vue";
/**
* Maximum number of console output lines to store
* @type {number}
*/
const maxLines = 10000;
const batchTimeout = 300; // ms
const initialBatchSize = 256;
/**
* 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[]> = shallowRef<string[]>([]);
const searchQuery: Ref<string> = shallowRef("");
const filteredOutput: Ref<string[]> = shallowRef([]);
let searchRegex: RegExp | null = null;
let lineBuffer: string[] = [];
let batchTimer: NodeJS.Timeout | null = null;
let isProcessingInitialBatch = false;
let refilterTimer: NodeJS.Timeout | null = null;
const refilterTimeout = 100; // ms
const updateFilter = () => {
if (!searchQuery.value) {
filteredOutput.value = [];
return;
}
if (!searchRegex) {
searchRegex = new RegExp(searchQuery.value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i");
}
filteredOutput.value = output.value.filter((line) => searchRegex?.test(line) ?? false);
};
const scheduleRefilter = () => {
if (refilterTimer) clearTimeout(refilterTimer);
refilterTimer = setTimeout(updateFilter, refilterTimeout);
};
const flushBuffer = () => {
if (lineBuffer.length === 0) return;
const processedLines = lineBuffer.flatMap((line) => line.split("\n").filter(Boolean));
if (isProcessingInitialBatch && processedLines.length >= initialBatchSize) {
isProcessingInitialBatch = false;
output.value = processedLines.slice(-maxLines);
} else {
const newOutput = [...output.value, ...processedLines];
output.value = newOutput.slice(-maxLines);
}
lineBuffer = [];
batchTimer = null;
if (searchQuery.value) {
scheduleRefilter();
}
};
/**
* 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 => {
lineBuffer.push(line);
if (!batchTimer) {
batchTimer = setTimeout(flushBuffer, batchTimeout);
}
};
/**
* 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 => {
if (output.value.length === 0 && lines.length >= initialBatchSize) {
isProcessingInitialBatch = true;
lineBuffer = lines;
flushBuffer();
return;
}
lineBuffer.push(...lines);
if (!batchTimer) {
batchTimer = setTimeout(flushBuffer, batchTimeout);
}
};
/**
* Sets the search query and filters the output based on the query
*
* @param {string} query - The search query
*/
const setSearchQuery = (query: string): void => {
searchQuery.value = query;
searchRegex = null;
updateFilter();
};
/**
* Clears all console output lines
*/
const clear = (): void => {
output.value = [];
filteredOutput.value = [];
searchQuery.value = "";
lineBuffer = [];
isProcessingInitialBatch = false;
if (batchTimer) {
clearTimeout(batchTimer);
batchTimer = null;
}
if (refilterTimer) {
clearTimeout(refilterTimer);
refilterTimer = null;
}
searchRegex = null;
};
/**
* Finds the index of a line in the main output
*
* @param {string} line - The line to find
* @returns {number} The index of the line, or -1 if not found
*/
const findLineIndex = (line: string): number => {
return output.value.findIndex((l) => l === line);
};
return {
output,
searchQuery,
filteredOutput,
addLine,
addLines,
setSearchQuery,
clear,
findLineIndex,
};
});