From 7d7bf9ed4c00ac4dd5f5ad254206e7130e63e596 Mon Sep 17 00:00:00 2001 From: martylukyy <35452459+martylukyy@users.noreply.github.com> Date: Mon, 12 Aug 2024 20:36:45 +0200 Subject: [PATCH] refactor(web): update deprecated HeadlessUI v2 components (#1580) * refactor(web): move away from old headless UI dot notation * refactor(web): refactor `Disclosure` component * refactor(web): rename formik's `Field` to `FormikField` and keep original HeadlessUI component names --- web/src/components/Checkbox.tsx | 14 ++--- web/src/components/header/Header.tsx | 6 +- web/src/components/header/MobileNav.tsx | 8 +-- web/src/components/header/RightNav.tsx | 22 +++---- web/src/components/inputs/input_wide.tsx | 36 +++++------ web/src/components/inputs/radio.tsx | 18 +++--- web/src/components/inputs/select.tsx | 62 +++++++++---------- web/src/components/inputs/switch.tsx | 20 +++--- web/src/screens/Logs.tsx | 22 +++---- web/src/screens/filters/List.tsx | 67 ++++++++++++--------- web/src/screens/releases/ReleaseFilters.tsx | 14 ++--- web/src/screens/settings/Feed.tsx | 34 +++++------ web/src/screens/settings/Irc.tsx | 38 ++++++------ 13 files changed, 185 insertions(+), 176 deletions(-) diff --git a/web/src/components/Checkbox.tsx b/web/src/components/Checkbox.tsx index b53bddc..e033ac6 100644 --- a/web/src/components/Checkbox.tsx +++ b/web/src/components/Checkbox.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -import { Switch } from "@headlessui/react"; +import { Switch, Field, Label, Description } from "@headlessui/react"; import { classNames } from "@utils"; interface CheckboxProps { @@ -23,7 +23,7 @@ export const Checkbox = ({ setValue, disabled }: CheckboxProps) => ( - { @@ -34,14 +34,14 @@ export const Checkbox = ({ {(label || description) ? (
{label ? ( - + + ) : null} {description ? ( - + {description} - + ) : null}
) : null} @@ -81,5 +81,5 @@ export const Checkbox = ({ )} -
+ ); diff --git a/web/src/components/header/Header.tsx b/web/src/components/header/Header.tsx index 7036fcb..e44d696 100644 --- a/web/src/components/header/Header.tsx +++ b/web/src/components/header/Header.tsx @@ -6,7 +6,7 @@ import toast from "react-hot-toast"; import { useMutation, useQuery } from "@tanstack/react-query"; import { useRouter } from "@tanstack/react-router"; -import { Disclosure } from "@headlessui/react"; +import { Disclosure, DisclosureButton } from "@headlessui/react"; import { Bars3Icon, XMarkIcon, MegaphoneIcon } from "@heroicons/react/24/outline"; import { APIClient } from "@api/APIClient"; @@ -60,7 +60,7 @@ export const Header = () => {
{/* Mobile menu button */} - + Open main menu {open ? ( { aria-hidden="true" /> )} - +
diff --git a/web/src/components/header/MobileNav.tsx b/web/src/components/header/MobileNav.tsx index 4a9b241..b5a8054 100644 --- a/web/src/components/header/MobileNav.tsx +++ b/web/src/components/header/MobileNav.tsx @@ -3,8 +3,8 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -import {Link} from "@tanstack/react-router"; -import { Disclosure } from "@headlessui/react"; +import { Link } from "@tanstack/react-router"; +import { DisclosurePanel } from "@headlessui/react"; import { classNames } from "@utils"; @@ -12,7 +12,7 @@ import { NAV_ROUTES } from "./_shared"; import type { RightNavProps } from "./_shared"; export const MobileNav = (props: RightNavProps) => ( - +
{NAV_ROUTES.map((item) => ( ( Logout
-
+ ); diff --git a/web/src/components/header/RightNav.tsx b/web/src/components/header/RightNav.tsx index 0f3bccb..2155adf 100644 --- a/web/src/components/header/RightNav.tsx +++ b/web/src/components/header/RightNav.tsx @@ -5,7 +5,7 @@ import { Fragment } from "react"; import { UserIcon } from "@heroicons/react/24/solid"; -import { Menu, Transition } from "@headlessui/react"; +import { Menu, MenuButton, MenuItem, MenuItems, Transition } from "@headlessui/react"; import { classNames } from "@utils"; @@ -44,7 +44,7 @@ export const RightNav = (props: RightNavProps) => { {({ open }) => ( <> - { className="inline ml-1 h-5 w-5" aria-hidden="true" /> - + { leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > - - + {({ active }) => ( { Account )} - - + + {({ active }) => ( { Settings )} - - + + {({ active }) => ( )} - - + + )} diff --git a/web/src/components/inputs/input_wide.tsx b/web/src/components/inputs/input_wide.tsx index c9245eb..46b0b52 100644 --- a/web/src/components/inputs/input_wide.tsx +++ b/web/src/components/inputs/input_wide.tsx @@ -3,9 +3,9 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -import { Field } from "formik"; +import { Field as FormikField } from "formik"; import Select from "react-select"; -import { Switch } from "@headlessui/react"; +import { Field, Label, Description } from "@headlessui/react"; import type { FieldProps, FieldValidator } from "formik"; import { classNames } from "@utils"; @@ -55,7 +55,7 @@ export const TextFieldWide = ({
- )} - + {help && (

{help}

)} @@ -130,7 +130,7 @@ export const PasswordFieldWide = ({
-
)} - + {help && (

{help}

)} @@ -203,7 +203,7 @@ export const NumberFieldWide = ({
- @@ -229,7 +229,7 @@ export const NumberFieldWide = ({ placeholder={placeholder} /> )} - + {help && (

{help}

)} @@ -255,23 +255,23 @@ export const SwitchGroupWide = ({ defaultValue }: SwitchGroupWideProps) => (
    - +
    - + + {description && ( - + {description} - + )}
    - )} - -
    + +
); @@ -314,7 +314,7 @@ export const SelectFieldWide = ({
- + {({ field, form: { setFieldValue } @@ -352,7 +352,7 @@ export const SelectFieldWide = ({ options={options} /> )} - +
); diff --git a/web/src/components/inputs/radio.tsx b/web/src/components/inputs/radio.tsx index 205fad4..01696ea 100644 --- a/web/src/components/inputs/radio.tsx +++ b/web/src/components/inputs/radio.tsx @@ -4,7 +4,7 @@ */ import { Field, useFormikContext } from "formik"; -import { RadioGroup } from "@headlessui/react"; +import { RadioGroup, Description, Label, Radio } from "@headlessui/react"; import { classNames } from "@utils"; export interface radioFieldsetOption { @@ -47,12 +47,12 @@ function RadioFieldsetWide({ name, legend, options }: props) { {() => ( - + +
{options.map((setting, settingIdx) => ( - @@ -82,7 +82,7 @@ function RadioFieldsetWide({ name, legend, options }: props) { aria-hidden="true" />
- {setting.type}}
- - + {setting.description} - +
)} - + ))}
diff --git a/web/src/components/inputs/select.tsx b/web/src/components/inputs/select.tsx index ab4e075..42bbcba 100644 --- a/web/src/components/inputs/select.tsx +++ b/web/src/components/inputs/select.tsx @@ -5,7 +5,7 @@ import { Fragment } from "react"; import { Field, FieldProps } from "formik"; -import { Listbox, Transition } from "@headlessui/react"; +import { Listbox, ListboxButton, Label, ListboxOption, ListboxOptions, Transition } from "@headlessui/react"; import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/24/solid"; import { MultiSelect as RMSC } from "react-multi-select-component"; @@ -166,11 +166,11 @@ export function DownloadClientSelect({ > {({ open }) => ( <> - + +
- + {field.value ? clients.find((c) => c.id === field.value)?.name @@ -181,7 +181,7 @@ export function DownloadClientSelect({ className="h-5 w-5 text-gray-400 dark:text-gray-300" aria-hidden="true" /> - + - {clients .filter((c) => c.type === action.type) .map((client) => ( - classNames( active @@ -232,9 +232,9 @@ export function DownloadClientSelect({ ) : null} )} - + ))} - + {meta.touched && meta.error && (

* {meta.error}

@@ -294,13 +294,13 @@ export const Select = ({ > {({ open }) => ( <> - + +
- + {field.value ? options.find((c) => c.value === field.value)?.label @@ -313,7 +313,7 @@ export const Select = ({ aria-hidden="true" /> - + - {options.map((opt) => ( - classNames( @@ -359,9 +359,9 @@ export const Select = ({ )} - + ))} - +
@@ -395,11 +395,11 @@ export const SelectWide = ({ {({ open }) => (
- + +
- + {field.value ? options.find((c) => c.value === field.value)?.label @@ -412,7 +412,7 @@ export const SelectWide = ({ aria-hidden="true" /> - + - {options.map((opt) => ( - classNames( @@ -464,9 +464,9 @@ export const SelectWide = ({ ) : null} )} - + ))} - +
@@ -512,14 +512,14 @@ export const AgeSelect = ({ {({ open }) => ( <>
- + {duration ? options.find(opt => opt.value === duration)?.label : 'Select...'} - + - + {options.map((option) => ( - `relative cursor-default select-none py-2 pl-3 pr-9 ${selected ? "font-bold text-black dark:text-white bg-gray-300 dark:bg-gray-950" : active ? "text-black dark:text-gray-100 font-normal bg-gray-200 dark:bg-gray-800" : "text-gray-700 dark:text-gray-300 font-normal" @@ -547,9 +547,9 @@ export const AgeSelect = ({ )} )} - + ))} - +
diff --git a/web/src/components/inputs/switch.tsx b/web/src/components/inputs/switch.tsx index a970a99..5f611a5 100644 --- a/web/src/components/inputs/switch.tsx +++ b/web/src/components/inputs/switch.tsx @@ -4,8 +4,8 @@ */ import type { FieldProps } from "formik"; -import { Field } from "formik"; -import { Switch as HeadlessSwitch } from "@headlessui/react"; +import { Field as FormikField } from "formik"; +import { Field, Label, Description } from "@headlessui/react"; import { classNames } from "@utils"; import { DocsTooltip } from "@components/tooltips/DocsTooltip"; @@ -30,7 +30,7 @@ const SwitchGroup = ({ disabled, className }: SwitchGroupProps) => ( - {label &&
- {tooltip} ) : label}
- + {description && ( - + {description} - + )}
} - + {({ field, form: { setFieldValue } @@ -75,8 +75,8 @@ const SwitchGroup = ({ disabled={disabled} /> )} - - + +
); export { SwitchGroup }; diff --git a/web/src/screens/Logs.tsx b/web/src/screens/Logs.tsx index d46842f..7e76cbd 100644 --- a/web/src/screens/Logs.tsx +++ b/web/src/screens/Logs.tsx @@ -5,7 +5,7 @@ import { Fragment, useEffect, useRef, useState } from "react"; import { useSuspenseQuery } from "@tanstack/react-query"; -import { Menu, Transition } from "@headlessui/react"; +import { Menu, MenuButton, MenuItem, MenuItems, Transition } from "@headlessui/react"; import { DebounceInput } from "react-debounce-input"; import { Cog6ToothIcon, @@ -307,12 +307,12 @@ const LogsDropdown = () => { return ( - + + { leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > -
- + {() => ( { setValue={(newValue) => onSetValue("scrollOnNewLog", newValue)} /> )} - - + + {() => ( { setValue={(newValue) => onSetValue("indentLogLines", newValue)} /> )} - - + + {() => ( { setValue={(newValue) => onSetValue("hideWrappedText", newValue)} /> )} - +
-
+
); diff --git a/web/src/screens/filters/List.tsx b/web/src/screens/filters/List.tsx index fa024e7..11f5d15 100644 --- a/web/src/screens/filters/List.tsx +++ b/web/src/screens/filters/List.tsx @@ -6,7 +6,16 @@ import { Dispatch, FC, Fragment, MouseEventHandler, useCallback, useEffect, useReducer, useRef, useState } from "react"; import { Link } from '@tanstack/react-router' import { toast } from "react-hot-toast"; -import { Listbox, Menu, Transition } from "@headlessui/react"; +import { + Listbox, + ListboxButton, + ListboxOption, ListboxOptions, + Menu, + MenuButton, + MenuItem, + MenuItems, + Transition +} from "@headlessui/react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { ArrowsRightLeftIcon, @@ -114,9 +123,9 @@ export function Filters() { Create Filter - + - + - - + + {({ active }) => ( )} - - + + )} @@ -380,12 +389,12 @@ const FilterItemDropdown = ({ filter, onToggle }: FilterItemDropdownProps) => { title={`Remove filter: ${filter.name}`} text="Are you sure you want to remove this filter? This action cannot be undone." /> - + + { leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > -
- + {({ active }) => ( { Edit )} - - + + {({ active }) => ( )} - - + + {({ active }) => ( )} - - + + {({ active }) => ( )} - - + + {({ active }) => ( )} - +
- + {({ active }) => ( )} - +
-
+
); @@ -712,7 +721,7 @@ const ListboxFilter = ({ onChange={onChange} >
- + {label} - + - {children} - +
@@ -774,7 +783,7 @@ interface FilterOptionProps { } const FilterOption = ({ label, value }: FilterOptionProps) => ( - classNames( "cursor-pointer select-none relative py-2 px-4", active ? "text-black dark:text-gray-200 bg-gray-100 dark:bg-gray-900" : "text-gray-700 dark:text-gray-400" @@ -798,7 +807,7 @@ const FilterOption = ({ label, value }: FilterOptionProps) => ( ) : null} )} - + ); export const SortSelectFilter = ({ dispatch }: any) => { diff --git a/web/src/screens/releases/ReleaseFilters.tsx b/web/src/screens/releases/ReleaseFilters.tsx index 7866b8b..c07f25f 100644 --- a/web/src/screens/releases/ReleaseFilters.tsx +++ b/web/src/screens/releases/ReleaseFilters.tsx @@ -5,7 +5,7 @@ import * as React from "react"; import { useQuery } from "@tanstack/react-query"; -import { Listbox, Transition } from "@headlessui/react"; +import { Listbox, ListboxButton, ListboxOption, ListboxOptions, Transition } from "@headlessui/react"; import { CheckIcon, ChevronDownIcon } from "@heroicons/react/24/solid"; import { classNames } from "@utils"; @@ -36,7 +36,7 @@ const ListboxFilter = ({ onChange={onChange} >
- + {label} - + - {children} - +
@@ -91,7 +91,7 @@ interface FilterOptionProps { } const FilterOption = ({ label, value }: FilterOptionProps) => ( - classNames( "cursor-pointer select-none relative py-2 pl-10 pr-4", active ? "text-black dark:text-gray-200 bg-gray-100 dark:bg-gray-900" : "text-gray-700 dark:text-gray-400" @@ -115,7 +115,7 @@ const FilterOption = ({ label, value }: FilterOptionProps) => ( ) : null} )} - + ); export const PushStatusSelectColumnFilter = ({ diff --git a/web/src/screens/settings/Feed.tsx b/web/src/screens/settings/Feed.tsx index 17118b9..4e7e6a3 100644 --- a/web/src/screens/settings/Feed.tsx +++ b/web/src/screens/settings/Feed.tsx @@ -5,7 +5,7 @@ import { Fragment, useMemo, useRef, useState } from "react"; import { useMutation, useQueryClient, useSuspenseQuery } from "@tanstack/react-query"; -import { Menu, Transition } from "@headlessui/react"; +import { Menu, MenuButton, MenuItem, MenuItems, Transition } from "@headlessui/react"; import { toast } from "react-hot-toast"; import { ArrowsRightLeftIcon, @@ -302,12 +302,12 @@ const FeedItemDropdown = ({ title={`Force run feed: ${feed.name}`} text={`Are you sure you want to force run the ${feed.name} feed? Respecting RSS interval rules is crucial to avoid potential IP bans.`} /> - + + -
- + {({ active }) => (
- + {({ active }) => ( )} - - + + View latest run - - + + {({ active }) => (
- + {({ active }) => (
-
+
); diff --git a/web/src/screens/settings/Irc.tsx b/web/src/screens/settings/Irc.tsx index 320f0a7..303edcb 100644 --- a/web/src/screens/settings/Irc.tsx +++ b/web/src/screens/settings/Irc.tsx @@ -6,7 +6,7 @@ import { Fragment, MouseEvent, useEffect, useMemo, useRef, useState } from "react"; import { useMutation, useQueryClient, useSuspenseQuery } from "@tanstack/react-query"; import { ArrowPathIcon, LockClosedIcon, LockOpenIcon, PlusIcon } from "@heroicons/react/24/solid"; -import { Menu, Transition } from "@headlessui/react"; +import { Menu, MenuButton, MenuItem, MenuItems, Transition } from "@headlessui/react"; import { toast } from "react-hot-toast"; import { ArrowsPointingInIcon, @@ -462,12 +462,12 @@ const ListItemDropdown = ({ title={`Remove network: ${network.name}`} text="Are you sure you want to remove this network? This action cannot be undone." /> - + + -
- + {({ active }) => (
- + {({ active }) => (
-
+
); @@ -776,9 +776,9 @@ const IRCLogsDropdown = () => { // at IRCLogsDropdown (http://localhost:3000/src/screens/settings/Irc.tsx?t=1694269937935:1354:53) return ( - + Options - + { leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > - - + {() => ( { setValue={(newValue) => onSetValue("scrollOnNewLog", newValue)} /> )} - - + + );