Skip to content

Commit

Permalink
UI: Warn player if they are editing and saving files on non-home serv…
Browse files Browse the repository at this point in the history
…ers (#1968)
  • Loading branch information
catloversg authored Feb 17, 2025
1 parent 13990fb commit 63d7061
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 32 deletions.
23 changes: 13 additions & 10 deletions src/ScriptEditor/ui/ScriptEditorRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { PromptEvent } from "../../ui/React/PromptManager";

import { useRerender } from "../../ui/React/hooks";

import { dirty, getServerCode, makeModel } from "./utils";
import { isUnsavedFile, getServerCode, makeModel } from "./utils";
import { OpenScript } from "./OpenScript";
import { Tabs } from "./Tabs";
import { Toolbar } from "./Toolbar";
Expand All @@ -38,6 +38,9 @@ import { RamCalculationErrorCode } from "../../Script/RamCalculationErrorCodes";
import { hasScriptExtension, isLegacyScript, type ScriptFilePath } from "../../Paths/ScriptFilePath";
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
import type { BaseServer } from "../../Server/BaseServer";
import { SpecialServers } from "../../Server/data/SpecialServers";
import { SnackbarEvents } from "../../ui/React/Snackbar";
import { ToastVariant } from "@enums";

// Extend acorn-walk to support TypeScript nodes.
extendAcornWalkForTypeScriptNodes(walk.base);
Expand Down Expand Up @@ -206,13 +209,7 @@ function Root(props: IProps): React.ReactElement {

return;
}

const server = GetServer(currentScript.hostname);
if (server === null) throw new Error("Server should not be null but it is.");
server.writeToContentFile(currentScript.path, currentScript.code);
if (Settings.SaveGameOnFileSave) {
saveObject.saveGame().catch((error) => exceptionAlert(error));
}
saveScript(currentScript);
rerender();
}, [rerender]);

