Skip to content

Commit a5bb34f

Browse files
Add edit pool button (apache#46998)
1 parent a369c6d commit a5bb34f

File tree

4 files changed

+180
-2
lines changed

4 files changed

+180
-2
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*!
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
import { Heading, useDisclosure } from "@chakra-ui/react";
20+
import { FiEdit } from "react-icons/fi";
21+
22+
import type { PoolResponse } from "openapi/requests/types.gen";
23+
import { Dialog } from "src/components/ui";
24+
import ActionButton from "src/components/ui/ActionButton";
25+
import { useEditPool } from "src/queries/useEditPool";
26+
27+
import PoolForm, { type PoolBody } from "./PoolForm";
28+
29+
type Props = {
30+
readonly pool: PoolResponse;
31+
};
32+
33+
const EditPoolButton = ({ pool }: Props) => {
34+
const { onClose, onOpen, open } = useDisclosure();
35+
const initialPoolValue: PoolBody = {
36+
description: pool.description ?? "",
37+
include_deferred: pool.include_deferred,
38+
name: pool.name,
39+
slots: pool.slots,
40+
};
41+
const { editPool, error, isPending, setError } = useEditPool(initialPoolValue, {
42+
onSuccessConfirm: onClose,
43+
});
44+
45+
const handleClose = () => {
46+
setError(undefined);
47+
onClose();
48+
};
49+
50+
return (
51+
<>
52+
<ActionButton
53+
actionName="Edit Pool"
54+
icon={<FiEdit />}
55+
onClick={() => {
56+
onOpen();
57+
}}
58+
text="Edit Pool"
59+
withText={false}
60+
/>
61+
62+
<Dialog.Root onOpenChange={handleClose} open={open} size="xl">
63+
<Dialog.Content backdrop>
64+
<Dialog.Header>
65+
<Heading size="xl">Edit Pool</Heading>
66+
</Dialog.Header>
67+
68+
<Dialog.CloseTrigger />
69+
70+
<Dialog.Body>
71+
<PoolForm
72+
error={error}
73+
initialPool={initialPoolValue}
74+
isPending={isPending}
75+
manageMutate={editPool}
76+
setError={setError}
77+
/>
78+
</Dialog.Body>
79+
</Dialog.Content>
80+
</Dialog.Root>
81+
</>
82+
);
83+
};
84+
85+
export default EditPoolButton;

airflow/ui/src/pages/Pools/PoolBar.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { Tooltip } from "src/components/ui";
2727
import { capitalize } from "src/utils";
2828

2929
import DeletePoolButton from "./DeletePoolButton";
30+
import EditPoolButton from "./EditPoolButton";
3031

3132
const slots = {
3233
open_slots: { color: "success", icon: <StateIcon color="white" state="success" /> },
@@ -54,7 +55,10 @@ const PoolBar = ({ pool }: PoolBarProps) => (
5455
</Tooltip>
5556
) : undefined}
5657
</Text>
57-
{pool.name === "default_pool" ? undefined : <DeletePoolButton poolName={pool.name} />}
58+
<HStack gap={0}>
59+
<EditPoolButton pool={pool} />
60+
{pool.name === "default_pool" ? undefined : <DeletePoolButton poolName={pool.name} />}
61+
</HStack>
5862
</HStack>
5963
{pool.description ?? (
6064
<Text color="gray.fg" fontSize="sm">

airflow/ui/src/pages/Pools/PoolForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ const PoolForm = ({ error, initialPool, isPending, manageMutate, setError }: Poo
9696
render={({ field }) => (
9797
<Field.Root mb={4} mt={4}>
9898
<Field.Label fontSize="md">Description</Field.Label>
99-
<Textarea {...field} size="sm" />
99+
<Textarea {...field} disabled={initialPool.name === "default_pool"} size="sm" />
100100
</Field.Root>
101101
)}
102102
/>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*!
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
import { useQueryClient } from "@tanstack/react-query";
20+
import { useState } from "react";
21+
22+
import { usePoolServiceGetPoolsKey, usePoolServicePatchPool } from "openapi/queries";
23+
import type { PoolBody } from "openapi/requests/types.gen";
24+
import { toaster } from "src/components/ui";
25+
26+
export const useEditPool = (
27+
initialPool: PoolBody,
28+
{
29+
onSuccessConfirm,
30+
}: {
31+
onSuccessConfirm: () => void;
32+
},
33+
) => {
34+
const queryClient = useQueryClient();
35+
const [error, setError] = useState<unknown>(undefined);
36+
37+
const onSuccess = async () => {
38+
await queryClient.invalidateQueries({
39+
queryKey: [usePoolServiceGetPoolsKey],
40+
});
41+
42+
toaster.create({
43+
description: "Pool has been edited successfully",
44+
title: "Pool Edit Request Submitted",
45+
type: "success",
46+
});
47+
48+
onSuccessConfirm();
49+
};
50+
51+
const onError = (_error: unknown) => {
52+
setError(_error);
53+
};
54+
55+
const { isPending, mutate } = usePoolServicePatchPool({
56+
onError,
57+
onSuccess,
58+
});
59+
60+
const editPool = (editPoolRequestBody: PoolBody) => {
61+
const updateMask: Array<string> = [];
62+
63+
if (editPoolRequestBody.slots !== initialPool.slots) {
64+
updateMask.push("slots");
65+
}
66+
if (editPoolRequestBody.description !== initialPool.description) {
67+
updateMask.push("description");
68+
}
69+
if (editPoolRequestBody.include_deferred !== initialPool.include_deferred) {
70+
updateMask.push("include_deferred");
71+
}
72+
73+
const parsedDescription =
74+
editPoolRequestBody.description === "" ? undefined : editPoolRequestBody.description;
75+
76+
mutate({
77+
poolName: initialPool.name,
78+
requestBody: {
79+
description: parsedDescription,
80+
include_deferred: editPoolRequestBody.include_deferred,
81+
pool: editPoolRequestBody.name,
82+
slots: editPoolRequestBody.slots,
83+
},
84+
updateMask,
85+
});
86+
};
87+
88+
return { editPool, error, isPending, setError };
89+
};

0 commit comments

Comments
 (0)