Skip to content

Commit

Permalink
Add variables (#44942)
Browse files Browse the repository at this point in the history
* add variables

* error

* description

* multi

* toaster

* use feild

* place error

* type and memo removal

* check length

* check req error
  • Loading branch information
shubhamraj-git authored Dec 24, 2024
1 parent f27eb71 commit f1167f4
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 1 deletion.
144 changes: 144 additions & 0 deletions airflow/ui/src/pages/Variables/AddVariableForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Box, Field, HStack, Input, Spacer, Textarea } from "@chakra-ui/react";
import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { FiSave } from "react-icons/fi";

import { ErrorAlert } from "src/components/ErrorAlert";
import { Button } from "src/components/ui";
import { useAddVariable } from "src/queries/useAddVariable";

export type AddVariableBody = {
description: string | undefined;
key: string;
value: string;
};

type AddVariableFormProps = {
readonly onClose: () => void;
};

const AddVariableForm = ({ onClose }: AddVariableFormProps) => {
const { addVariable, error, isPending } = useAddVariable(onClose);

const {
control,
formState: { isDirty, isValid },
handleSubmit,
reset,
} = useForm<AddVariableBody>({
defaultValues: {
description: "",
key: "",
value: "",
},
mode: "onChange",
});

useEffect(() => {
reset({
description: "",
key: "",
value: "",
});
}, [reset]);

const onSubmit = (data: AddVariableBody) => {
addVariable(data);
};

return (
<>
<Controller
control={control}
name="key"
render={({ field, fieldState }) => (
<Field.Root invalid={Boolean(fieldState.error)} required>
<Field.Label fontSize="md">
Key <Field.RequiredIndicator />
</Field.Label>
<Input {...field} required size="sm" />
{fieldState.error ? (
<Field.ErrorText>{fieldState.error.message}</Field.ErrorText>
) : undefined}
</Field.Root>
)}
rules={{
required: "Key is required",
validate: (_value) =>
_value.length <= 250 ||
"Key can contain a maximum of 250 characters",
}}
/>

<Controller
control={control}
name="value"
render={({ field, fieldState }) => (
<Field.Root invalid={Boolean(fieldState.error)} mt={4} required>
<Field.Label fontSize="md">
Value <Field.RequiredIndicator />
</Field.Label>
<Textarea {...field} required size="sm" />
{fieldState.error ? (
<Field.ErrorText>{fieldState.error.message}</Field.ErrorText>
) : undefined}
</Field.Root>
)}
rules={{
required: "Value is required",
}}
/>

<Controller
control={control}
name="description"
render={({ field }) => (
<Field.Root mb={4} mt={4}>
<Field.Label fontSize="md">Description</Field.Label>
<Textarea {...field} size="sm" />
</Field.Root>
)}
/>

<ErrorAlert error={error} />

<Box as="footer" display="flex" justifyContent="flex-end" mt={8}>
<HStack w="full">
{isDirty ? (
<Button onClick={() => reset()} variant="outline">
Reset
</Button>
) : undefined}
<Spacer />
<Button
colorPalette="blue"
disabled={!isValid || isPending}
onClick={() => void handleSubmit(onSubmit)()}
>
<FiSave /> Save
</Button>
</HStack>
</Box>
</>
);
};

export default AddVariableForm;
52 changes: 52 additions & 0 deletions airflow/ui/src/pages/Variables/AddVariableModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Heading, useDisclosure } from "@chakra-ui/react";
import { FiPlusCircle } from "react-icons/fi";

import { Button, Dialog, Toaster } from "src/components/ui";

import AddVariableForm from "./AddVariableForm";

const AddVariableModal: React.FC = () => {
const { onClose, onOpen, open } = useDisclosure();

return (
<>
<Toaster />
<Button colorPalette="blue" onClick={onOpen}>
<FiPlusCircle /> Add Variable
</Button>
<Dialog.Root onOpenChange={onClose} open={open} size="xl">
<Dialog.Content backdrop>
<Dialog.Header>
<Heading size="xl">Add Variable</Heading>
</Dialog.Header>

<Dialog.CloseTrigger />

<Dialog.Body>
<AddVariableForm onClose={onClose} />
</Dialog.Body>
</Dialog.Content>
</Dialog.Root>
</>
);
};

export default AddVariableModal;
7 changes: 6 additions & 1 deletion airflow/ui/src/pages/Variables/Variables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { Box, VStack } from "@chakra-ui/react";
import { Box, HStack, VStack } from "@chakra-ui/react";
import type { ColumnDef } from "@tanstack/react-table";
import { useState } from "react";
import { useSearchParams } from "react-router-dom";
Expand All @@ -32,6 +32,8 @@ import {
type SearchParamsKeysType,
} from "src/constants/searchParams";

import AddVariableModal from "./AddVariableModal";

const columns: Array<ColumnDef<VariableResponse>> = [
{
accessorKey: "key",
Expand Down Expand Up @@ -104,6 +106,9 @@ export const Variables = () => {
onChange={handleSearchChange}
placeHolder="Search Keys"
/>
<HStack mt={4}>
<AddVariableModal />
</HStack>
</VStack>
<Box>
<DataTable
Expand Down
72 changes: 72 additions & 0 deletions airflow/ui/src/queries/useAddVariable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { useQueryClient } from "@tanstack/react-query";
import { useState } from "react";

import {
useVariableServiceGetVariablesKey,
useVariableServicePostVariable,
} from "openapi/queries";
import { toaster } from "src/components/ui";
import type { AddVariableBody } from "src/pages/Variables/AddVariableForm";

export const useAddVariable = (onClose: () => void) => {
const queryClient = useQueryClient();
const [error, setError] = useState<unknown>(undefined);

const onSuccess = async () => {
await queryClient.invalidateQueries({
queryKey: [useVariableServiceGetVariablesKey],
});

toaster.create({
description: "Variable has been added successfully",
title: "Variable Add Request Submitted",
type: "success",
});

onClose();
};

const onError = (_error: unknown) => {
setError(_error);
};

const { isPending, mutate } = useVariableServicePostVariable({
onError,
onSuccess,
});

const addVariable = (addVariableRequestBody: AddVariableBody) => {
const parsedDescription =
addVariableRequestBody.description === ""
? undefined
: addVariableRequestBody.description;

mutate({
requestBody: {
description: parsedDescription,
key: addVariableRequestBody.key,
value: addVariableRequestBody.value,
},
});
};

return { addVariable, error, isPending };
};

0 comments on commit f1167f4

Please sign in to comment.