diff --git a/packages/web_ui/src/components/ModsPage.tsx b/packages/web_ui/src/components/ModsPage.tsx index e380bcb5..7b2e85ed 100644 --- a/packages/web_ui/src/components/ModsPage.tsx +++ b/packages/web_ui/src/components/ModsPage.tsx @@ -56,11 +56,13 @@ function ImportModPackButton() { name="string" rules={[ { required: true }, - { async validator(rule, value) { - if (value) { - lib.ModPack.fromModPackString(value); - } - }}, + { + async validator(rule, value) { + if (value) { + lib.ModPack.fromModPackString(value); + } + }, + }, ]} > @@ -236,54 +238,118 @@ export default function ModsPage() { })} /> - ( - strcmp(a.name, b.name) || a.integerVersion - b.integerVersion - ), - }, - { - title: "Version", - key: "version", - align: "right", - render: (_, mod) => <> - {`${mod.version} `} - {`/ ${mod.factorioVersion}`} - , - }, - { - title: "Filename", - dataIndex: "filename", - responsive: ["xl"], - sorter: (a, b) => strcmp(a.filename, b.filename), - }, - { - title: "Size", - key: "size", - responsive: ["lg"], - render: (_, mod) => lib.formatBytes(mod.size), - align: "right", - sorter: (a, b) => a.size - b.size, - }, - { - title: "Action", - key: "action", - responsive: ["lg"], - render: (_, mod) => actions(mod), - }, - ]} - expandable={{ - expandedRowRender: (mod: lib.ModInfo) => , - expandedRowClassName: () => "no-expanded-padding", + + mod.id} - /> + action={`${webRoot}api/upload-mod`} + showUploadList={false} + > +
{ + setIsDroppingFile(true); + }} + onDragLeave={e => { + if ((e.currentTarget as Node).contains(e.relatedTarget as Node)) { + return; + } + setIsDroppingFile(false); + }} + onDrop={e => setIsDroppingFile(false)} + > +
+
+ +

+ Drop to upload +

+
+
+
( + strcmp(a.name, b.name) || a.integerVersion - b.integerVersion + ), + }, + { + title: "Version", + key: "version", + align: "right", + render: (_, mod) => <> + {`${mod.version} `} + {`/ ${mod.factorioVersion}`} + , + }, + { + title: "Filename", + dataIndex: "filename", + responsive: ["xl"], + sorter: (a, b) => strcmp(a.filename, b.filename), + }, + { + title: "Size", + key: "size", + responsive: ["lg"], + render: (_, mod) => lib.formatBytes(mod.size), + align: "right", + sorter: (a, b) => a.size - b.size, + }, + { + title: "Action", + key: "action", + responsive: ["lg"], + render: (_, mod) => actions(mod), + }, + ]} + expandable={{ + expandedRowRender: (mod: lib.ModInfo) => , + expandedRowClassName: () => "no-expanded-padding", + }} + dataSource={[...mods.values()]} + pagination={false} + rowKey={mod => mod.id} + /> + + ; } diff --git a/packages/web_ui/src/components/SavesList.tsx b/packages/web_ui/src/components/SavesList.tsx index 92ce287c..66f4f78d 100644 --- a/packages/web_ui/src/components/SavesList.tsx +++ b/packages/web_ui/src/components/SavesList.tsx @@ -15,6 +15,7 @@ import SectionHeader from "./SectionHeader"; import { useInstances } from "../model/instance"; import { useSavesOfInstance } from "../model/saves"; import { notifyErrorHandler } from "../util/notify"; +import { InboxOutlined } from "@ant-design/icons"; type ModalProps = { @@ -150,7 +151,7 @@ function TransferModal(props: ModalProps) { autoFocus showSearch filterOption={(input, option) => ( - (option?.title.toLowerCase().indexOf(input.toLowerCase())??-1) >= 0 + (option?.title.toLowerCase().indexOf(input.toLowerCase()) ?? -1) >= 0 )} > {[...instances.values()].filter( @@ -204,6 +205,7 @@ export default function SavesList(props: { instance: lib.InstanceDetails }) { let [saves] = useSavesOfInstance(props.instance.id); let [starting, setStarting] = useState(false); let [uploadingFiles, setUploadingFiles] = useState([]); + const [isDroppingFile, setIsDroppingFile] = useState(false); let hostOffline = ["unassigned", "unknown"].includes(props.instance.status!); const saveTable =
<> {save.name} - {save.loaded && } - {save.loadByDefault && } + {save.loaded && } + {save.loadByDefault && } , sorter: (a, b) => a.name.localeCompare(b.name), }, @@ -240,7 +242,7 @@ export default function SavesList(props: { instance: lib.InstanceDetails }) { expandable={{ columnWidth: 33, expandRowByClick: true, - expandedRowRender: save => + expandedRowRender: save => {account.hasPermission("core.instance.start") &&