Various bug fixes (#102)

* feat: set lang in html head

* fix: add # in front of git ref

* fix: remove unused vars from example env

* fix: package name and license field

* fix: enable sourcemap for client and server

* fix: emojis not showing in prod

this is extremely cursed, but it works

* chore: refactor auth manager

* feat: disable invitations if simple auth disabled

* feat: add drop version to footer

* feat: translate auth endpoints

* chore: move oidc module

* feat: add weekly tasks

enabled object cleanup as weekly task

* feat: add timestamp to task log msgs

* feat: add guard to prevent invalid progress %

* fix: add missing global scope to i18n components

* feat: set base url for i18n

* feat: switch task log to json format

* ci: run ci on develop branch only

* fix: UserWidget text not updating #109

* fix: EXTERNAL_URL being computed at build

* feat: add basic language outlines for translation

* feat: add more english dialects
This commit is contained in:
Husky
2025-06-07 23:49:43 -04:00
committed by GitHub
parent 9f5a3b3976
commit 72ae7a2884
43 changed files with 577 additions and 229 deletions
+79 -12
View File
@@ -9,6 +9,7 @@ import checkUpdate from "./registry/update";
import cleanupObjects from "./registry/objects";
import { taskGroups, type TaskGroup } from "./group";
import prisma from "../db/database";
import { type } from "arktype";
// a task that has been run
type FinishedTask = {
@@ -45,11 +46,12 @@ class TaskHandler {
// list of all clients currently connected to tasks
private clientRegistry = new Map<string, PeerImpl>();
private scheduledTasks: TaskGroup[] = [
private dailyScheduledTasks: TaskGroup[] = [
"cleanup:invitations",
"cleanup:sessions",
"check:update",
];
private weeklyScheduledTasks: TaskGroup[] = ["cleanup:objects"];
constructor() {
// register the cleanup invitations task
@@ -124,18 +126,22 @@ class TaskHandler {
}, 100);
});
const progress = (progress: number) => {
const taskEntry = this.taskPool.get(task.id);
if (!taskEntry) return;
taskEntry.progress = progress;
updateAllClients();
};
const log = (entry: string) => {
const taskEntry = this.taskPool.get(task.id);
if (!taskEntry) return;
taskEntry.log.push(entry);
// console.log(`[Task ${task.taskGroup}]: ${entry}`);
taskEntry.log.push(msgWithTimestamp(entry));
updateAllClients();
};
const progress = (progress: number) => {
if (progress < 0 || progress > 100) {
console.error("Progress must be between 0 and 100", { progress });
return;
}
const taskEntry = this.taskPool.get(task.id);
if (!taskEntry) return;
taskEntry.progress = progress;
// log(`Progress: ${progress}%`);
updateAllClients();
};
@@ -288,7 +294,11 @@ class TaskHandler {
}
dailyTasks() {
return this.scheduledTasks;
return this.dailyScheduledTasks;
}
weeklyTasks() {
return this.weeklyScheduledTasks;
}
runTaskGroupByName(name: TaskGroup) {
@@ -304,7 +314,7 @@ class TaskHandler {
* Runs all daily tasks that are scheduled to run once a day.
*/
async triggerDailyTasks() {
for (const taskGroup of this.scheduledTasks) {
for (const taskGroup of this.dailyScheduledTasks) {
const mostRecent = await prisma.task.findFirst({
where: {
taskGroup,
@@ -324,6 +334,32 @@ class TaskHandler {
}
await this.runTaskGroupByName(taskGroup);
}
// After running daily tasks, trigger weekly tasks as well
await this.triggerWeeklyTasks();
}
private async triggerWeeklyTasks() {
for (const taskGroup of this.weeklyScheduledTasks) {
const mostRecent = await prisma.task.findFirst({
where: {
taskGroup,
},
orderBy: {
ended: "desc",
},
});
if (mostRecent) {
const currentTime = Date.now();
const lastRun = mostRecent.ended.getTime();
const difference = currentTime - lastRun;
if (difference < 1000 * 60 * 60 * 24 * 7) {
// If it's been less than one week
continue; // skip
}
}
await this.runTaskGroupByName(taskGroup);
}
}
}
@@ -383,6 +419,37 @@ interface DropTask {
build: () => Task;
}
export const TaskLog = type({
timestamp: "string",
message: "string",
});
/**
* Create a log message with a timestamp in the format YYYY-MM-DD HH:mm:ss.SSS UTC
* @param message
* @returns
*/
function msgWithTimestamp(message: string): string {
const now = new Date();
const pad = (n: number, width = 2) => n.toString().padStart(width, "0");
const year = now.getUTCFullYear();
const month = pad(now.getUTCMonth() + 1);
const day = pad(now.getUTCDate());
const hours = pad(now.getUTCHours());
const minutes = pad(now.getUTCMinutes());
const seconds = pad(now.getUTCSeconds());
const milliseconds = pad(now.getUTCMilliseconds(), 3);
const log: typeof TaskLog.infer = {
timestamp: `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds} UTC`,
message,
};
return JSON.stringify(log);
}
export function defineDropTask(buildTask: BuildTask): DropTask {
// TODO: only let one task with the same taskGroup run at the same time if specified