mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 15:04:52 +09:00
The button offered Stop while the instance was starting whenever the start came from somewhere else, such as Load save, another tab or ctl. It now shows the action in progress as loading until the status settles. Kill stays available from the dropdown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
134 lines
3.7 KiB
TypeScript
134 lines
3.7 KiB
TypeScript
import React, { useContext, useState } from "react";
|
|
import { Popconfirm } from "antd";
|
|
|
|
import * as lib from "@clusterio/lib";
|
|
|
|
import ControlContext from "./ControlContext";
|
|
import { useAccount } from "../model/account";
|
|
import { notifyErrorHandler } from "../util/notify";
|
|
import VariableDropdownButton, { VariableDropdownButtonProps } from "./VariableDropdownButton";
|
|
|
|
type InstanceControlButtonProps = Omit<VariableDropdownButtonProps, "actions"> & {
|
|
instance: lib.InstanceDetails;
|
|
onFinish?: () => void;
|
|
};
|
|
|
|
export const InstanceControlButtonPermissions = [
|
|
"core.instance.start", "core.instance.restart", "core.instance.stop", "core.instance.kill",
|
|
] as const;
|
|
|
|
export default function InstanceControlButton(props: InstanceControlButtonProps) {
|
|
const account = useAccount();
|
|
const control = useContext(ControlContext);
|
|
const [switching, setSwitching] = useState<boolean>(false);
|
|
const [popconfirm, setPopconfirm] = useState<string | null>(null);
|
|
|
|
const instanceId = props.instance.id;
|
|
const instanceStatus = props.instance.status;
|
|
// While starting or stopping the button shows the action in progress as loading.
|
|
const showStart = ["stopped", "starting"].includes(instanceStatus);
|
|
const showStop = ["running", "stopping"].includes(instanceStatus);
|
|
const transitioning = ["starting", "stopping"].includes(instanceStatus);
|
|
|
|
function actionFinish() {
|
|
setSwitching(false);
|
|
if (props.onFinish) {
|
|
props.onFinish();
|
|
}
|
|
}
|
|
|
|
const actions: VariableDropdownButtonProps["actions"] = [];
|
|
|
|
if (account.hasPermission("core.instance.start") && showStart) {
|
|
actions.push({
|
|
key: "start",
|
|
label: "Start",
|
|
onClick: () => {
|
|
setSwitching(true);
|
|
control.sendTo(
|
|
{ instanceId },
|
|
new lib.InstanceStartRequest(undefined),
|
|
).catch(
|
|
notifyErrorHandler("Error starting instance")
|
|
).finally(actionFinish);
|
|
},
|
|
});
|
|
|
|
} else if (account.hasPermission("core.instance.stop")) { // else if because it is stop or start
|
|
actions.push({
|
|
key: "stop",
|
|
label: "Stop",
|
|
danger: true,
|
|
onClick: () => {
|
|
setSwitching(true);
|
|
control.sendTo(
|
|
{ instanceId },
|
|
new lib.InstanceStopRequest(),
|
|
).catch(
|
|
notifyErrorHandler("Error stopping instance")
|
|
).finally(actionFinish);
|
|
},
|
|
});
|
|
}
|
|
|
|
if (account.hasPermission("core.instance.restart")) {
|
|
actions.push({
|
|
key: "restart",
|
|
label: "Restart",
|
|
disabled: instanceStatus !== "running",
|
|
onClick: () => {
|
|
setSwitching(true);
|
|
control.sendTo(
|
|
{ instanceId },
|
|
new lib.InstanceRestartRequest(undefined),
|
|
).catch(
|
|
notifyErrorHandler("Error restarting instance")
|
|
).finally(actionFinish);
|
|
},
|
|
});
|
|
}
|
|
|
|
if (account.hasPermission("core.instance.kill")) {
|
|
actions.push({
|
|
key: "kill",
|
|
label: "Kill",
|
|
danger: true,
|
|
disabled: instanceStatus === "stopped",
|
|
onClick: () => setPopconfirm("kill"),
|
|
});
|
|
}
|
|
|
|
return <div style={{ position: "relative", display: "inline-block" }}>
|
|
<VariableDropdownButton
|
|
{...props}
|
|
type="primary"
|
|
actions={actions}
|
|
loading={switching || transitioning}
|
|
disabled={!(showStart || showStop)}
|
|
/>
|
|
<Popconfirm
|
|
title={<>
|
|
Killing this instance may leave you save and player data corrupted.
|
|
Are you sure you want to kill the instance?
|
|
</>}
|
|
open={popconfirm === "kill"}
|
|
placement="bottomRight"
|
|
okText="Kill"
|
|
okButtonProps={{ danger: true }}
|
|
onCancel={() => setPopconfirm(null)}
|
|
onConfirm={() => {
|
|
control.sendTo(
|
|
{ instanceId },
|
|
new lib.InstanceKillRequest(),
|
|
).catch(
|
|
notifyErrorHandler("Error killing instance")
|
|
).finally(actionFinish);
|
|
setPopconfirm(null);
|
|
}}
|
|
>
|
|
{/* Used to position the popup under the button */}
|
|
<span style={{ position: "absolute", right: 0, top: "100%", width: 1, height: 1 }} />
|
|
</Popconfirm>
|
|
</div>;
|
|
}
|