This is an automated email from the ASF dual-hosted git repository.
jscheffl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new c692b0836b0 Trim the oversized text in the variables table and
Implement variables view (#45401)
c692b0836b0 is described below
commit c692b0836b0db0df2b3352cc067c565603c7bfac
Author: Shubham Raj <[email protected]>
AuthorDate: Sun Jan 5 15:44:00 2025 +0530
Trim the oversized text in the variables table and Implement variables view
(#45401)
* trim text component
* fix
* reviews
---
.../ManageVariable/DeleteVariableButton.tsx | 2 +-
airflow/ui/src/pages/Variables/Variables.tsx | 4 +
airflow/ui/src/utils/TrimText.tsx | 118 +++++++++++++++++++++
3 files changed, 123 insertions(+), 1 deletion(-)
diff --git
a/airflow/ui/src/pages/Variables/ManageVariable/DeleteVariableButton.tsx
b/airflow/ui/src/pages/Variables/ManageVariable/DeleteVariableButton.tsx
index c53dc77c670..d8d2efbecae 100644
--- a/airflow/ui/src/pages/Variables/ManageVariable/DeleteVariableButton.tsx
+++ b/airflow/ui/src/pages/Variables/ManageVariable/DeleteVariableButton.tsx
@@ -63,7 +63,7 @@ const DeleteVariableButton = ({ deleteKey: variableKey }:
Props) => {
<Dialog.Content backdrop>
<Dialog.Header>
<VStack align="start" gap={4}>
- <Heading size="xl">Delete Variable - {variableKey} </Heading>
+ <Heading size="xl">Delete Variable</Heading>
</VStack>
</Dialog.Header>
diff --git a/airflow/ui/src/pages/Variables/Variables.tsx
b/airflow/ui/src/pages/Variables/Variables.tsx
index 6f46deca343..bfe266a21a5 100644
--- a/airflow/ui/src/pages/Variables/Variables.tsx
+++ b/airflow/ui/src/pages/Variables/Variables.tsx
@@ -33,6 +33,7 @@ import { Button, Tooltip } from "src/components/ui";
import { ActionBar } from "src/components/ui/ActionBar";
import { Checkbox } from "src/components/ui/Checkbox";
import { SearchParamsKeys, type SearchParamsKeysType } from
"src/constants/searchParams";
+import { TrimText } from "src/utils/TrimText";
import ImportVariablesButton from "./ImportVariablesButton";
import AddVariableButton from "./ManageVariable/AddVariableButton";
@@ -63,14 +64,17 @@ const getColumns = ({
},
{
accessorKey: "key",
+ cell: ({ row }) => <TrimText isClickable onClickContent={row.original}
text={row.original.key} />,
header: "Key",
},
{
accessorKey: "value",
+ cell: ({ row }) => <TrimText showTooltip text={row.original.value} />,
header: "Value",
},
{
accessorKey: "description",
+ cell: ({ row }) => <TrimText showTooltip text={row.original.description}
/>,
header: "Description",
},
{
diff --git a/airflow/ui/src/utils/TrimText.tsx
b/airflow/ui/src/utils/TrimText.tsx
new file mode 100644
index 00000000000..d9cdb5ae002
--- /dev/null
+++ b/airflow/ui/src/utils/TrimText.tsx
@@ -0,0 +1,118 @@
+/*!
+ * 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 { Text, Box, useDisclosure, Heading, Stack } from "@chakra-ui/react";
+
+import { Dialog, Tooltip } from "src/components/ui";
+
+import { capitalize } from "./capitalize";
+
+const formatKey = (key: string): string => {
+ const formatted = capitalize(key).replaceAll("_", " ");
+
+ return formatted;
+};
+
+type TrimTextProps = {
+ readonly charLimit?: number;
+ readonly isClickable?: boolean;
+ readonly onClickContent?: Record<string, boolean | number | string | null>;
+ readonly showTooltip?: boolean;
+ readonly text: string | null;
+};
+
+export const TrimText = ({
+ charLimit = 50,
+ isClickable = false,
+ onClickContent,
+ showTooltip = false,
+ text,
+}: TrimTextProps) => {
+ const safeText = text ?? "";
+ const isTrimmed = safeText.length > charLimit;
+ const trimmedText = isTrimmed ? `${safeText.slice(0, charLimit)}...` :
safeText;
+
+ const { onClose, onOpen, open } = useDisclosure();
+
+ return (
+ <>
+ <Tooltip
+ content={showTooltip && isTrimmed ? safeText : undefined}
+ disabled={!isTrimmed || !showTooltip}
+ >
+ <Box
+ _hover={isClickable ? { textDecoration: "underline" } : undefined}
+ as={isClickable ? "button" : "span"}
+ color={isClickable ? "fg.info" : undefined}
+ cursor={isClickable ? "pointer" : "default"}
+ fontWeight={isClickable ? "bold" : undefined}
+ onClick={onOpen}
+ >
+ <Text>{trimmedText}</Text>
+ </Box>
+ </Tooltip>
+
+ <Dialog.Root onOpenChange={onClose} open={isClickable ? open :
undefined} size="xl">
+ <Dialog.Content backdrop>
+ <Dialog.Header>
+ <Heading size="xl">Details</Heading>
+ </Dialog.Header>
+
+ <Dialog.CloseTrigger />
+
+ <Dialog.Body>
+ <Stack gap={4}>
+ {onClickContent ? (
+ Object.entries(onClickContent).map(([key, value]) => {
+ const formattedKey = formatKey(key);
+ const isEmpty = value === "" || value === null;
+
+ return (
+ <Box key={key}>
+ <Text fontWeight="bold" mb={2}>
+ {formattedKey}
+ </Text>
+ <Box
+ bg="gray.subtle"
+ borderRadius="md"
+ maxHeight={200}
+ overflow="auto"
+ overflowWrap="break-word"
+ p={4}
+ whiteSpace="pre-wrap"
+ >
+ <Text
+ color={isEmpty ? "gray.emphasized" : undefined}
+ fontWeight={isEmpty ? "bold" : "normal"}
+ >
+ {isEmpty ? "Empty" : String(value)}
+ </Text>
+ </Box>
+ </Box>
+ );
+ })
+ ) : (
+ <Text>No content available.</Text>
+ )}
+ </Stack>
+ </Dialog.Body>
+ </Dialog.Content>
+ </Dialog.Root>
+ </>
+ );
+};