Line data Source code
1 43 : import React, { useState } from 'react';
2 :
3 : import { Alert } from "@patternfly/react-core/dist/esm/components/Alert";
4 : import { Button } from "@patternfly/react-core/dist/esm/components/Button";
5 : import { Divider } from '@patternfly/react-core/dist/esm/components/Divider/index.js';
6 : import { DropdownItem } from '@patternfly/react-core/dist/esm/components/Dropdown/index.js';
7 : import { List, ListItem } from "@patternfly/react-core/dist/esm/components/List";
8 : import {
9 : Modal
10 : } from '@patternfly/react-core/dist/esm/deprecated/components/Modal';
11 : import { Stack } from "@patternfly/react-core/dist/esm/layouts/Stack";
12 : import { KebabDropdown } from "cockpit-components-dropdown.jsx";
13 : import { useDialogs } from "dialogs.jsx";
14 :
15 : import cockpit from 'cockpit';
16 :
17 : import * as client from './client.js';
18 :
19 43 : const _ = cockpit.gettext;
20 :
21 1 : const PodDeleteModal = ({ con, pod }) => {
22 1 : const Dialogs = useDialogs();
23 1 : const [deleteError, setDeleteError] = useState(null);
24 1 : const [force, setForce] = useState(false);
25 :
26 0 : const containers = (pod.Containers || []).filter(ct => ct.Id !== pod.InfraId);
27 :
28 1 : function handlePodDelete() {
29 1 : client.delPod(con, pod.Id, force)
30 1 : .then(() => {
31 1 : Dialogs.close();
32 1 : })
33 1 : .catch(ex => {
34 1 : setDeleteError(ex.message);
35 1 : setForce(true);
36 1 : });
37 1 : }
38 :
39 1 : return (
40 1 : <Modal isOpen
41 1 : position="top" variant="medium"
42 1 : titleIconVariant="warning"
43 1 : title={force
44 1 : ? cockpit.format(_("Force delete pod $0?"), pod.Name)
45 1 : : cockpit.format(_("Delete pod $0?"), pod.Name)}
46 1 : onClose={Dialogs.close}
47 1 : footer={<>
48 1 : <Button variant="danger"
49 1 : onClick={handlePodDelete}>
50 1 : {force ? _("Force delete") : _("Delete")}
51 1 : </Button>
52 1 : {' '}
53 1 : <Button variant="link" onClick={Dialogs.close}>
54 1 : {_("Cancel")}
55 1 : </Button>
56 1 : </>}
57 : >
58 1 : {deleteError &&
59 1 : <Alert variant="danger" isInline title={_("An error occurred")}>{deleteError}</Alert>}
60 1 : {containers.length === 0 &&
61 1 : <p>{cockpit.format(_("Empty pod $0 will be permanently removed."), pod.Name)}</p>
62 : }
63 1 : {containers.length > 0 &&
64 1 : <Stack hasGutter>
65 1 : <p>{_("Deleting this pod will remove the following containers:")}</p>
66 1 : <List>
67 1 : {containers.map(container => <ListItem key={container.Names}>{container.Names}</ListItem>)}
68 1 : </List>
69 1 : </Stack>}
70 1 : </Modal>
71 : );
72 1 : };
73 :
74 10 : export const PodActions = ({ con, onAddNotification, pod, isPodService }) => {
75 10 : const Dialogs = useDialogs();
76 :
77 10 : const dropdownItems = [];
78 : // Possible Pod Statuses can be found here https://github.com/containers/podman/blob/main/libpod/define/podstate.go
79 4 : if (pod.Status == "Running" || pod.Status == "Paused") {
80 6 : dropdownItems.push(
81 6 : <DropdownItem key="action-stop"
82 6 : className="pod-action-stop"
83 1 : onClick={() =>
84 1 : client.postPod(con, "stop", pod.Id, {})
85 0 : .catch(ex => {
86 0 : const error = cockpit.format(_("Failed to stop pod $0"), pod.Name);
87 0 : onAddNotification({ type: 'danger', error, errorDetail: ex.message });
88 0 : })}
89 6 : component="button">
90 6 : {_("Stop")}
91 6 : </DropdownItem>,
92 6 : <DropdownItem key="action-force-stop"
93 6 : className="pod-action-force-stop"
94 0 : onClick={() =>
95 0 : client.postPod(con, "stop", pod.Id, { t: 0 })
96 0 : .catch(ex => {
97 0 : const error = cockpit.format(_("Failed to force stop pod $0"), pod.Name);
98 0 : onAddNotification({ type: 'danger', error, errorDetail: ex.message });
99 0 : })}
100 6 : component="button">
101 6 : {_("Force stop")}
102 6 : </DropdownItem>,
103 6 : <DropdownItem key="action-restart"
104 6 : className="pod-action-restart"
105 1 : onClick={() =>
106 1 : client.postPod(con, "restart", pod.Id, {})
107 0 : .catch(ex => {
108 0 : const error = cockpit.format(_("Failed to restart pod $0"), pod.Name);
109 0 : onAddNotification({ type: 'danger', error, errorDetail: ex.message });
110 0 : })}
111 6 : component="button">
112 6 : {_("Restart")}
113 6 : </DropdownItem>,
114 6 : <DropdownItem key="action-force-restart"
115 6 : className="pod-action-force-restart"
116 0 : onClick={() =>
117 0 : client.postPod(con, "restart", pod.Id, { t: 0 })
118 0 : .catch(ex => {
119 0 : const error = cockpit.format(_("Failed to force restart pod $0"), pod.Name);
120 0 : onAddNotification({ type: 'danger', error, errorDetail: ex.message });
121 0 : })}
122 6 : component="button">
123 6 : {_("Force restart")}
124 6 : </DropdownItem>,
125 6 : );
126 6 : }
127 4 : if (pod.Status == "Created" || pod.Status == "Exited" || pod.Status == "Stopped") {
128 6 : dropdownItems.push(
129 6 : <DropdownItem key="action-start"
130 6 : className="pod-action-start"
131 1 : onClick={() =>
132 1 : client.postPod(con, "start", pod.Id, {})
133 0 : .catch(ex => {
134 0 : const error = cockpit.format(_("Failed to start pod $0"), pod.Name);
135 0 : onAddNotification({ type: 'danger', error, errorDetail: ex.message });
136 0 : })}
137 6 : component="button">
138 6 : {_("Start")}
139 6 : </DropdownItem>,
140 6 : );
141 6 : }
142 1 : if (pod.Status == "Paused") {
143 1 : dropdownItems.push(
144 1 : <DropdownItem key="action-unpause"
145 1 : className="pod-action-unpause"
146 1 : onClick={() =>
147 1 : client.postPod(con, "unpause", pod.Id, {})
148 0 : .catch(ex => {
149 0 : const error = cockpit.format(_("Failed to resume pod $0"), pod.Name);
150 0 : onAddNotification({ type: 'danger', error, errorDetail: ex.message });
151 0 : })}
152 1 : component="button">
153 1 : {_("Resume")}
154 1 : </DropdownItem>,
155 1 : );
156 1 : }
157 6 : if (pod.Status == "Running") {
158 6 : dropdownItems.push(
159 6 : <DropdownItem key="action-pause"
160 6 : className="pod-action-pause"
161 1 : onClick={() =>
162 1 : client.postPod(con, "pause", pod.Id, {})
163 0 : .catch(ex => {
164 0 : const error = cockpit.format(_("Failed to pause pod $0"), pod.Name);
165 0 : onAddNotification({ type: 'danger', error, errorDetail: ex.message });
166 0 : })}
167 6 : component="button">
168 6 : {_("Pause")}
169 6 : </DropdownItem>,
170 6 : );
171 6 : }
172 :
173 6 : if (dropdownItems.length > 1) {
174 6 : dropdownItems.push(<Divider key="separator-1" />);
175 6 : }
176 10 : dropdownItems.push(
177 10 : <DropdownItem key="action-delete"
178 10 : className="pod-action-delete pf-m-danger"
179 1 : onClick={() => {
180 1 : Dialogs.show(<PodDeleteModal con={con} pod={pod} />);
181 1 : }}
182 10 : component="button">
183 10 : {_("Delete")}
184 10 : </DropdownItem>,
185 10 : );
186 :
187 10 : if (!dropdownItems.length)
188 0 : return null;
189 :
190 10 : return (
191 10 : <KebabDropdown
192 2 : toggleButtonId={"pod-" + pod.Name + (pod.uid === 0 ? "-system" : "-user") + "-action-toggle"}
193 10 : position="right"
194 10 : dropdownItems={dropdownItems}
195 10 : isDisabled={isPodService}
196 10 : />
197 : );
198 10 : };
|