Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* under the License.
*/
import { useDisclosure } from "@chakra-ui/react";
import { useTranslation } from "react-i18next";
import { FiTrash2 } from "react-icons/fi";
import { useNavigate } from "react-router-dom";

Expand All @@ -33,7 +34,7 @@ type DeleteDagButtonProps = {
const DeleteDagButton = ({ dagDisplayName, dagId, withText = true }: DeleteDagButtonProps) => {
const { onClose, onOpen, open } = useDisclosure();
const navigate = useNavigate();

const { t: translate } = useTranslation("dags");
const { isPending, mutate: deleteDag } = useDeleteDag({
dagId,
onSuccessConfirm: () => {
Expand All @@ -45,11 +46,11 @@ const DeleteDagButton = ({ dagDisplayName, dagId, withText = true }: DeleteDagBu
return (
<>
<ActionButton
actionName="Delete DAG"
actionName={translate("actions.delete")}
colorPalette="red"
icon={<FiTrash2 />}
onClick={onOpen}
text="Delete DAG"
text={translate("actions.delete")}
variant="solid"
withText={withText}
/>
Expand All @@ -60,8 +61,8 @@ const DeleteDagButton = ({ dagDisplayName, dagId, withText = true }: DeleteDagBu
onDelete={() => deleteDag({ dagId })}
open={open}
resourceName={dagDisplayName}
title="Delete DAG"
warningText="This will remove all metadata related to the DAG, including DAG Runs and Tasks."
title={translate("actions.delete")}
warningText={translate("actions.deleteDagWarning")}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
import { IconButton } from "@chakra-ui/react";
import { flexRender, type Header, type Table } from "@tanstack/react-table";
import { useTranslation } from "react-i18next";
import { MdFilterList } from "react-icons/md";

import { Menu } from "src/components/ui";
Expand All @@ -27,44 +28,43 @@ type Props<TData> = {
readonly table: Table<TData>;
};

const FilterMenuButton = <TData,>({ table }: Props<TData>) => (
<Menu.Root closeOnSelect={false} positioning={{ placement: "bottom" }}>
<Menu.Trigger asChild>
<IconButton
aria-label="Filter table columns"
margin={1}
padding={0}
title="Filter table columns"
variant="ghost"
>
<MdFilterList size="1" />
</IconButton>
</Menu.Trigger>
<Menu.Content>
{table.getAllLeafColumns().map((column) => {
const text = flexRender(column.columnDef.header, {
column,
header: { column } as Header<TData, unknown>,
table,
});
const FilterMenuButton = <TData,>({ table }: Props<TData>) => {
const { t: translate } = useTranslation("common");
const filterLabel = translate("table.filterColumns");

return text?.toString ? (
<Menu.Item asChild key={column.id} value={column.id}>
<Checkbox
checked={column.getIsVisible()}
// At least one item needs to be visible
disabled={table.getVisibleFlatColumns().length < 2 && column.getIsVisible()}
onChange={() => {
column.toggleVisibility();
}}
>
{text}
</Checkbox>
</Menu.Item>
) : undefined;
})}
</Menu.Content>
</Menu.Root>
);
return (
<Menu.Root closeOnSelect={false} positioning={{ placement: "bottom" }}>
<Menu.Trigger asChild>
<IconButton aria-label={filterLabel} margin={1} padding={0} title={filterLabel} variant="ghost">
<MdFilterList size="1" />
</IconButton>
</Menu.Trigger>
<Menu.Content>
{table.getAllLeafColumns().map((column) => {
const text = flexRender(column.columnDef.header, {
column,
header: { column } as Header<TData, unknown>,
table,
});

return text?.toString ? (
<Menu.Item asChild key={column.id} value={column.id}>
<Checkbox
checked={column.getIsVisible()}
// At least one item needs to be visible
disabled={table.getVisibleFlatColumns().length < 2 && column.getIsVisible()}
onChange={() => {
column.toggleVisibility();
}}
>
{text}
</Checkbox>
</Menu.Item>
) : undefined;
})}
</Menu.Content>
</Menu.Root>
);
};

export default FilterMenuButton;
62 changes: 33 additions & 29 deletions airflow-core/src/airflow/ui/src/components/DeleteDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
import { Text, Heading, HStack } from "@chakra-ui/react";
import React from "react";
import { useTranslation } from "react-i18next";
import { FiTrash2 } from "react-icons/fi";

import { Button, Dialog } from "src/components/ui";
Expand All @@ -34,41 +35,44 @@ type DeleteDialogProps = {
};

const DeleteDialog: React.FC<DeleteDialogProps> = ({
deleteButtonText = "Delete",
deleteButtonText,
isDeleting,
onClose,
onDelete,
open,
resourceName,
title,
warningText,
}) => (
<Dialog.Root lazyMount onOpenChange={onClose} open={open} size="md" unmountOnExit>
<Dialog.Content backdrop>
<Dialog.Header>
<Heading size="lg">{title}</Heading>
</Dialog.Header>
<Dialog.CloseTrigger />
<Dialog.Body>
<Text>
Are you sure you want to delete <strong>{resourceName}</strong>? This action cannot be undone.
</Text>
<Text color="red.500" fontWeight="bold" mt={4}>
{warningText}
</Text>
</Dialog.Body>
<Dialog.Footer>
<HStack justifyContent="flex-end" width="100%">
<Button onClick={onClose} variant="outline">
Cancel
</Button>
<Button colorPalette="red" loading={isDeleting} onClick={onDelete}>
<FiTrash2 style={{ marginRight: "8px" }} /> {deleteButtonText}
</Button>
</HStack>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
);
}) => {
const { t: translate } = useTranslation("common");

return (
<Dialog.Root lazyMount onOpenChange={onClose} open={open} size="md" unmountOnExit>
<Dialog.Content backdrop>
<Dialog.Header>
<Heading size="lg">{title}</Heading>
</Dialog.Header>
<Dialog.CloseTrigger />
<Dialog.Body>
<Text>{translate("modal.delete.confirmation", { resourceName })}</Text>
<Text color="red.500" fontWeight="bold" mt={4}>
{warningText}
</Text>
</Dialog.Body>
<Dialog.Footer>
<HStack justifyContent="flex-end" width="100%">
<Button onClick={onClose} variant="outline">
{translate("modal.cancel")}
</Button>
<Button colorPalette="red" loading={isDeleting} onClick={onDelete}>
<FiTrash2 style={{ marginRight: "8px" }} />{" "}
{deleteButtonText ?? translate("modal.delete.button")}
</Button>
</HStack>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
);
};

export default DeleteDialog;
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe("Test SearchBar", () => {

const input = screen.getByTestId("search-dags");

expect(screen.getByText("Advanced Search")).toBeDefined();
expect(screen.getByText("advancedSearch")).toBeDefined();
expect(screen.queryByTestId("clear-search")).toBeNull();

fireEvent.change(input, { target: { value: "search" } });
Expand Down
7 changes: 4 additions & 3 deletions airflow-core/src/airflow/ui/src/components/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import { Button, Input, Kbd, type ButtonProps } from "@chakra-ui/react";
import { useState, useRef, type ChangeEvent } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import { useTranslation } from "react-i18next";
import { FiSearch } from "react-icons/fi";
import { useDebouncedCallback } from "use-debounce";

Expand Down Expand Up @@ -51,7 +52,7 @@ export const SearchBar = ({
const searchRef = useRef<HTMLInputElement>(null);
const [value, setValue] = useState(defaultValue);
const metaKey = getMetaKey();

const { t: translate } = useTranslation(["dags"]);
const onSearchChange = (event: ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
handleSearchChange(event.target.value);
Expand All @@ -73,7 +74,7 @@ export const SearchBar = ({
<>
{Boolean(value) ? (
<CloseButton
aria-label="Clear search"
aria-label={translate("clearSearch")}
colorPalette="gray"
data-testid="clear-search"
onClick={() => {
Expand All @@ -85,7 +86,7 @@ export const SearchBar = ({
) : undefined}
{Boolean(hideAdvanced) ? undefined : (
<Button fontWeight="normal" height="1.75rem" variant="ghost" width={140} {...buttonProps}>
Advanced Search
{translate("advancedSearch")}
</Button>
)}
{!hotkeyDisabled && <Kbd size="sm">{metaKey}+K</Kbd>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
import { Box } from "@chakra-ui/react";
import { useDisclosure } from "@chakra-ui/react";
import { useTranslation } from "react-i18next";
import { FiPlay } from "react-icons/fi";

import type { DAGResponse, DAGWithLatestDagRunsResponse } from "openapi/requests/types.gen";
Expand All @@ -32,15 +33,16 @@ type Props = {

const TriggerDAGButton: React.FC<Props> = ({ dag, withText = true }) => {
const { onClose, onOpen, open } = useDisclosure();
const { t: translate } = useTranslation("dags");

return (
<Box>
<ActionButton
actionName="Trigger Dag"
actionName={translate("actions.triggerDag")}
colorPalette="blue"
icon={<FiPlay />}
onClick={onOpen}
text="Trigger"
text={translate("actions.trigger")}
variant="solid"
withText={withText}
/>
Expand Down
56 changes: 38 additions & 18 deletions airflow-core/src/airflow/ui/src/constants/sortParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,42 @@
* under the License.
*/
import { createListCollection } from "@chakra-ui/react/collection";
import type { TFunction } from "i18next";

export const dagSortOptions = createListCollection({
items: [
{ label: "Sort by Display Name (A-Z)", value: "dag_display_name" },
{ label: "Sort by Display Name (Z-A)", value: "-dag_display_name" },
{ label: "Sort by Next DAG Run (Earliest-Latest)", value: "next_dagrun" },
{ label: "Sort by Next DAG Run (Latest-Earliest)", value: "-next_dagrun" },
{ label: "Sort by Latest Run State (A-Z)", value: "last_run_state" },
{ label: "Sort by Latest Run State (Z-A)", value: "-last_run_state" },
{
label: "Sort by Latest Run Start Date (Earliest-Latest)",
value: "last_run_start_date",
},
{
label: "Sort by Latest Run Start Date (Latest-Earliest)",
value: "-last_run_start_date",
},
],
});
export const createDagSortOptions = (translate: TFunction) =>
createListCollection({
items: [
{
label: translate("sort.displayName.asc"),
value: "dag_display_name",
},
{
label: translate("sort.displayName.desc"),
value: "-dag_display_name",
},
{
label: translate("sort.nextDagRun.asc"),
value: "next_dagrun",
},
{
label: translate("sort.nextDagRun.desc"),
value: "-next_dagrun",
},
{
label: translate("sort.lastRunState.asc"),
value: "last_run_state",
},
{
label: translate("sort.lastRunState.desc"),
value: "-last_run_state",
},
{
label: translate("sort.lastRunStartDate.asc"),
value: "last_run_start_date",
},
{
label: translate("sort.lastRunStartDate.desc"),
value: "-last_run_start_date",
},
],
});
4 changes: 3 additions & 1 deletion airflow-core/src/airflow/ui/src/i18n/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { initReactI18next } from "react-i18next";
import deCommon from "./locales/de/common.json";
import deDashboard from "./locales/de/dashboard.json";
import enCommon from "./locales/en/common.json";
import enDags from "./locales/en/dags.json";
import enDashboard from "./locales/en/dashboard.json";
import koCommon from "./locales/ko/common.json";
import koDashboard from "./locales/ko/dashboard.json";
Expand All @@ -43,7 +44,7 @@ export const supportedLanguages = [
] as const;

export const defaultLanguage = "en";
export const namespaces = ["common", "dashboard"] as const;
export const namespaces = ["common", "dashboard", "dags"] as const;

const resources = {
de: {
Expand All @@ -52,6 +53,7 @@ const resources = {
},
en: {
common: enCommon,
dags: enDags,
dashboard: enDashboard,
},
ko: {
Expand Down
Loading