diff --git a/src/apps/admin/adminportal/AdminPortal/Page/BugHunt/QuickView.svelte b/src/apps/admin/adminportal/AdminPortal/Page/BugHunt/QuickView.svelte index 74a0f77d8..6c99ad39b 100755 --- a/src/apps/admin/adminportal/AdminPortal/Page/BugHunt/QuickView.svelte +++ b/src/apps/admin/adminportal/AdminPortal/Page/BugHunt/QuickView.svelte @@ -11,7 +11,7 @@ let loading = $state(true); onMount(async () => { - report = await process.admin.getBugReport(id); + report = (await process.admin.getBugReport(id))?.report; loading = false; }); diff --git a/src/apps/admin/adminportal/store.ts b/src/apps/admin/adminportal/store.ts index 421247cbf..be03666da 100755 --- a/src/apps/admin/adminportal/store.ts +++ b/src/apps/admin/adminportal/store.ts @@ -73,7 +73,7 @@ export const AdminPortalPageStore: AdminPortalPages = new Map { const id = process.switchPageProps().id; - return { report: await process.admin.getBugReport(id) }; + return (await process.admin.getBugReport(id)) ?? {}; }, }, ], @@ -89,9 +89,9 @@ export const AdminPortalPageStore: AdminPortalPages = new Map { const id = process.switchPageProps().id; const report = await process.admin.getBugReport(id); - if (!report) return { report }; + if (!report) return report; - const source = await process.admin.getReportSourceFile(report); + const source = await process.admin.getReportSourceFile(report.report); return { report, source }; }, diff --git a/src/apps/components/messagecomposer/MessageComposer.ts b/src/apps/components/messagecomposer/MessageComposer.ts index 9109b8013..8d71b7fc0 100644 --- a/src/apps/components/messagecomposer/MessageComposer.ts +++ b/src/apps/components/messagecomposer/MessageComposer.ts @@ -12,8 +12,8 @@ export const MessageComposerApp: App = { appGroup: "multimedia", }, position: { centered: true }, - size: { w: 800, h: 650 }, - minSize: { w: 800, h: 650 }, + size: { w: 800, h: 500 }, + minSize: { w: 800, h: 500 }, maxSize: { w: NaN, h: NaN }, state: { maximized: false, diff --git a/src/apps/core/loginapp/runtime.ts b/src/apps/core/loginapp/runtime.ts index af39e6917..b9f30c7d0 100755 --- a/src/apps/core/loginapp/runtime.ts +++ b/src/apps/core/loginapp/runtime.ts @@ -237,6 +237,9 @@ export class LoginAppRuntime extends AppProcess implements ILoginAppRuntime { }; if (userDaemon) { + broadcast("Notifying login activity"); + await userDaemon.activity?.logActivity("shutdown"); + broadcast("Stopping Service Host"); await userDaemon.serviceHost?.spinDown(broadcast); @@ -268,6 +271,9 @@ export class LoginAppRuntime extends AppProcess implements ILoginAppRuntime { this.loadingStatus.set(`Restarting...`); if (userDaemon) { + broadcast("Notifying login activity"); + await userDaemon.activity?.logActivity("shutdown"); + broadcast("Stopping Service Host"); await userDaemon.serviceHost?.spinDown(broadcast); diff --git a/src/apps/core/newloginapp/NewLogin.svelte b/src/apps/core/newloginapp/NewLogin.svelte index 79819fca5..573a1d0ce 100644 --- a/src/apps/core/newloginapp/NewLogin.svelte +++ b/src/apps/core/newloginapp/NewLogin.svelte @@ -31,7 +31,7 @@

{:else if $Status.variant === LoginStatusVariant.Loading} -

+

{@html $Status.content}

diff --git a/src/apps/core/newloginapp/runtime.ts b/src/apps/core/newloginapp/runtime.ts index 1ba59437c..81b669372 100644 --- a/src/apps/core/newloginapp/runtime.ts +++ b/src/apps/core/newloginapp/runtime.ts @@ -32,6 +32,7 @@ import { type LoginState, type LoginStatus, } from "./types"; +import { LoginUserDaemonStartOptions } from "../loginapp/store"; export class NewLoginAppRuntime extends AppProcess implements INewLoginAppRuntime { private readonly PERSISTENCE_LS_ID = "arcNewLoginPersistence"; @@ -222,6 +223,12 @@ export class NewLoginAppRuntime extends AppProcess implements INewLoginAppRuntim this.ShowLoading("Saving token"); this.SaveToken(userDaemon!); + // await new Promise(async (r) => { + // while (true) { + // await Sleep(1); + // } + // }); + const result = await userDaemon?.startUserDaemon(NewLoginUserDaemonStartOptions(this), broadcast.bind(this)); this.SaveUserPersistence(userDaemon?.userInfo!); diff --git a/src/apps/user/settings/Settings/Slides/ManageApps.svelte b/src/apps/user/settings/Settings/Slides/ManageApps.svelte index 612c44c74..6d02c4b65 100755 --- a/src/apps/user/settings/Settings/Slides/ManageApps.svelte +++ b/src/apps/user/settings/Settings/Slides/ManageApps.svelte @@ -1,13 +1,16 @@
- -
- - - -
- + + +
{#if !$store.length}

No results!

{:else} {#each $store as app (`${app.originId}-${app.id}-${app.metadata.name}`)} - + {#if view === "grid"} + + {:else if view === "list"} + + {/if} {/each} {/if}
diff --git a/src/apps/user/settings/Settings/Slides/ManageApps/FIlter.svelte b/src/apps/user/settings/Settings/Slides/ManageApps/FIlter.svelte new file mode 100644 index 000000000..af73faf4d --- /dev/null +++ b/src/apps/user/settings/Settings/Slides/ManageApps/FIlter.svelte @@ -0,0 +1,14 @@ + + + diff --git a/src/apps/user/settings/Settings/Slides/ManageApps/GridAppItem.svelte b/src/apps/user/settings/Settings/Slides/ManageApps/GridAppItem.svelte new file mode 100644 index 000000000..ca2999312 --- /dev/null +++ b/src/apps/user/settings/Settings/Slides/ManageApps/GridAppItem.svelte @@ -0,0 +1,18 @@ + + + diff --git a/src/apps/user/settings/Settings/Slides/ManageApps/GridListItem.svelte b/src/apps/user/settings/Settings/Slides/ManageApps/GridListItem.svelte new file mode 100644 index 000000000..b8deb8175 --- /dev/null +++ b/src/apps/user/settings/Settings/Slides/ManageApps/GridListItem.svelte @@ -0,0 +1,24 @@ + + + diff --git a/src/apps/user/settings/Settings/Slides/ManageApps/SearchBar.svelte b/src/apps/user/settings/Settings/Slides/ManageApps/SearchBar.svelte new file mode 100644 index 000000000..3d5019148 --- /dev/null +++ b/src/apps/user/settings/Settings/Slides/ManageApps/SearchBar.svelte @@ -0,0 +1,10 @@ + + + diff --git a/src/apps/user/settings/Settings/Slides/ManageApps/ViewMode.svelte b/src/apps/user/settings/Settings/Slides/ManageApps/ViewMode.svelte new file mode 100644 index 000000000..e08624f54 --- /dev/null +++ b/src/apps/user/settings/Settings/Slides/ManageApps/ViewMode.svelte @@ -0,0 +1,20 @@ + + +
+ + +
diff --git a/src/apps/user/settings/store/index.ts b/src/apps/user/settings/store/index.ts index 679d11153..7bcde3619 100755 --- a/src/apps/user/settings/store/index.ts +++ b/src/apps/user/settings/store/index.ts @@ -34,7 +34,7 @@ export const settingsPageStore: SettingsPages = new Map([ [ "wallpaper", { - name: "Wallpaper", + name: "Desktop Wallpaper", icon: "DesktopIcon", content: Wallpaper, description: "Change your desktop wallpaper", @@ -54,7 +54,7 @@ export const settingsPageStore: SettingsPages = new Map([ [ "visuals", { - name: "Visuals", + name: "Appearance", icon: "PersonalizationIcon", content: Visuals, separator: true, @@ -64,7 +64,7 @@ export const settingsPageStore: SettingsPages = new Map([ [ "shell", { - name: "Shell", + name: "Taskbar and start menu", icon: "TaskbarIcon", content: Shell, description: "The taskbar, start menu and action center", @@ -73,7 +73,7 @@ export const settingsPageStore: SettingsPages = new Map([ [ "search", { - name: "Search", + name: "ArcOS Search", icon: "ArcFindIcon", content: Search, description: "The search functionality of ArcOS", @@ -83,7 +83,7 @@ export const settingsPageStore: SettingsPages = new Map([ [ "apps", { - name: "Apps", + name: "Applications", icon: "AppsIcon", content: Apps, separator: true, diff --git a/src/apps/user/settings/systemSettings.ts b/src/apps/user/settings/systemSettings.ts index 07151b50b..69c877ef7 100644 --- a/src/apps/user/settings/systemSettings.ts +++ b/src/apps/user/settings/systemSettings.ts @@ -6,13 +6,13 @@ import Settings from "./Settings.svelte"; export const SystemSettings: App = { metadata: { name: "System Settings", - author: "Izaak Kuipers", + author: "Izaak Kuipers", version: "6.0.4", icon: "SettingsIcon", appGroup: "systemTools", }, - size: { w: 730, h: 560 }, - minSize: { w: 730, h: 560 }, + size: { w: 810, h: 560 }, + minSize: { w: 810, h: 560 }, maxSize: { w: 1000, h: 800 }, position: { centered: true }, state: { diff --git a/src/css/apps/user/logging.css b/src/css/apps/user/logging.css index bc9d30799..aaf277bc6 100755 --- a/src/css/apps/user/logging.css +++ b/src/css/apps/user/logging.css @@ -137,7 +137,8 @@ } #logging > div.body div.log-list div.row div.segment.message { - max-width: calc(100% - 160px - 16px - 20px); + width: 0; + flex-grow: 1; } #logging > div.body div.log-list div.row div.segment:not(.icon) { diff --git a/src/css/apps/user/settings/page/loginbackground.css b/src/css/apps/user/settings/page/loginbackground.css index 73433beac..1f3cf1686 100755 --- a/src/css/apps/user/settings/page/loginbackground.css +++ b/src/css/apps/user/settings/page/loginbackground.css @@ -1,7 +1,7 @@ #systemSettings div.container.loginBackground div.upload-actions { display: flex; align-items: center; - gap: 5px; + gap: 8px; } #systemSettings div.container.loginBackground div.upload-actions button { @@ -32,8 +32,8 @@ } #systemSettings div.loginBackground div.wallpaper-section div.wallpapers { - display: grid; - grid-template-columns: repeat(5, 70px); + display: flex; + flex-wrap: wrap; gap: 15px; } diff --git a/src/css/apps/user/settings/page/wallpaper.css b/src/css/apps/user/settings/page/wallpaper.css index 79f1d3753..98f9f424f 100755 --- a/src/css/apps/user/settings/page/wallpaper.css +++ b/src/css/apps/user/settings/page/wallpaper.css @@ -1,7 +1,7 @@ #systemSettings div.container.wallpaper div.upload-actions { display: flex; align-items: center; - gap: 5px; + gap: 8px; } #systemSettings div.container.wallpaper div.upload-actions button { diff --git a/src/css/apps/user/settings/section.css b/src/css/apps/user/settings/section.css index 6d74b77f7..fb46ef202 100755 --- a/src/css/apps/user/settings/section.css +++ b/src/css/apps/user/settings/section.css @@ -1,5 +1,5 @@ #systemSettings section { - width: 340px; + width: 350px; margin: 0 auto; margin-top: 20px; } @@ -127,3 +127,7 @@ outline: var(--button-glass-hover-bg) 1px solid; outline-offset: -1px; } + +.theme-light #systemSettings section div.content select { + background-color: var(--win-bg) !important; +} \ No newline at end of file diff --git a/src/css/apps/user/settings/slide/loginactivity.css b/src/css/apps/user/settings/slide/loginactivity.css index 4b66e2ea3..2921404d2 100755 --- a/src/css/apps/user/settings/slide/loginactivity.css +++ b/src/css/apps/user/settings/slide/loginactivity.css @@ -2,6 +2,10 @@ margin-bottom: 20px; } +#systemSettings div.account_loginActivity section { + width: 400px; +} + #systemSettings div.account_loginActivity div.activity-item { display: flex; align-items: start; diff --git a/src/css/apps/user/settings/slide/manageapps.css b/src/css/apps/user/settings/slide/manageapps.css index 5db98c236..e25edda41 100755 --- a/src/css/apps/user/settings/slide/manageapps.css +++ b/src/css/apps/user/settings/slide/manageapps.css @@ -9,8 +9,8 @@ #systemSettings div.apps_manageApps div.options { display: flex; align-items: center; - gap: 10px; - padding: 0 10px; + gap: 15px; + padding: 0 15px; } #systemSettings div.apps_manageApps div.options div.view-mode { @@ -60,18 +60,15 @@ outline-offset: -1px; } #systemSettings div.apps_manageApps div.apps { - display: flex; - flex-wrap: wrap; - gap: 5px; position: relative; height: 0; flex-grow: 1; - padding: 10px; + padding: 15px; overflow-y: scroll; } #systemSettings div.apps_manageApps div.apps button.app { - display: grid; + display: inline-grid; grid-template: "icon name" "icon author"; @@ -79,18 +76,22 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - gap: 0 8px; + gap: 0 15px; text-align: left; --font-size: 12px; - padding: 4px; + padding: 12px; outline: none; - border-radius: 4px; - width: 140px; - height: 40px; + border-radius: 10px; + width: 250px; + height: fit-content; + margin-right: 8px; + margin-bottom: 8px; } -#systemSettings div.apps_manageApps div.apps.grid-large button.app { - width: 200px; +#systemSettings div.apps_manageApps div.apps button.app:hover { + background-color: var(--button-glass-bg); + outline: var(--button-glass-bg) 1px solid; + outline-offset: -1px; } #systemSettings div.apps_manageApps div.apps button.app h1 { @@ -114,17 +115,15 @@ grid-area: icon; } -#systemSettings div.apps_manageApps div.apps.grid-large button.app img { - width: 40px; - height: 40px; -} - -#systemSettings div.apps_manageApps div.apps.grid-large button.app h1 { - font-size: 14px; +#systemSettings div.apps_manageApps div.apps button.app.list-item img { + width: 32px; + height: 32px; } -#systemSettings div.apps_manageApps div.apps.list { - display: block; +#systemSettings div.apps_manageApps div.apps button.app.list-item p.type { + opacity: 0.5; + margin-left: auto; + padding: 0 10px; } #systemSettings div.apps_manageApps div.apps.list button.app { @@ -146,13 +145,10 @@ font-style: italic; } -#systemSettings div.apps_manageApps div.apps.list button.app img { - width: 20px; - height: 20px; -} - -#systemSettings div.apps_manageApps div.apps.list button.app h1 { - margin-right: auto; +#systemSettings div.apps_manageApps div.apps button.app.grid-item:hover { + background-color: var(--button-glass-hover-bg); + outline: var(--button-glass-hover-bg) 1px solid; + outline-offset: -1px; } #systemSettings div.apps_manageApps p.no-results { diff --git a/src/css/spinner.css b/src/css/spinner.css index efdaf28e3..bc24115b5 100755 --- a/src/css/spinner.css +++ b/src/css/spinner.css @@ -6,10 +6,14 @@ img.spinner-svg.hide { opacity: 0 !important; } -#appRenderer[class*="theme-light"] img.spinner-svg { +.theme-light img.spinner-svg { filter: brightness(0.4); } +.theme-dark img.spinner-svg { + filter: brightness(1); +} + div.html-spinner { --size: 32px; --thickness: 5px; diff --git a/src/interfaces/contexts/IFilesystemUserContext.ts b/src/interfaces/contexts/IFilesystemUserContext.ts index f547ea33a..bcf8612ad 100644 --- a/src/interfaces/contexts/IFilesystemUserContext.ts +++ b/src/interfaces/contexts/IFilesystemUserContext.ts @@ -1,7 +1,7 @@ import type { FileProgressMutator, FsProgressOperation } from "$apps/components/fsprogress/types"; import type { LoadSaveDialogData } from "$apps/user/filemanager/types"; import type { ILegacyServerDrive } from "$interfaces/drives/ILegacyServerDrive"; -import type { IMemoryFilesystemDrive } from "$interfaces/drives/IMemoryFilesystemDrive"; +import type { ITemporaryFilesystemDrive } from "$interfaces/drives/ITemporaryFilesystemDrive"; import type { ICommandResult } from "$interfaces/ICommandResult"; import type { IFilesystemDrive } from "$interfaces/IFilesystemDrive"; import type { IUserContext } from "$interfaces/IUserDaemon"; @@ -12,7 +12,7 @@ import type { CategorizedDiskUsage } from "$types/user"; // !tpa export interface IFilesystemUserContext extends IUserContext { - TempFs?: IMemoryFilesystemDrive; + TempFs?: ITemporaryFilesystemDrive; fileHandlers: Record; mountedDrives: string[]; _init(): Promise; diff --git a/src/interfaces/drives/IMemoryFilesystemDrive.ts b/src/interfaces/drives/ITemporaryFilesystemDrive.ts similarity index 73% rename from src/interfaces/drives/IMemoryFilesystemDrive.ts rename to src/interfaces/drives/ITemporaryFilesystemDrive.ts index 4f98eda5a..2b8d01e98 100644 --- a/src/interfaces/drives/IMemoryFilesystemDrive.ts +++ b/src/interfaces/drives/ITemporaryFilesystemDrive.ts @@ -1,7 +1,7 @@ import type { IFilesystemDrive } from "$interfaces/IFilesystemDrive"; // !tpa -export interface IMemoryFilesystemDrive extends IFilesystemDrive { +export interface ITemporaryFilesystemDrive extends IFilesystemDrive { takeSnapshot(): Promise>; restoreSnapshot(snapshot: Record): void; } diff --git a/src/interfaces/services/IAdminBootstrapper.ts b/src/interfaces/services/IAdminBootstrapper.ts index 2f934ac6d..712e6ca84 100644 --- a/src/interfaces/services/IAdminBootstrapper.ts +++ b/src/interfaces/services/IAdminBootstrapper.ts @@ -6,6 +6,7 @@ import type { AdminTemporaryPassword, AuditLog, AuditLogQueryOptions, + BugHuntGetResponse, BugReportSourceInformation, FSItem, IpAddress, @@ -54,7 +55,7 @@ export interface IAdminBootstrapper extends IBaseService { closeBugReport(reportId: string): Promise; reopenBugReport(reportId: string): Promise; getAllBugReports(): Promise; - getBugReport(id: string): Promise; + getBugReport(id: string): Promise; getBugHuntStatistics(): Promise; setSystemFor(username: string, value: boolean): Promise; disapproveUser(username: string): Promise; diff --git a/src/main.ts b/src/main.ts index 8368727d2..3d0c3eb95 100755 --- a/src/main.ts +++ b/src/main.ts @@ -1,14 +1,14 @@ import "dseg/css/dseg.css"; import "./css/main.css"; +import { HtmlUtil } from "$ts/util/html"; // CODE EXECUTION STARTS HERE async function Main() { const { WaveKernel } = await import("$ts/kernel/wavekernel"); - const kernel = new WaveKernel(); window.__DW_STATUS__ = "async Main"; - document.querySelector("#stateLoader")!.innerText = ".."; + HtmlUtil.GetStateLoader().innerText = ".."; await kernel._init(); } diff --git a/src/ts/basic/commands/setpref.ts b/src/ts/basic/commands/setpref.ts new file mode 100644 index 000000000..f2d95b956 --- /dev/null +++ b/src/ts/basic/commands/setpref.ts @@ -0,0 +1,29 @@ +import { Daemon } from "$ts/env"; +import { setJsonHierarchy } from "$ts/util/hierarchy"; +import { BasicCommand } from "../engine/command"; + +export class SetprefCommand extends BasicCommand { + static keyword: string = "setpref"; + + async execute(line: string): Promise { + const [rawHierarchy, ...values] = await this.interpreter.getStrings(line, false); + + if (!rawHierarchy) { + return "No hierarchy found. Did you wrap it in a string?" + } + + if (values.length !== 1) { + return "SETPREF takes exactly one value"; + } + + const hierarchy = await this.interpreter.replaceVariables(rawHierarchy, false); + const value = await this.interpreter.replaceVariables(values[0], true); + + Daemon.preferences.update((v) => { + setJsonHierarchy(v, hierarchy, value); + return v; + }); + + return undefined; + } +} diff --git a/src/ts/basic/config/commandset.ts b/src/ts/basic/config/commandset.ts index 59dfc9b30..da4c903e9 100644 --- a/src/ts/basic/config/commandset.ts +++ b/src/ts/basic/config/commandset.ts @@ -5,6 +5,7 @@ import { GosubCommand } from "../commands/gosub"; import { IfCommand } from "../commands/if"; import { KillCommand } from "../commands/kill"; import { PrintCommand } from "../commands/print"; +import { SetprefCommand } from "../commands/setpref"; import { SoundbusCommand } from "../commands/soundbus"; import { StopCommand } from "../commands/stop"; import { SubCommand } from "../commands/sub"; @@ -13,16 +14,17 @@ import { WhileCommand } from "../commands/while"; import type { BasicCommand } from "../engine/command"; export const BasicCommandSet: (typeof BasicCommand)[] = [ - PrintCommand, - IfCommand, - VarCommand, + EndsubCommand, + ErrorCommand, + GostartCommand, GosubCommand, - SubCommand, - StopCommand, + IfCommand, KillCommand, - GostartCommand, - WhileCommand, + PrintCommand, + SetprefCommand, SoundbusCommand, - EndsubCommand, - ErrorCommand, + StopCommand, + SubCommand, + VarCommand, + WhileCommand, ]; diff --git a/src/ts/basic/engine/index.ts b/src/ts/basic/engine/index.ts index ef97157cc..1bbfe2dd3 100644 --- a/src/ts/basic/engine/index.ts +++ b/src/ts/basic/engine/index.ts @@ -391,7 +391,7 @@ export class ArcBasicEngine { async findNextEndling(endling: string, startIdx = this.programCounter): Promise { this.Debug(`findNextEndling >>${endling}<< startIdx=${startIdx}`); - const lookahead = this.source.slice(startIdx, this.source.length - 1); + const lookahead = this.source.slice(startIdx, this.source.length); const endKeyword = `end${endling.toLowerCase()}`; const idx = lookahead.findIndex((l) => l.toLowerCase().trim().startsWith(endKeyword)); @@ -430,9 +430,10 @@ export class ArcBasicEngine { await this.setVariable("ERR", message); if (exit) { + this.HALT = true; const line = this.source[this.programCounter]; const lineNumber = `${this.programCounter + 1}`; - const columnNumber = Math.max(columnIndexHint ? line.indexOf(columnIndexHint) : 0, 0); + const columnNumber = Math.max(columnIndexHint ? line?.indexOf(columnIndexHint) ?? 0 : 0, 0); const linePrefix = " ".repeat(lineNumber.length) + " ║ "; const leftOffset = " ".repeat(columnNumber); diff --git a/src/ts/basic/engine/regex.ts b/src/ts/basic/engine/regex.ts index b8a983d3d..fa65e89d8 100644 --- a/src/ts/basic/engine/regex.ts +++ b/src/ts/basic/engine/regex.ts @@ -1,10 +1,10 @@ export const REGEXES = { STRING: /"(?[^"]+|)"/gm, - FUNCTION: /(?[a-zA-Z]+)\((?.+|)\)/gm, + FUNCTION: /\b(?[a-zA-Z]+)\((?(?:"(?:[^"\\]|\\.)*"|[^()"])*)\)/gm, IF: /(?NOT |not |)(?.+) (?:THEN|then)($| (?.+))/, DUALEXPR: /(?.+) (?[A-Za-z]+) (?.+)/, WHILE: /(?NOT |not |)(?.+) (?:DO|do)($| (?.+))/, - VARGET: /\$(?[A-Za-z]{1,6})(?:\[(?[0-9\-]+|\+|\$[A-Za-z]{1,6}|LEN)\]|\{(?[a-zA-Z\_\.0-9]+)\}|)/g, + VARGET: /\$(?[A-Za-z]{1,6})(?:\[(?[0-9\-]+|\+|\$[A-Za-z]{1,6}|LEN|len)\]|\{(?[a-zA-Z\_\.0-9]+)\}|)/g, VARSET: - /(?[A-Za-z]{1,6})(?:\[(?[0-9\-]+|\+|\$[A-Za-z]{1,6}|LEN)\]|\{(?[a-zA-Z\_\.0-9]+)\}|) = (?.+|)/, + /(?[A-Za-z]{1,6})(?:\[(?[0-9\-]+|\+|\$[A-Za-z]{1,6}|LEN|len)\]|\{(?[a-zA-Z\_\.0-9]+)\}|) = (?.+|)/, }; diff --git a/src/ts/basic/highlight.ts b/src/ts/basic/highlight.ts index 7b698da32..98d7d0f54 100644 --- a/src/ts/basic/highlight.ts +++ b/src/ts/basic/highlight.ts @@ -24,6 +24,7 @@ export default function ArcBasicHighlighter(hljs: HLJSApi): Language { "THEN", "VAR", "WHILE", + "SETPREF" ]; const VARGET = { diff --git a/src/ts/daemon/contexts/filesystem.ts b/src/ts/daemon/contexts/filesystem.ts index 8e7cc29fb..731c4558a 100644 --- a/src/ts/daemon/contexts/filesystem.ts +++ b/src/ts/daemon/contexts/filesystem.ts @@ -2,7 +2,7 @@ import { DummyFileProgress, type FileProgressMutator, type FsProgressOperation } import type { LoadSaveDialogData } from "$apps/user/filemanager/types"; import type { IFilesystemUserContext } from "$interfaces/contexts/IFilesystemUserContext"; import type { ILegacyServerDrive } from "$interfaces/drives/ILegacyServerDrive"; -import type { IMemoryFilesystemDrive } from "$interfaces/drives/IMemoryFilesystemDrive"; +import type { ITemporaryFilesystemDrive } from "$interfaces/drives/ITemporaryFilesystemDrive"; import type { ICommandResult } from "$interfaces/ICommandResult"; import type { IFilesystemDrive } from "$interfaces/IFilesystemDrive"; import type { IUserDaemon } from "$interfaces/IUserDaemon"; @@ -30,7 +30,7 @@ import { UserContext } from "../context"; export class FilesystemUserContext extends UserContext implements IFilesystemUserContext { private thumbnailCache: Record = {}; - public TempFs?: IMemoryFilesystemDrive; + public TempFs?: ITemporaryFilesystemDrive; public fileHandlers: Record; public mountedDrives: string[] = []; private TempFsSnapshot: Record = {}; @@ -46,7 +46,7 @@ export class FilesystemUserContext extends UserContext implements IFilesystemUse } async _init() { - this.TempFs = Fs.getDriveById("temp") as IMemoryFilesystemDrive; + this.TempFs = Fs.getDriveById("temp") as ITemporaryFilesystemDrive; this.TempFsSnapshot = await this.TempFs.takeSnapshot(); } diff --git a/src/ts/kernel/init.ts b/src/ts/kernel/init.ts index 51c46c683..e8e131cb8 100755 --- a/src/ts/kernel/init.ts +++ b/src/ts/kernel/init.ts @@ -2,7 +2,7 @@ import type { IStateHandler } from "$interfaces/IStateHandler"; import type { IServerManager } from "$interfaces/modules/IServerManager"; import { __Console__ } from "$ts/console"; import { ArcOSVersion, Env, Fs, getKMod, Kernel, SetCurrentStateHandler, Stack } from "$ts/env"; -import { MemoryFilesystemDrive } from "$ts/kernel/mods/fs/drives/temp"; +import { TemporaryFilesystemDrive } from "$ts/kernel/mods/fs/drives/temp"; import { ArcBuild } from "$ts/metadata/build"; import { ArcMode } from "$ts/metadata/mode"; import { States } from "$ts/state/store"; @@ -58,7 +58,7 @@ export class InitProcess extends Process { this.Log("Initializing TEMP"); try { - await Fs.mountDrive("temp", MemoryFilesystemDrive, "T"); + await Fs.mountDrive("temp", TemporaryFilesystemDrive, "T"); await Fs.createDirectory("T:/Apps"); await Fs.createDirectory("T:/Meta"); await Fs.writeFile("T:/Meta/ARCOS_BUILD", textToBlob(ArcBuild())); diff --git a/src/ts/kernel/mods/fs/drives/admin.ts b/src/ts/kernel/mods/fs/drives/admin.ts index 1690c4873..1a6ad153b 100644 --- a/src/ts/kernel/mods/fs/drives/admin.ts +++ b/src/ts/kernel/mods/fs/drives/admin.ts @@ -1,16 +1,18 @@ import type { IFilesystemDrive } from "$interfaces/IFilesystemDrive"; -import { Daemon } from "$ts/env"; +import { Daemon, Server } from "$ts/env"; import { FilesystemDrive } from "$ts/kernel/mods/fs/drives/generic"; import { Backend } from "$ts/kernel/mods/server/axios"; -import { ToAxiosProgress } from "$ts/util"; +import { authcode, ToAxiosProgress } from "$ts/util"; import { arrayBufferToBlob } from "$ts/util/convert"; import { toForm } from "$ts/util/form"; import { getItemNameFromPath, join } from "$ts/util/fs"; import type { DirectoryReadReturn, DriveCapabilities, + ExtendedStat, FilesystemProgressCallback, FilesystemStat, + FsAccess, RecursiveDirectoryReadReturn, UserQuota, } from "$types/system/fs"; @@ -184,18 +186,34 @@ export class AdminFileSystem extends FilesystemDrive implements IFilesystemDrive } async direct(path: string): Promise { - const content = await this.readFile(path, () => {}); - if (!content) return undefined; + try { + const response = await Backend.post( + `/admin/afs/accessors/${path}`, + {}, + { headers: { Authorization: `Bearer ${Daemon!.token}` } } + ); - const blob = arrayBufferToBlob(content); - return URL.createObjectURL(blob); + const data = response.data as FsAccess; + + return `${this.server.url}/admin/afs/direct/${data.userId}/${data.accessor}${authcode()}`; + } catch { + return undefined; + } } async stat(path: string): Promise { try { const response = await Backend.get(`/admin/afs/stat/${path}`, { headers: { Authorization: `Bearer ${Daemon!.token}` } }); + const data = response.data as ExtendedStat; + + if (data.modifiers?.createdBy?.user?.profilePicture) { + data.modifiers.createdBy.user.profilePicture = `${Server.url}${data.modifiers.createdBy.user.profilePicture}${authcode()}`; + } + if (data.modifiers?.lastWrite?.user?.profilePicture) { + data.modifiers.lastWrite.user.profilePicture = `${Server.url}${data.modifiers.lastWrite.user.profilePicture}${authcode()}`; + } - return response.data as FilesystemStat; + return data as FilesystemStat; } catch { return undefined; } diff --git a/src/ts/kernel/mods/fs/drives/temp.ts b/src/ts/kernel/mods/fs/drives/temp.ts index f9bd939be..20243023c 100644 --- a/src/ts/kernel/mods/fs/drives/temp.ts +++ b/src/ts/kernel/mods/fs/drives/temp.ts @@ -1,4 +1,4 @@ -import type { IMemoryFilesystemDrive } from "$interfaces/drives/IMemoryFilesystemDrive"; +import type { ITemporaryFilesystemDrive } from "$interfaces/drives/ITemporaryFilesystemDrive"; import { FilesystemDrive } from "$ts/kernel/mods/fs/drives/generic"; import { deepCopyWithBlobs, sortByKey } from "$ts/util"; import { UUID } from "$ts/util/uuid"; @@ -11,7 +11,7 @@ import type { UserQuota, } from "$types/system/fs"; -export class MemoryFilesystemDrive extends FilesystemDrive implements IMemoryFilesystemDrive { +export class TemporaryFilesystemDrive extends FilesystemDrive implements ITemporaryFilesystemDrive { private readonly data: Record = {}; public FIXED: boolean = true; public override IDENTIFIES_AS: string = "temp"; diff --git a/src/ts/kernel/mods/fs/drives/userfs.ts b/src/ts/kernel/mods/fs/drives/userfs.ts index dc4437833..cf1ecb723 100644 --- a/src/ts/kernel/mods/fs/drives/userfs.ts +++ b/src/ts/kernel/mods/fs/drives/userfs.ts @@ -247,11 +247,11 @@ export class UserDrive extends FilesystemDrive implements IFilesystemDrive { const response = await Backend.get(`/fs/stat/${path}`, { headers: { Authorization: `Bearer ${Daemon!.token}` } }); const data = response.data as ExtendedStat; - if (data.modifiers?.createdBy?.user) { - data.modifiers.createdBy.user.profilePicture = `${Server.url}${data.modifiers.createdBy.user.profilePicture}`; + if (data.modifiers?.createdBy?.user?.profilePicture) { + data.modifiers.createdBy.user.profilePicture = `${Server.url}${data.modifiers.createdBy.user.profilePicture}${authcode()}`; } - if (data.modifiers?.lastWrite?.user) { - data.modifiers.lastWrite.user.profilePicture = `${Server.url}${data.modifiers.lastWrite.user.profilePicture}`; + if (data.modifiers?.lastWrite?.user?.profilePicture) { + data.modifiers.lastWrite.user.profilePicture = `${Server.url}${data.modifiers.lastWrite.user.profilePicture}${authcode()}`; } return data as ExtendedStat; diff --git a/src/ts/kernel/mods/server/connectors/ShareConnector.ts b/src/ts/kernel/mods/server/connectors/ShareConnector.ts index 366682407..54ff89af6 100644 --- a/src/ts/kernel/mods/server/connectors/ShareConnector.ts +++ b/src/ts/kernel/mods/server/connectors/ShareConnector.ts @@ -2,7 +2,7 @@ import type { ICommandResult } from "$interfaces/ICommandResult"; import type { IShareConnector } from "$interfaces/modules/server/IShareConnector"; import { Server } from "$ts/env"; import { CommandResult } from "$ts/result"; -import { ToAxiosProgress } from "$ts/util"; +import { authcode, ToAxiosProgress } from "$ts/util"; import { arrayBufferToBlob } from "$ts/util/convert"; import { toForm } from "$ts/util/form"; import { getItemNameFromPath, join } from "$ts/util/fs"; @@ -131,8 +131,8 @@ export class ShareConnector extends ServerConnector implements IShareConnector { const response = CommandResult.FromResponse(await this.server.get(`/stat/${shareId}/${path}`)); if (!response.success) return response as ICommandResult; - response.result.modifiers.createdBy.user.profilePicture = `${Server.url}${response.result.modifiers.createdBy.user.profilePicture}`; - response.result.modifiers.lastWrite.user.profilePicture = `${Server.url}${response.result.modifiers.lastWrite.user.profilePicture}`; + response.result.modifiers.createdBy.user.profilePicture = `${Server.url}${response.result.modifiers.createdBy.user.profilePicture}${authcode()}`; + response.result.modifiers.lastWrite.user.profilePicture = `${Server.url}${response.result.modifiers.lastWrite.user.profilePicture}${authcode()}`; return response; } catch (e) { diff --git a/src/ts/servicehost/services/AdminBootstrapper/index.ts b/src/ts/servicehost/services/AdminBootstrapper/index.ts index 034e3eedb..f3493efea 100644 --- a/src/ts/servicehost/services/AdminBootstrapper/index.ts +++ b/src/ts/servicehost/services/AdminBootstrapper/index.ts @@ -24,6 +24,7 @@ import type { AdminTemporaryPassword, AuditLog, AuditLogQueryOptions, + BugHuntGetResponse, BugReportSourceInformation, FsAccess, FSItem, @@ -367,12 +368,12 @@ export class AdminBootstrapper extends BaseService implements IAdminBootstrapper } } - async getBugReport(id: string): Promise { + async getBugReport(id: string): Promise { if (this._disposed) return; try { - const response = await this.adminClient.get(`/report/${id}`); + const response = await this.adminClient.get(`/bughunt/report/${id}`); - return response.data as BugReport; + return response.data as BugHuntGetResponse; } catch { return undefined; } diff --git a/src/ts/servicehost/services/ArcFindSvc/index.ts b/src/ts/servicehost/services/ArcFindSvc/index.ts index 5eeeb3bc2..2c7008459 100644 --- a/src/ts/servicehost/services/ArcFindSvc/index.ts +++ b/src/ts/servicehost/services/ArcFindSvc/index.ts @@ -129,8 +129,10 @@ export class ArcFindService extends BaseService implements IArcFindService { this.fileSystemIndex = index; // Set the cache + const assoc = Daemon.assoc; + for (const file of index) { - const info = Daemon?.assoc?.getFileAssociation(file.name); + const info = assoc?.getFileAssociation(file.name); if (preferences.searchOptions.excludeShortcuts && !!file.shortcut) continue; diff --git a/src/ts/servicehost/services/GlobalDispatch/index.ts b/src/ts/servicehost/services/GlobalDispatch/index.ts index 89e21895e..b2b4e698c 100644 --- a/src/ts/servicehost/services/GlobalDispatch/index.ts +++ b/src/ts/servicehost/services/GlobalDispatch/index.ts @@ -61,6 +61,8 @@ export class GlobalDispatch extends BaseService implements IGlobalDispatch { this.client?.once("disconnect", () => resolve()); this.client?.disconnect(); this.stackUnsubscribe?.(); + + if (this.client?.disconnected) resolve(); }); } @@ -93,6 +95,15 @@ export class GlobalDispatch extends BaseService implements IGlobalDispatch { this.emit("update", { lastActive: Date.now(), processCount: Stack.store().size, + processes: [...Stack.store()].map(([pid, proc]) => ({ + pid, + parentPid: proc.parentPid, + name: proc.name, + className: proc.constructor.name, + classType: Object.getPrototypeOf(proc.constructor).name, + sourceUrl: proc.sourceUrl, + state: proc.STATE, + })), lastApp: Stack.renderer?.lastInteract?.app?.data, }); } diff --git a/src/ts/terminal/commands/admin/commands/bughunt/get.ts b/src/ts/terminal/commands/admin/commands/bughunt/get.ts index 1106d70a4..bcde6bbd7 100755 --- a/src/ts/terminal/commands/admin/commands/bughunt/get.ts +++ b/src/ts/terminal/commands/admin/commands/bughunt/get.ts @@ -8,10 +8,10 @@ export const AdminBugHuntReportGet: AdminCommandType = async (term, admin, [id]) if (!admin.canAccess(AdminScopes.adminBugHuntGet, AdminScopes.adminUsersList)) return 2; if (!id) return 5; - const report = await admin.getBugReport(id); - - if (!report) return 3; + const reportResult = await admin.getBugReport(id); + if (!reportResult) return 3; + const report = reportResult.report; const opened = report.closed ? `${BRRED}Closed${RESET}` : `${BRGREEN}Open${RESET}`; const api = `${report.api || "No server"}`; const frontend = `${report.frontend}`; diff --git a/src/ts/user/store.ts b/src/ts/user/store.ts index 9ed9fbf74..691e6cd1d 100644 --- a/src/ts/user/store.ts +++ b/src/ts/user/store.ts @@ -198,12 +198,14 @@ export const ActivityIconTranslations = { unknown: "shield-question", login: "log-in", logout: "log-out", + shutdown: "power", }; export const ActivityCaptionTranslations = { unknown: "Unknown activity", login: "Logged in", logout: "Logged out", + shutdown: "Shut down ArcOS", }; export const TimeFrames: Record = { diff --git a/src/ts/util/html.ts b/src/ts/util/html.ts new file mode 100644 index 000000000..acb1bfa16 --- /dev/null +++ b/src/ts/util/html.ts @@ -0,0 +1,24 @@ +export class HtmlUtil { + public static GetStateLoader() { + return this.GetElement("#stateLoader", "StateLoader"); + } + + public static GetAppRenderer() { + return this.GetElement("#appRenderer", "AppRenderer"); + } + + public static GetKernelLog() { + return this.GetElement("#kernelLog", "KernelLog"); + } + + public static GetMain() { + return this.GetElement("body > main#main", "Main"); + } + + private static GetElement(selectors: string, qualifiedName: string): T { + const element = document.querySelector(selectors); + if (!element) throw new Error(`${this.GetElement.name}::${qualifiedName} failed`); + + return element; + } +} diff --git a/src/types/server/admin.ts b/src/types/server/admin.ts index 7ed86fd64..0c03b3d35 100644 --- a/src/types/server/admin.ts +++ b/src/types/server/admin.ts @@ -1,4 +1,5 @@ import type { ExpandedUserInfo } from "../user"; +import type { BugReport } from "./bughunt"; import type { QueryableOptions } from "./query"; export interface Activity { @@ -199,3 +200,8 @@ export interface AdminTemporaryPassword { createdAt: string; updatedAt: string; } + +export interface BugHuntGetResponse { + report: BugReport; + reportId: string; +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 42b29dfa0..27f693640 100755 --- a/vite.config.ts +++ b/vite.config.ts @@ -41,6 +41,7 @@ export default defineConfig({ }, assetsInlineLimit: 1, minify: true, + target: [] }, esbuild: { keepNames: true,