Skip to content

Commit

Permalink
Merge pull request clusterio#602 from Danielv123/react-to-drag-and-drop
Browse files Browse the repository at this point in the history
React to drag and drop
  • Loading branch information
Danielv123 authored May 18, 2024
2 parents 201209e + c6abe29 commit 7489a76
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 116 deletions.
51 changes: 51 additions & 0 deletions packages/web_ui/src/components/Dropzone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { InboxOutlined } from "@ant-design/icons";
import { DraggingContext } from "../model/is_dragging";
import { useContext } from "react";

// This component is used to display a dropzone when a file is being dragged over the parent component
export function Dropzone({ disabled = false }: { disabled?: boolean }) {
const isDroppingFile = useContext(DraggingContext);

const textStyle: { color?: string } = {};
let text = "Drop to upload";
if (disabled) {
textStyle.color = "red";
text = "Target is offline";
}
const borderColor = disabled ? "gray" : "rgb(22, 119, 255)";

return <div
className={`dropzone ${disabled ? "disabled" : "enabled"}`} // Don't remove this class, linked to SiteLayout
style={{
position: "absolute",
top: "0",
left: "0",
width: "100%",
height: "100%",
zIndex: "90",
backgroundColor: "#88888844",
borderRadius: "20px",
border: `dashed 2px ${borderColor}`,
display: isDroppingFile ? "block" : "none",
}}
>
<div
className="dropzone-icon"
style={{
fontSize: "72px",
color: "rgb(22, 119, 255)",
display: "flex",
zIndex: "100",
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
height: "100%",
}}
>
<InboxOutlined style={textStyle} />
<p style={{ ...textStyle, fontSize: "24px", display: "block", textAlign: "center", marginTop: "8px" }}>
{text}
</p>
</div>
</div>;
}
136 changes: 81 additions & 55 deletions packages/web_ui/src/components/ModsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useNavigate } from "react-router-dom";
import { Button, Form, Input, Modal, Popconfirm, Space, Table, Typography, Upload } from "antd";
import ImportOutlined from "@ant-design/icons/ImportOutlined";
import PlusOutlined from "@ant-design/icons/PlusOutlined";
import UploadOutlined from "@ant-design/icons/UploadOutlined";

import * as lib from "@clusterio/lib";

Expand All @@ -17,6 +16,8 @@ import PageLayout from "./PageLayout";
import PluginExtra from "./PluginExtra";
import SectionHeader from "./SectionHeader";
import ModDetails from "./ModDetails";
import { Dropzone } from "./Dropzone";
import UploadButton from "./UploadButton";

const strcmp = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare;

Expand Down Expand Up @@ -55,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);
}
},
},
]}
>
<Input.TextArea autoSize={{ minRows: 6, maxRows: 6 }} />
Expand Down Expand Up @@ -172,12 +175,13 @@ export default function ModsPage() {
name="file"
accept=".zip"
multiple
showUploadList={false}
headers={{
"X-Access-Token": control.connector.token||"",
"X-Access-Token": control.connector.token || "",
}}
action={`${webRoot}api/upload-mod`}
>
<Button icon={<UploadOutlined/>}>Upload</Button>
<UploadButton />
</Upload>;
}