Expand Down Expand Up @@ -363,7 +360,13 @@ function Root(props: IProps): React.ReactElement {

function saveScript(scriptToSave: OpenScript): void {
const server = GetServer(scriptToSave.hostname);
if (!server) throw new Error("Server should not be null but it is.");
if (!server) {
throw new Error("Server should not be null but it is.");
}
// Show a warning message if the file is on a non-home server.
if (scriptToSave.hostname !== SpecialServers.Home) {
SnackbarEvents.emit("You saved a file on a non-home server!", ToastVariant.WARNING, 3000);
}
// This server helper already handles overwriting, etc.
server.writeToContentFile(scriptToSave.path, scriptToSave.code);
if (Settings.SaveGameOnFileSave) {
Expand Down Expand Up @@ -411,7 +414,7 @@ function Root(props: IProps): React.ReactElement {
const savedScriptCode = closingScript.code;
const wasCurrentScript = openScripts[index] === currentScript;

if (dirty(openScripts, index)) {
if (isUnsavedFile(openScripts, index)) {
PromptEvent.emit({
txt: `Do you want to save changes to ${closingScript.path} on ${closingScript.hostname}?`,
resolve: (result: boolean | string) => {
Expand Down
43 changes: 37 additions & 6 deletions src/ScriptEditor/ui/Tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { DraggableProvided } from "react-beautiful-dnd";

import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";

import SyncIcon from "@mui/icons-material/Sync";
import CloseIcon from "@mui/icons-material/Close";
Expand All @@ -11,9 +12,10 @@ import { Settings } from "../../Settings/Settings";

interface IProps {
provided: DraggableProvided;
title: string;
fullPath: string;
isActive: boolean;
isExternal: boolean;
isUnsaved: boolean;

onClick: () => void;
onClose: () => void;
Expand All @@ -24,7 +26,7 @@ const tabMargin = 5;
const tabIconWidth = 25;
const tabIconHeight = 38.5;

export function Tab({ provided, title, isActive, isExternal, onClick, onClose, onUpdate }: IProps) {
export function Tab({ provided, fullPath, isActive, isExternal, isUnsaved, onClick, onClose, onUpdate }: IProps) {
const colorProps = isActive
? {
background: Settings.theme.button,
Expand All @@ -37,8 +39,35 @@ export function Tab({ provided, title, isActive, isExternal, onClick, onClose, o
color: Settings.theme.secondary,
};

let tabTitle;
let tooltipTitle;
if (isUnsaved) {
// Show a blinking "*" character to notify the player that this file is dirtied.
tabTitle = (
<>
<Typography component="span" color={Settings.theme.warning}>
*{" "}
</Typography>
{fullPath}
</>
);
} else {
tabTitle = fullPath;
}

if (isExternal) {
colorProps.color = Settings.theme.info;
colorProps.color = Settings.theme.warning;
// Show a warning message if this file is on a non-home server.
tooltipTitle = (
<Typography component="span" color={Settings.theme.warning}>
{tabTitle}
<br />
This file is on a non-home server. You will lose all files on non-home servers when they are deleted or
recreated (install augmentations, soft reset, deleted by NS APIs, etc.).
</Typography>
);
} else {
tooltipTitle = tabTitle;
}
const iconButtonStyle = {
maxWidth: tabIconWidth,
Expand Down Expand Up @@ -71,20 +100,22 @@ export function Tab({ provided, title, isActive, isExternal, onClick, onClose, o
border: "1px solid " + Settings.theme.well,
}}
>
<Tooltip title={title}>
<Tooltip title={tooltipTitle}>
<Button
onClick={onClick}
onMouseDown={(e) => {
e.preventDefault();
if (e.button === 1) onClose();
if (e.button === 1) {
onClose();
}
}}
style={{
minHeight: tabIconHeight,
overflow: "hidden",
...colorProps,
}}
>
<span style={{ overflow: "hidden", direction: "rtl", textOverflow: "ellipsis" }}>{title}</span>
<span style={{ overflow: "hidden", textOverflow: "ellipsis" }}>{tabTitle}</span>
</Button>
</Tooltip>
<Tooltip title="Overwrite editor content with saved file content">
Expand Down
19 changes: 7 additions & 12 deletions src/ScriptEditor/ui/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import SearchIcon from "@mui/icons-material/Search";
import { useBoolean, useRerender } from "../../ui/React/hooks";
import { Settings } from "../../Settings/Settings";

import { dirty, reorder } from "./utils";
import { isUnsavedFile, reorder } from "./utils";
import { OpenScript } from "./OpenScript";
import { Tab } from "./Tab";
import { SpecialServers } from "../../Server/data/SpecialServers";

const tabsMaxWidth = 1640;
const searchWidth = 180;
Expand Down Expand Up @@ -119,22 +120,16 @@ export function Tabs({ scripts, currentScript, onTabClick, onTabClose, onTabUpda
{filteredScripts.map(({ script, originalIndex }, index) => {
const { path: fileName, hostname } = script;
const isActive = currentScript?.path === script.path && currentScript.hostname === script.hostname;

const title = `${hostname}:~${fileName.startsWith("/") ? "" : "/"}${fileName} ${dirty(scripts, index)}`;

const fullPath = `${hostname}:/${fileName}`;
return (
<Draggable
key={fileName + hostname}
draggableId={fileName + hostname}
index={index}
disableInteractiveElementBlocking
>
<Draggable key={fullPath} draggableId={fullPath} index={index} disableInteractiveElementBlocking>
{(provided) => (
<Tab
provided={provided}
title={title}
fullPath={fullPath}
isActive={isActive}
isExternal={hostname !== "home"}
isExternal={hostname !== SpecialServers.Home}
isUnsaved={isUnsavedFile(scripts, index)}
onClick={() => onTabClick(originalIndex)}
onClose={() => onTabClose(originalIndex)}
onUpdate={() => onTabUpdate(originalIndex)}
Expand Down
10 changes: 6 additions & 4 deletions src/ScriptEditor/ui/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ function getServerCode(scripts: OpenScript[], index: number): string | null {
return data;
}

function dirty(scripts: OpenScript[], index: number): string {
function isUnsavedFile(scripts: OpenScript[], index: number): boolean {
const openScript = scripts[index];
const serverData = getServerCode(scripts, index);
if (serverData === null) return " *";
return serverData !== openScript.code ? " *" : "";
if (serverData === null) {
return true;
}
return serverData !== openScript.code;
}

function reorder(list: unknown[], startIndex: number, endIndex: number): void {
Expand Down Expand Up @@ -60,4 +62,4 @@ function makeModel(hostname: string, filename: string, code: string): editor.ITe
return editor.createModel(code, language, uri);
}

export { getServerCode, dirty, reorder, makeModel };
export { getServerCode, isUnsavedFile, reorder, makeModel };

0 comments on commit 63d7061

Please sign in to comment.