This is an automated email from the ASF dual-hosted git repository. rahulvats pushed a commit to branch backport-61679 in repository https://gitbox.apache.org/repos/asf/airflow.git
commit f659e41c2f863e6cdb2ee9d85dccd339e17a0bc7 Author: Tomi <[email protected]> AuthorDate: Tue Feb 24 18:27:28 2026 +0200 UI variables page: added option to view text as multi lines (#61679) * Variables page added a button to set or unset text trim * ui variable page, fold and expand buttons: * reused expandCollapse component * used useDisclosure instead of useState * affect only the variable.value field * * Variable page fold/expand buttons affect also variable.description * tooltip text fixed * formatting issues resolved (cherry picked from commit 5764d69208ff39aa77ed9f43b16908e048ebc628) --- .../airflow/ui/src/pages/Variables/Variables.tsx | 101 ++++++++++++++++++++- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx b/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx index fdea3be2383..ab7c1e09945 100644 --- a/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx +++ b/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { Box, Flex, HStack, Spacer, VStack } from "@chakra-ui/react"; +import { Box, Flex, HStack, Spacer, useDisclosure, VStack } from "@chakra-ui/react"; import type { ColumnDef } from "@tanstack/react-table"; import type { TFunction } from "i18next"; import { useEffect, useMemo, useState } from "react"; @@ -30,6 +30,7 @@ import { DataTable } from "src/components/DataTable"; import { useRowSelection, type GetColumnsParams } from "src/components/DataTable/useRowSelection"; import { useTableURLState } from "src/components/DataTable/useTableUrlState"; import { ErrorAlert } from "src/components/ErrorAlert"; +import { ExpandCollapseButtons } from "src/components/ExpandCollapseButtons"; import { SearchBar } from "src/components/SearchBar"; import { Button, Tooltip } from "src/components/ui"; import { ActionBar } from "src/components/ui/ActionBar"; @@ -44,13 +45,19 @@ import AddVariableButton from "./ManageVariable/AddVariableButton"; import DeleteVariableButton from "./ManageVariable/DeleteVariableButton"; import EditVariableButton from "./ManageVariable/EditVariableButton"; +type ColumnProps = { + readonly open: boolean; + readonly translate: TFunction; +}; + const getColumns = ({ allRowsSelected, onRowSelect, onSelectAll, + open, selectedRows, translate, -}: { translate: TFunction } & GetColumnsParams): Array<ColumnDef<VariableResponse>> => [ +}: ColumnProps & GetColumnsParams): Array<ColumnDef<VariableResponse>> => [ { accessorKey: "select", cell: ({ row }) => ( @@ -109,6 +116,86 @@ const getColumns = ({ }, }, ]; +}: ColumnProps & GetColumnsParams): Array<ColumnDef<VariableResponse>> => { + const columns: Array<ColumnDef<VariableResponse>> = [ + { + accessorKey: "select", + cell: ({ row }) => ( + <Checkbox + borderWidth={1} + checked={selectedRows.get(row.original.key)} + colorPalette="brand" + onCheckedChange={(event) => onRowSelect(row.original.key, Boolean(event.checked))} + /> + ), + enableHiding: false, + enableSorting: false, + header: () => ( + <Checkbox + borderWidth={1} + checked={allRowsSelected} + colorPalette="brand" + onCheckedChange={(event) => onSelectAll(Boolean(event.checked))} + /> + ), + meta: { + skeletonWidth: 10, + }, + }, + { + accessorKey: "key", + cell: ({ row }) => <TrimText isClickable onClickContent={row.original} text={row.original.key} />, + header: translate("columns.key"), + }, + { + accessorKey: "value", + cell: ({ row }) => ( + <TrimText + charLimit={open ? row.original.value.length : undefined} + showTooltip + text={row.original.value} + /> + ), + header: translate("columns.value"), + }, + { + accessorKey: "description", + cell: ({ row }) => ( + <TrimText + charLimit={open ? row.original.description?.length : undefined} + showTooltip + text={row.original.description} + /> + ), + header: translate("columns.description"), + }, + { + accessorKey: "is_encrypted", + header: translate("variables.columns.isEncrypted"), + }, + ...(multiTeam + ? [ + { + accessorKey: "team_name", + header: translate("columns.team"), + }, + ] + : []), + { + accessorKey: "actions", + cell: ({ row: { original } }) => ( + <Flex justifyContent="end"> + <EditVariableButton disabled={selectedRows.size > 0} variable={original} /> + <DeleteVariableButton deleteKey={original.key} disabled={selectedRows.size > 0} /> + </Flex> + ), + enableSorting: false, + header: "", + meta: { + skeletonWidth: 10, + }, + }, + ]; export const Variables = () => { const { t: translate } = useTranslation("admin"); @@ -117,6 +204,7 @@ export const Variables = () => { sorting: [{ desc: false, id: "key" }], }); // To make multiselection smooth const [searchParams, setSearchParams] = useSearchParams(); + const { onClose, onOpen, open } = useDisclosure(); const { NAME_PATTERN, OFFSET }: SearchParamsKeysType = SearchParamsKeys; const [variableKeyPattern, setVariableKeyPattern] = useState(searchParams.get(NAME_PATTERN) ?? undefined); const [selectedVariables, setSelectedVariables] = useState<Record<string, string | undefined>>({}); @@ -143,10 +231,11 @@ export const Variables = () => { allRowsSelected, onRowSelect: handleRowSelect, onSelectAll: handleSelectAll, + open, selectedRows, translate, }), - [allRowsSelected, handleRowSelect, handleSelectAll, selectedRows, translate], + [allRowsSelected, handleRowSelect, handleSelectAll, open, selectedRows, translate], ); const handleSearchChange = (value: string) => { @@ -199,6 +288,12 @@ export const Variables = () => { <HStack gap={4} mt={2}> <ImportVariablesButton disabled={selectedRows.size > 0} /> <Spacer /> + <ExpandCollapseButtons + collapseLabel={translate("common:expand.collapse")} + expandLabel={translate("common:expand.expand")} + onCollapse={onClose} + onExpand={onOpen} + /> <AddVariableButton disabled={selectedRows.size > 0} /> </HStack> </VStack>