Expand Down Expand Up @@ -219,54 +223,76 @@ export default function ModsPage() {
})}
/>
<SectionHeader title="Stored Mods" extra={uploadButton} />
<Table
columns={[
{
title: "Name",
dataIndex: "title",
defaultSortOrder: "ascend",
sorter: (a, b) => (
strcmp(a.name, b.name) || a.integerVersion - b.integerVersion
),
},
{
title: "Version",
key: "version",
align: "right",
render: (_, mod) => <>
{`${mod.version} `}
<Typography.Text type="secondary">{`/ ${mod.factorioVersion}`}</Typography.Text>
</>,
},
{
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) => <ModDetails mod={mod} actions={actions} />,
expandedRowClassName: () => "no-expanded-padding",

<Upload.Dragger
className="save-list-dragger"
openFileDialogOnClick={false}
name="file"
accept=".zip"
multiple
headers={{
"X-Access-Token": control.connector.token || "",
}}
dataSource={[...mods.values()]}
pagination={false}
rowKey={mod => mod.id}
/>
action={`${webRoot}api/upload-mod`}
showUploadList={false}
>
<div
style={{
position: "relative",
zIndex: "1010",
}}
>
<Dropzone />
<Table
columns={[
{
title: "Name",
dataIndex: "title",
defaultSortOrder: "ascend",
sorter: (a, b) => (
strcmp(a.name, b.name) || a.integerVersion - b.integerVersion
),
},
{
title: "Version",
key: "version",
align: "right",
render: (_, mod) => <>
{`${mod.version} `}
<Typography.Text type="secondary">{`/ ${mod.factorioVersion}`}</Typography.Text>
</>,
},
{
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) => <ModDetails mod={mod} actions={actions} />,
expandedRowClassName: () => "no-expanded-padding",
}}
dataSource={[...mods.values()]}
pagination={false}
rowKey={mod => mod.id}
/>
</div>
</Upload.Dragger>
<PluginExtra component="ModsPage" />
</PageLayout>;
}
26 changes: 19 additions & 7 deletions packages/web_ui/src/components/SavesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import SectionHeader from "./SectionHeader";
import { useInstances } from "../model/instance";
import { useSavesOfInstance } from "../model/saves";
import { notifyErrorHandler } from "../util/notify";
import { Dropzone } from "./Dropzone";
import UploadButton from "./UploadButton";


type ModalProps = {
Expand Down Expand Up @@ -150,7 +152,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(
Expand Down Expand Up @@ -214,8 +216,8 @@ export default function SavesList(props: { instance: lib.InstanceDetails }) {
title: "Name",
render: (_, save) => <>
{save.name}
{save.loaded && <Tooltip title="Currently loaded save"><CaretLeftOutlined/></Tooltip>}
{save.loadByDefault && <Tooltip title="Save loaded by default"><LeftOutlined/></Tooltip>}
{save.loaded && <Tooltip title="Currently loaded save"><CaretLeftOutlined /></Tooltip>}
{save.loadByDefault && <Tooltip title="Save loaded by default"><LeftOutlined /></Tooltip>}
</>,
sorter: (a, b) => a.name.localeCompare(b.name),
},
Expand All @@ -240,7 +242,7 @@ export default function SavesList(props: { instance: lib.InstanceDetails }) {
expandable={{
columnWidth: 33,
expandRowByClick: true,
expandedRowRender: save => <Space wrap style={{marginBottom: 0}}>
expandedRowRender: save => <Space wrap style={{ marginBottom: 0 }}>
{account.hasPermission("core.instance.start") && <Button
loading={starting}
disabled={props.instance.status !== "stopped"}
Expand Down Expand Up @@ -346,14 +348,24 @@ export default function SavesList(props: { instance: lib.InstanceDetails }) {
return <div>
<SectionHeader title="Saves" extra={<Space>
{account.hasPermission("core.instance.save.upload") && <Upload {...uploadProps} >
<Button disabled={hostOffline}>Upload save</Button>
<UploadButton disabled={hostOffline}>
Upload save
</UploadButton>
</Upload>}
{account.hasPermission("core.instance.save.create") && <CreateSaveModal instance={props.instance} />}
</Space>} />
{
account.hasPermission("core.instance.save.upload")
? <Upload.Dragger className="save-list-dragger" openFileDialogOnClick={false} {...uploadProps}>
{saveTable}
<div
style={{
position: "relative",
zIndex: "1010",
}}
>
<Dropzone disabled={hostOffline} />
{saveTable}
</div>
</Upload.Dragger>
: saveTable
}
Expand All @@ -362,7 +374,7 @@ export default function SavesList(props: { instance: lib.InstanceDetails }) {
{file.name}
<Progress
percent={file.percent}
format={percent => `${Math.floor(percent||0)}%`}
format={percent => `${Math.floor(percent || 0)}%`}
status={file.status === "error" ? "exception" : "normal"}
/>
</List.Item>)}
Expand Down
Loading

0 comments on commit 7489a76

Please sign in to comment.