diff --git a/.gitignore b/.gitignore index e7fb2a5403dff..1528de626bdac 100644 --- a/.gitignore +++ b/.gitignore @@ -171,8 +171,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* -.vscode/* -!.vscode/extensions.json /.vite/ # Exclude the ui .vite dir airflow-core/src/airflow/ui/.vite/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000000..0e6d5fd64e4df --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "esbenp.prettier-vscode", + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000..aeae611e1fe46 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,38 @@ +{ + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } + }, + "[javascriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, +} diff --git a/airflow-core/src/airflow/ui/src/layouts/Nav/Nav.tsx b/airflow-core/src/airflow/ui/src/layouts/Nav/Nav.tsx index 1ee7444b3bd44..aa612849fab64 100644 --- a/airflow-core/src/airflow/ui/src/layouts/Nav/Nav.tsx +++ b/airflow-core/src/airflow/ui/src/layouts/Nav/Nav.tsx @@ -145,15 +145,15 @@ export const Nav = () => { width={16} zIndex={2} > - - - + + + diff --git a/airflow-core/src/airflow/ui/src/layouts/Nav/NavButton.tsx b/airflow-core/src/airflow/ui/src/layouts/Nav/NavButton.tsx index 3ebea71bef110..eaa13f57f1b76 100644 --- a/airflow-core/src/airflow/ui/src/layouts/Nav/NavButton.tsx +++ b/airflow-core/src/airflow/ui/src/layouts/Nav/NavButton.tsx @@ -17,8 +17,8 @@ * under the License. */ import { Box, type BoxProps, Button, Icon, type IconProps, Link, type ButtonProps } from "@chakra-ui/react"; -import { useMemo, type ForwardRefExoticComponent, type RefAttributes } from "react"; -import { IconType } from "react-icons"; +import { type ReactNode, useMemo, type ForwardRefExoticComponent, type RefAttributes } from "react"; +import type { IconType } from "react-icons"; import { Link as RouterLink, useMatch } from "react-router-dom"; const commonLabelProps: BoxProps = { @@ -31,63 +31,73 @@ const commonLabelProps: BoxProps = { }; type NavButtonProps = { - readonly icon: IconType | ForwardRefExoticComponent>; + readonly icon: ForwardRefExoticComponent> | IconType; readonly isExternal?: boolean; + readonly pluginIcon?: ReactNode; readonly title: string; readonly to?: string; } & ButtonProps; -export const NavButton = ({ icon, isExternal = false, title, to, ...rest }: NavButtonProps) => { +export const NavButton = ({ icon, isExternal = false, pluginIcon, title, to, ...rest }: NavButtonProps) => { // Use useMatch to determine if the current route matches the button's destination // This provides the same functionality as NavLink's isActive prop // Only applies to buttons with a to prop (but needs to be before any return statements) - const match = to ? useMatch({ - path: to, - end: to === "/" // Only exact match for root path - }) : undefined; + const match = useMatch({ + end: to === "/", // Only exact match for root path + path: to ?? "", + }); // Only applies to buttons with a to prop - const isActive = Boolean(match); + const isActive = Boolean(to) ? Boolean(match) : false; - const commonButtonProps = useMemo(() => ({ - _expanded: isActive ? undefined : { - bg: "brand.emphasized", // Even darker for better light mode contrast - color: "fg", - }, - _focus: isActive ? undefined : { - color: "fg", - }, - _hover: isActive ? undefined : { - bg: "brand.emphasized", // Even darker for better light mode contrast - color: "fg", - _active: { - bg: "brand.solid", - color: "white", - }, - }, - alignItems: "center", - bg: isActive ? "brand.solid" : undefined, - borderRadius: "md", - borderWidth: 0, - boxSize: 14, - color: isActive ? "white" : "fg.muted", - colorPalette: "brand", - cursor: "pointer", - flexDir: "column", - gap: 0, - overflow: "hidden", - padding: 0, - textDecoration: "none", - title, - transition: "background-color 0.2s ease, color 0.2s ease", - variant: "plain", - whiteSpace: "wrap", - ...rest, - }), [isActive, rest, title]); + const commonButtonProps = useMemo( + () => ({ + _expanded: isActive + ? undefined + : { + bg: "brand.emphasized", // Even darker for better light mode contrast + color: "fg", + }, + _focus: isActive + ? undefined + : { + color: "fg", + }, + _hover: isActive + ? undefined + : { + _active: { + bg: "brand.solid", + color: "white", + }, + bg: "brand.emphasized", // Even darker for better light mode contrast + color: "fg", + }, + alignItems: "center", + bg: isActive ? "brand.solid" : undefined, + borderRadius: "md", + borderWidth: 0, + boxSize: 14, + color: isActive ? "white" : "fg.muted", + colorPalette: "brand", + cursor: "pointer", + flexDir: "column", + gap: 0, + overflow: "hidden", + padding: 0, + textDecoration: "none", + title, + transition: "background-color 0.2s ease, color 0.2s ease", + variant: "plain", + whiteSpace: "wrap", + ...rest, + }), + [isActive, rest, title], + ); if (to === undefined) { return ( ); @@ -95,9 +105,9 @@ export const NavButton = ({ icon, isExternal = false, title, to, ...rest }: NavB if (isExternal) { return ( - + @@ -105,13 +115,9 @@ export const NavButton = ({ icon, isExternal = false, title, to, ...rest }: NavB } return ( - diff --git a/airflow-core/src/airflow/ui/src/layouts/Nav/PluginMenuItem.tsx b/airflow-core/src/airflow/ui/src/layouts/Nav/PluginMenuItem.tsx index c7372703237a5..5d36cf59e1053 100644 --- a/airflow-core/src/airflow/ui/src/layouts/Nav/PluginMenuItem.tsx +++ b/airflow-core/src/airflow/ui/src/layouts/Nav/PluginMenuItem.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { Link, Image, Menu } from "@chakra-ui/react"; +import { Link, Image, Menu, Icon, Box } from "@chakra-ui/react"; import { FiExternalLink } from "react-icons/fi"; import { LuPlug } from "react-icons/lu"; import { RiArchiveStackLine } from "react-icons/ri"; @@ -46,11 +46,11 @@ export const PluginMenuItem = ({ const displayIcon = colorMode === "dark" && typeof iconDarkMode === "string" ? iconDarkMode : icon; const pluginIcon = typeof displayIcon === "string" ? ( - + ) : urlRoute === "legacy-fab-views" ? ( - + ) : ( - + ); const isExternal = urlRoute === undefined || urlRoute === null; @@ -58,9 +58,10 @@ export const PluginMenuItem = ({ if (topLevel) { return ( @@ -80,13 +81,15 @@ export const PluginMenuItem = ({ width="100%" > {pluginIcon} - {name} - + {name} + ) : ( {pluginIcon} - {name} + + {name} + )} diff --git a/airflow-core/src/airflow/ui/src/layouts/Nav/PluginMenus.tsx b/airflow-core/src/airflow/ui/src/layouts/Nav/PluginMenus.tsx index c872780489097..9ac31f6947fed 100644 --- a/airflow-core/src/airflow/ui/src/layouts/Nav/PluginMenus.tsx +++ b/airflow-core/src/airflow/ui/src/layouts/Nav/PluginMenus.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { Box } from "@chakra-ui/react"; +import { Box, Icon } from "@chakra-ui/react"; import { useTranslation } from "react-i18next"; import { FiChevronRight } from "react-icons/fi"; import { LuPlug } from "react-icons/lu"; @@ -63,7 +63,7 @@ export const PluginMenus = ({ navItems }: { readonly navItems: Array {key} - + {menuButtons.map((navItem) => ( diff --git a/airflow-core/src/airflow/ui/src/layouts/Nav/UserSettingsButton.tsx b/airflow-core/src/airflow/ui/src/layouts/Nav/UserSettingsButton.tsx index 15ee91b04228c..84d8c385fed87 100644 --- a/airflow-core/src/airflow/ui/src/layouts/Nav/UserSettingsButton.tsx +++ b/airflow-core/src/airflow/ui/src/layouts/Nav/UserSettingsButton.tsx @@ -121,7 +121,9 @@ export const UserSettingsButton = ({ externalViews }: { readonly externalViews: value={dagView} > - {dagView === "grid" ? translate("defaultToGraphView") : translate("defaultToGridView")} + + {dagView === "grid" ? translate("defaultToGraphView") : translate("defaultToGridView")} + {externalViews.map((view) => (