mirror of
https://github.com/idanoo/autobrr
synced 2025-07-26 02:09:13 +00:00
feat(irc): improve list view (#466)
* feat(irc): add irc status examples * feat(irc): add dropdown menu to list * feat(irc): update heroicons and add expand button * feat(irc): update heroicons and add expand button
This commit is contained in:
parent
f5faf066a9
commit
300418b9f1
34 changed files with 478 additions and 258 deletions
|
@ -1,8 +1,8 @@
|
|||
import { Fragment } from "react";
|
||||
import { Link, NavLink, Outlet } from "react-router-dom";
|
||||
import { Disclosure, Menu, Transition } from "@headlessui/react";
|
||||
import { ExternalLinkIcon } from "@heroicons/react/solid";
|
||||
import { ChevronDownIcon, MenuIcon, XIcon } from "@heroicons/react/outline";
|
||||
import { ArrowTopRightOnSquareIcon } from "@heroicons/react/24/solid";
|
||||
import { Bars3Icon, ChevronDownIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
import { AuthContext } from "../utils/Context";
|
||||
|
||||
|
@ -76,7 +76,7 @@ export default function Base() {
|
|||
)}
|
||||
>
|
||||
Docs
|
||||
<ExternalLinkIcon className="inline ml-1 h-5 w-5"
|
||||
<ArrowTopRightOnSquareIcon className="inline ml-1 h-5 w-5"
|
||||
aria-hidden="true"/>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -157,9 +157,9 @@ export default function Base() {
|
|||
className="bg-gray-200 dark:bg-gray-800 inline-flex items-center justify-center p-2 rounded-md text-gray-600 dark:text-gray-400 hover:text-white hover:bg-gray-700">
|
||||
<span className="sr-only">Open main menu</span>
|
||||
{open ? (
|
||||
<XIcon className="block h-6 w-6" aria-hidden="true"/>
|
||||
<XMarkIcon className="block h-6 w-6" aria-hidden="true"/>
|
||||
) : (
|
||||
<MenuIcon className="block h-6 w-6" aria-hidden="true"/>
|
||||
<Bars3Icon className="block h-6 w-6" aria-hidden="true"/>
|
||||
)}
|
||||
</Disclosure.Button>
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { ExclamationIcon } from "@heroicons/react/solid";
|
||||
import {useEffect, useRef, useState} from "react";
|
||||
import {ExclamationTriangleIcon} from "@heroicons/react/24/solid";
|
||||
import format from "date-fns/format";
|
||||
import { DebounceInput } from "react-debounce-input";
|
||||
import {DebounceInput} from "react-debounce-input";
|
||||
|
||||
import { APIClient } from "../api/APIClient";
|
||||
import { Checkbox } from "../components/Checkbox";
|
||||
import { classNames } from "../utils";
|
||||
import { SettingsContext } from "../utils/Context";
|
||||
import {APIClient} from "../api/APIClient";
|
||||
import {Checkbox} from "../components/Checkbox";
|
||||
import {classNames} from "../utils";
|
||||
import {SettingsContext} from "../utils/Context";
|
||||
|
||||
type LogEvent = {
|
||||
time: string;
|
||||
|
@ -79,7 +79,7 @@ export const Logs = () => {
|
|||
<div className="max-w-screen-xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<h1 className="text-3xl font-bold text-black dark:text-white">Logs</h1>
|
||||
<div className="flex justify-center">
|
||||
<ExclamationIcon
|
||||
<ExclamationTriangleIcon
|
||||
className="h-5 w-5 text-yellow-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { NavLink, Outlet, useLocation } from "react-router-dom";
|
||||
import {NavLink, Outlet, useLocation} from "react-router-dom";
|
||||
import {
|
||||
BellIcon,
|
||||
ChatAlt2Icon,
|
||||
ChatBubbleLeftRightIcon,
|
||||
CogIcon,
|
||||
CollectionIcon,
|
||||
DownloadIcon,
|
||||
FolderArrowDownIcon,
|
||||
KeyIcon,
|
||||
RectangleStackIcon,
|
||||
RssIcon
|
||||
} from "@heroicons/react/outline";
|
||||
} from "@heroicons/react/24/outline";
|
||||
|
||||
import { classNames } from "../utils";
|
||||
import {classNames} from "../utils";
|
||||
|
||||
interface NavTabType {
|
||||
name: string;
|
||||
|
@ -20,12 +20,12 @@ interface NavTabType {
|
|||
const subNavigation: NavTabType[] = [
|
||||
{ name: "Application", href: "", icon: CogIcon },
|
||||
{ name: "Indexers", href: "indexers", icon: KeyIcon },
|
||||
{ name: "IRC", href: "irc", icon: ChatAlt2Icon },
|
||||
{ name: "IRC", href: "irc", icon: ChatBubbleLeftRightIcon },
|
||||
{ name: "Feeds", href: "feeds", icon: RssIcon },
|
||||
{ name: "Clients", href: "clients", icon: DownloadIcon },
|
||||
{ name: "Clients", href: "clients", icon: FolderArrowDownIcon },
|
||||
{ name: "Notifications", href: "notifications", icon: BellIcon },
|
||||
{ name: "API keys", href: "api-keys", icon: KeyIcon },
|
||||
{ name: "Releases", href: "releases", icon: CollectionIcon }
|
||||
{ name: "Releases", href: "releases", icon: RectangleStackIcon }
|
||||
// {name: 'Regex Playground', href: 'regex-playground', icon: CogIcon, current: false}
|
||||
// {name: 'Rules', href: 'rules', icon: ClipboardCheckIcon, current: false},
|
||||
];
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { AlertWarning } from "../../components/alerts";
|
||||
import { DownloadClientSelect, NumberField, Select, SwitchGroup, TextField } from "../../components/inputs";
|
||||
import { ActionContentLayoutOptions, ActionTypeNameMap, ActionTypeOptions } from "../../domain/constants";
|
||||
import React, { Fragment, useRef } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import { Field, FieldArray, FieldProps, FormikValues } from "formik";
|
||||
import { EmptyListState } from "../../components/emptystates";
|
||||
import { useToggle } from "../../hooks/hooks";
|
||||
import { classNames } from "../../utils";
|
||||
import { Dialog, Switch as SwitchBasic, Transition } from "@headlessui/react";
|
||||
import { ChevronRightIcon } from "@heroicons/react/solid";
|
||||
import { DeleteModal } from "../../components/modals";
|
||||
import { CollapsableSection } from "./details";
|
||||
import {AlertWarning} from "../../components/alerts";
|
||||
import {DownloadClientSelect, NumberField, Select, SwitchGroup, TextField} from "../../components/inputs";
|
||||
import {ActionContentLayoutOptions, ActionTypeNameMap, ActionTypeOptions} from "../../domain/constants";
|
||||
import React, {Fragment, useRef} from "react";
|
||||
import {useQuery} from "react-query";
|
||||
import {APIClient} from "../../api/APIClient";
|
||||
import {Field, FieldArray, FieldProps, FormikValues} from "formik";
|
||||
import {EmptyListState} from "../../components/emptystates";
|
||||
import {useToggle} from "../../hooks/hooks";
|
||||
import {classNames} from "../../utils";
|
||||
import {Dialog, Switch as SwitchBasic, Transition} from "@headlessui/react";
|
||||
import {ChevronRightIcon} from "@heroicons/react/24/solid";
|
||||
import {DeleteModal} from "../../components/modals";
|
||||
import {CollapsableSection} from "./details";
|
||||
|
||||
interface FilterActionsProps {
|
||||
filter: Filter;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useRef } from "react";
|
||||
import { useMutation, useQuery } from "react-query";
|
||||
import { NavLink, Route, Routes, useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { Form, Formik, FormikValues, useFormikContext } from "formik";
|
||||
import { ChevronDownIcon, ChevronRightIcon } from "@heroicons/react/solid";
|
||||
import React, {useRef} from "react";
|
||||
import {useMutation, useQuery} from "react-query";
|
||||
import {NavLink, Route, Routes, useLocation, useNavigate, useParams} from "react-router-dom";
|
||||
import {toast} from "react-hot-toast";
|
||||
import {Form, Formik, FormikValues, useFormikContext} from "formik";
|
||||
import {ChevronDownIcon, ChevronRightIcon} from "@heroicons/react/24/solid";
|
||||
|
||||
import {
|
||||
CODECS_OPTIONS,
|
||||
|
@ -19,10 +19,10 @@ import {
|
|||
SOURCES_MUSIC_OPTIONS,
|
||||
SOURCES_OPTIONS
|
||||
} from "../../domain/constants";
|
||||
import { queryClient } from "../../App";
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import { useToggle } from "../../hooks/hooks";
|
||||
import { classNames } from "../../utils";
|
||||
import {queryClient} from "../../App";
|
||||
import {APIClient} from "../../api/APIClient";
|
||||
import {useToggle} from "../../hooks/hooks";
|
||||
import {classNames} from "../../utils";
|
||||
|
||||
import {
|
||||
CheckboxField,
|
||||
|
@ -35,10 +35,10 @@ import {
|
|||
} from "../../components/inputs";
|
||||
import DEBUG from "../../components/debug";
|
||||
import Toast from "../../components/notifications/Toast";
|
||||
import { DeleteModal } from "../../components/modals";
|
||||
import { TitleSubtitle } from "../../components/headings";
|
||||
import { TextArea } from "../../components/inputs/input";
|
||||
import { FilterActions } from "./action";
|
||||
import {DeleteModal} from "../../components/modals";
|
||||
import {TitleSubtitle} from "../../components/headings";
|
||||
import {TextArea} from "../../components/inputs/input";
|
||||
import {FilterActions} from "./action";
|
||||
|
||||
interface tabType {
|
||||
name: string;
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
import { Dispatch, FC, Fragment, MouseEventHandler, useReducer, useRef, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { Listbox, Menu, Switch, Transition } from "@headlessui/react";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import {Dispatch, FC, Fragment, MouseEventHandler, useReducer, useRef, useState} from "react";
|
||||
import {Link} from "react-router-dom";
|
||||
import {toast} from "react-hot-toast";
|
||||
import {Listbox, Menu, Switch, Transition} from "@headlessui/react";
|
||||
import {useMutation, useQuery, useQueryClient} from "react-query";
|
||||
import {
|
||||
ArrowsRightLeftIcon,
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
DotsHorizontalIcon,
|
||||
DuplicateIcon,
|
||||
PencilAltIcon,
|
||||
SwitchHorizontalIcon,
|
||||
DocumentDuplicateIcon,
|
||||
EllipsisHorizontalIcon,
|
||||
PencilSquareIcon,
|
||||
TrashIcon
|
||||
} from "@heroicons/react/outline";
|
||||
} from "@heroicons/react/24/outline";
|
||||
|
||||
import { queryClient } from "../../App";
|
||||
import { classNames } from "../../utils";
|
||||
import { FilterAddForm } from "../../forms";
|
||||
import { useToggle } from "../../hooks/hooks";
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import {queryClient} from "../../App";
|
||||
import {classNames} from "../../utils";
|
||||
import {FilterAddForm} from "../../forms";
|
||||
import {useToggle} from "../../hooks/hooks";
|
||||
import {APIClient} from "../../api/APIClient";
|
||||
import Toast from "../../components/notifications/Toast";
|
||||
import { EmptyListState } from "../../components/emptystates";
|
||||
import { DeleteModal } from "../../components/modals";
|
||||
import {EmptyListState} from "../../components/emptystates";
|
||||
import {DeleteModal} from "../../components/modals";
|
||||
|
||||
type FilterListState = {
|
||||
indexerFilter: string[],
|
||||
|
@ -250,7 +250,7 @@ const FilterItemDropdown = ({
|
|||
text="Are you sure you want to remove this filter? This action cannot be undone."
|
||||
/>
|
||||
<Menu.Button className="px-4 py-2">
|
||||
<DotsHorizontalIcon
|
||||
<EllipsisHorizontalIcon
|
||||
className="w-5 h-5 text-gray-700 hover:text-gray-900 dark:text-gray-100 dark:hover:text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
@ -277,7 +277,7 @@ const FilterItemDropdown = ({
|
|||
"font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"
|
||||
)}
|
||||
>
|
||||
<PencilAltIcon
|
||||
<PencilSquareIcon
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-blue-500",
|
||||
"w-5 h-5 mr-2"
|
||||
|
@ -297,7 +297,7 @@ const FilterItemDropdown = ({
|
|||
)}
|
||||
onClick={() => onToggle(!filter.enabled)}
|
||||
>
|
||||
<SwitchHorizontalIcon
|
||||
<ArrowsRightLeftIcon
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-blue-500",
|
||||
"w-5 h-5 mr-2"
|
||||
|
@ -317,7 +317,7 @@ const FilterItemDropdown = ({
|
|||
)}
|
||||
onClick={() => duplicateMutation.mutate(filter.id)}
|
||||
>
|
||||
<DuplicateIcon
|
||||
<DocumentDuplicateIcon
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-blue-500",
|
||||
"w-5 h-5 mr-2"
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
import * as React from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { Listbox, Transition } from "@headlessui/react";
|
||||
import {
|
||||
CheckIcon,
|
||||
ChevronDownIcon
|
||||
} from "@heroicons/react/solid";
|
||||
import {useQuery} from "react-query";
|
||||
import {Listbox, Transition} from "@headlessui/react";
|
||||
import {CheckIcon, ChevronDownIcon} from "@heroicons/react/24/solid";
|
||||
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import { classNames } from "../../utils";
|
||||
import { PushStatusOptions } from "../../domain/constants";
|
||||
import { FilterProps } from "react-table";
|
||||
import { DebounceInput } from "react-debounce-input";
|
||||
import {APIClient} from "../../api/APIClient";
|
||||
import {classNames} from "../../utils";
|
||||
import {PushStatusOptions} from "../../domain/constants";
|
||||
import {FilterProps} from "react-table";
|
||||
import {DebounceInput} from "react-debounce-input";
|
||||
|
||||
interface ListboxFilterProps {
|
||||
id: string;
|
||||
|
|
|
@ -1,29 +1,20 @@
|
|||
import * as React from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import {
|
||||
useTable,
|
||||
useSortBy,
|
||||
usePagination,
|
||||
useFilters,
|
||||
Column
|
||||
} from "react-table";
|
||||
import {useQuery} from "react-query";
|
||||
import {Column, useFilters, usePagination, useSortBy, useTable} from "react-table";
|
||||
import {
|
||||
ChevronDoubleLeftIcon,
|
||||
ChevronDoubleRightIcon,
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
ChevronDoubleRightIcon
|
||||
} from "@heroicons/react/solid";
|
||||
ChevronRightIcon
|
||||
} from "@heroicons/react/24/solid";
|
||||
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import { EmptyListState } from "../../components/emptystates";
|
||||
import {APIClient} from "../../api/APIClient";
|
||||
import {EmptyListState} from "../../components/emptystates";
|
||||
|
||||
import * as Icons from "../../components/Icons";
|
||||
import * as DataTable from "../../components/data-table";
|
||||
|
||||
import {
|
||||
IndexerSelectColumnFilter,
|
||||
PushStatusSelectColumnFilter, SearchColumnFilter
|
||||
} from "./Filters";
|
||||
import {IndexerSelectColumnFilter, PushStatusSelectColumnFilter, SearchColumnFilter} from "./Filters";
|
||||
|
||||
type TableState = {
|
||||
queryPageIndex: number;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { queryClient } from "../../App";
|
||||
import { useRef } from "react";
|
||||
import { useMutation, useQuery } from "react-query";
|
||||
import { KeyField } from "../../components/fields/text";
|
||||
import { DeleteModal } from "../../components/modals";
|
||||
import {queryClient} from "../../App";
|
||||
import {useRef} from "react";
|
||||
import {useMutation, useQuery} from "react-query";
|
||||
import {KeyField} from "../../components/fields/text";
|
||||
import {DeleteModal} from "../../components/modals";
|
||||
import APIKeyAddForm from "../../forms/settings/APIKeyAddForm";
|
||||
import Toast from "../../components/notifications/Toast";
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import { useToggle } from "../../hooks/hooks";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { classNames } from "../../utils";
|
||||
import { TrashIcon } from "@heroicons/react/outline";
|
||||
import { EmptySimple } from "../../components/emptystates";
|
||||
import {APIClient} from "../../api/APIClient";
|
||||
import {useToggle} from "../../hooks/hooks";
|
||||
import {toast} from "react-hot-toast";
|
||||
import {classNames} from "../../utils";
|
||||
import {TrashIcon} from "@heroicons/react/24/outline";
|
||||
import {EmptySimple} from "../../components/emptystates";
|
||||
|
||||
function APISettings() {
|
||||
const [addFormIsOpen, toggleAddForm] = useToggle(false);
|
||||
|
|
|
@ -1,23 +1,18 @@
|
|||
import { useToggle } from "../../hooks/hooks";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import { Menu, Switch, Transition } from "@headlessui/react";
|
||||
import {useToggle} from "../../hooks/hooks";
|
||||
import {useMutation, useQuery, useQueryClient} from "react-query";
|
||||
import {APIClient} from "../../api/APIClient";
|
||||
import {Menu, Switch, Transition} from "@headlessui/react";
|
||||
|
||||
import { classNames } from "../../utils";
|
||||
import { Fragment, useRef, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import {classNames} from "../../utils";
|
||||
import {Fragment, useRef, useState} from "react";
|
||||
import {toast} from "react-hot-toast";
|
||||
import Toast from "../../components/notifications/Toast";
|
||||
import { queryClient } from "../../App";
|
||||
import { DeleteModal } from "../../components/modals";
|
||||
import {
|
||||
DotsHorizontalIcon,
|
||||
PencilAltIcon,
|
||||
SwitchHorizontalIcon,
|
||||
TrashIcon
|
||||
} from "@heroicons/react/outline";
|
||||
import { FeedUpdateForm } from "../../forms/settings/FeedForms";
|
||||
import { EmptySimple } from "../../components/emptystates";
|
||||
import { ImplementationBadges } from "./Indexer";
|
||||
import {queryClient} from "../../App";
|
||||
import {DeleteModal} from "../../components/modals";
|
||||
import {ArrowsRightLeftIcon, EllipsisHorizontalIcon, PencilSquareIcon, TrashIcon} from "@heroicons/react/24/outline";
|
||||
import {FeedUpdateForm} from "../../forms/settings/FeedForms";
|
||||
import {EmptySimple} from "../../components/emptystates";
|
||||
import {ImplementationBadges} from "./Indexer";
|
||||
|
||||
function FeedSettings() {
|
||||
const { data } = useQuery(
|
||||
|
@ -183,7 +178,7 @@ const FeedItemDropdown = ({
|
|||
text="Are you sure you want to remove this feed? This action cannot be undone."
|
||||
/>
|
||||
<Menu.Button className="px-4 py-2">
|
||||
<DotsHorizontalIcon
|
||||
<EllipsisHorizontalIcon
|
||||
className="w-5 h-5 text-gray-700 hover:text-gray-900 dark:text-gray-100 dark:hover:text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
@ -210,7 +205,7 @@ const FeedItemDropdown = ({
|
|||
)}
|
||||
onClick={() => toggleUpdate()}
|
||||
>
|
||||
<PencilAltIcon
|
||||
<PencilSquareIcon
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-blue-500",
|
||||
"w-5 h-5 mr-2"
|
||||
|
@ -230,7 +225,7 @@ const FeedItemDropdown = ({
|
|||
)}
|
||||
onClick={() => onToggle(!feed.enabled)}
|
||||
>
|
||||
<SwitchHorizontalIcon
|
||||
<ArrowsRightLeftIcon
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-blue-500",
|
||||
"w-5 h-5 mr-2"
|
||||
|
|
|
@ -1,14 +1,28 @@
|
|||
import { useQuery } from "react-query";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
|
||||
import { simplifyDate, IsEmptyDate, classNames } from "../../utils";
|
||||
import { classNames, IsEmptyDate, simplifyDate } from "../../utils";
|
||||
import { IrcNetworkAddForm, IrcNetworkUpdateForm } from "../../forms";
|
||||
import { useToggle } from "../../hooks/hooks";
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import { EmptySimple } from "../../components/emptystates";
|
||||
import { ExclamationCircleIcon } from "@heroicons/react/outline";
|
||||
import { LockClosedIcon, LockOpenIcon } from "@heroicons/react/solid";
|
||||
import { LockClosedIcon, LockOpenIcon } from "@heroicons/react/24/solid";
|
||||
import { Menu, Transition } from "@headlessui/react";
|
||||
import { Fragment, useRef } from "react";
|
||||
import { DeleteModal } from "../../components/modals";
|
||||
|
||||
import { toast } from "react-hot-toast";
|
||||
import Toast from "../../components/notifications/Toast";
|
||||
import {
|
||||
ArrowsPointingInIcon,
|
||||
ArrowsPointingOutIcon,
|
||||
EllipsisHorizontalIcon,
|
||||
ExclamationCircleIcon,
|
||||
PencilSquareIcon,
|
||||
TrashIcon
|
||||
} from "@heroicons/react/24/outline";
|
||||
|
||||
export const IrcSettings = () => {
|
||||
const [expandNetworks, toggleExpand] = useToggle(false);
|
||||
const [addNetworkIsOpen, toggleAddNetwork] = useToggle(false);
|
||||
|
||||
const { data } = useQuery("networks", () => APIClient.irc.getNetworks(), {
|
||||
|
@ -42,23 +56,63 @@ export const IrcSettings = () => {
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between flex-col sm:flex-row mt-10 px-1">
|
||||
<ol className="flex flex-col sm:flex-row sm:gap-2 pb-4 sm:pb-0 sm:divide-x sm:divide-gray-200 sm:dark:divide-gray-700">
|
||||
<li className="flex items-center">
|
||||
<span
|
||||
className="mr-2 flex h-4 w-4 relative"
|
||||
title="Network healthy"
|
||||
>
|
||||
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
|
||||
<span className="inline-flex absolute rounded-full h-4 w-4 bg-green-500" />
|
||||
</span>
|
||||
<span className="text-sm text-gray-800 dark:text-gray-500">Network healthy</span>
|
||||
</li>
|
||||
|
||||
<li className="flex items-center sm:pl-2">
|
||||
<span
|
||||
className="mr-2 flex h-4 w-4 rounded-full opacity-75 bg-yellow-400 over:text-yellow-600"
|
||||
title="Network unhealthy"
|
||||
/>
|
||||
<span className="text-sm text-gray-800 dark:text-gray-500">Network unhealthy</span>
|
||||
</li>
|
||||
|
||||
<li className="flex items-center sm:pl-2">
|
||||
<span
|
||||
className="mr-2 flex h-4 w-4 rounded-full opacity-75 bg-gray-500"
|
||||
title="Network disabled"
|
||||
>
|
||||
</span>
|
||||
<span className="text-sm text-gray-800 dark:text-gray-500">Network disabled</span>
|
||||
</li>
|
||||
</ol>
|
||||
<div className="flex gap-x-2">
|
||||
<button className="flex items-center text-sm text-gray-800 dark:text-gray-400 p-1 px-2 rounded shadow bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600" onClick={toggleExpand} title={expandNetworks ? "collapse" : "expand"}>
|
||||
{expandNetworks
|
||||
? <span className="flex items-center">Collapse <ArrowsPointingInIcon className="ml-1 w-4 h-4"/></span>
|
||||
: <span className="flex items-center">Expand <ArrowsPointingOutIcon className="ml-1 w-4 h-4"/></span>
|
||||
}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{data && data.length > 0 ? (
|
||||
<section className="mt-6 light:bg-white dark:bg-gray-800 light:shadow sm:rounded-md">
|
||||
<ol className="min-w-full">
|
||||
<ol className="min-w-full relative">
|
||||
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<div className="col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
Network
|
||||
</div>
|
||||
<div className="col-span-5 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
<div className="hidden sm:flex col-span-5 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
Server
|
||||
</div>
|
||||
<div className="col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
<div className="hidden sm:flex col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
Nick
|
||||
</div>
|
||||
</li>
|
||||
{data &&
|
||||
data.map((network, idx) => (
|
||||
<ListItem key={idx} idx={idx} network={network} />
|
||||
<ListItem key={idx} idx={idx} expanded={expandNetworks} network={network} />
|
||||
))}
|
||||
</ol>
|
||||
</section>
|
||||
|
@ -78,15 +132,16 @@ export const IrcSettings = () => {
|
|||
interface ListItemProps {
|
||||
idx: number;
|
||||
network: IrcNetworkWithHealth;
|
||||
expanded: boolean;
|
||||
}
|
||||
|
||||
const ListItem = ({ idx, network }: ListItemProps) => {
|
||||
const ListItem = ({ idx, network, expanded }: ListItemProps) => {
|
||||
const [updateIsOpen, toggleUpdate] = useToggle(false);
|
||||
const [edit, toggleEdit] = useToggle(false);
|
||||
|
||||
return (
|
||||
<li key={idx}>
|
||||
<div className={classNames("grid grid-cols-12 gap-2 lg:gap-4 items-center py-4", network.enabled && !network.healthy ? "bg-red-50 dark:bg-red-900 hover:bg-red-100 dark:hover:bg-red-800" : "hover:bg-gray-50 dark:hover:bg-gray-700 ")}>
|
||||
<div className={classNames("grid grid-cols-12 gap-2 lg:gap-4 items-center py-2", network.enabled && !network.healthy ? "bg-red-50 dark:bg-red-900 hover:bg-red-100 dark:hover:bg-red-800" : "hover:bg-gray-50 dark:hover:bg-gray-700 ")}>
|
||||
<IrcNetworkUpdateForm
|
||||
isOpen={updateIsOpen}
|
||||
toggle={toggleUpdate}
|
||||
|
@ -94,7 +149,7 @@ const ListItem = ({ idx, network }: ListItemProps) => {
|
|||
/>
|
||||
|
||||
<div
|
||||
className="col-span-3 items-center sm:px-6 text-sm font-medium text-gray-900 dark:text-white cursor-pointer"
|
||||
className="col-span-10 xs:col-span-3 sm:col-span-3 items-center sm:px-6 text-sm font-medium text-gray-900 dark:text-white cursor-pointer"
|
||||
onClick={toggleEdit}
|
||||
>
|
||||
<div className="flex">
|
||||
|
@ -126,7 +181,7 @@ const ListItem = ({ idx, network }: ListItemProps) => {
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="col-span-5 sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer"
|
||||
className="hidden sm:flex col-span-5 sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer"
|
||||
onClick={toggleEdit}
|
||||
>
|
||||
<div
|
||||
|
@ -155,7 +210,7 @@ const ListItem = ({ idx, network }: ListItemProps) => {
|
|||
</div>
|
||||
{network.nickserv && network.nickserv.account ? (
|
||||
<div
|
||||
className="col-span-3 items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer"
|
||||
className="hidden sm:flex col-span-3 items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer"
|
||||
onClick={toggleEdit}
|
||||
>
|
||||
<div className="overflow-x-auto flex">
|
||||
|
@ -166,15 +221,10 @@ const ListItem = ({ idx, network }: ListItemProps) => {
|
|||
<div className="col-span-3" />
|
||||
)}
|
||||
<div className="col-span-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
<span
|
||||
className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer"
|
||||
onClick={toggleUpdate}
|
||||
>
|
||||
Edit
|
||||
</span>
|
||||
<ListItemDropdown network={network} toggleUpdate={toggleUpdate} />
|
||||
</div>
|
||||
</div>
|
||||
{edit && (
|
||||
{(edit || expanded) && (
|
||||
<div className="px-4 py-4 flex border-b border-x-0 dark:border-gray-600 dark:bg-gray-700">
|
||||
<div className="min-w-full">
|
||||
{network.channels.length > 0 ? (
|
||||
|
@ -238,3 +288,168 @@ const ListItem = ({ idx, network }: ListItemProps) => {
|
|||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
interface ListItemDropdownProps {
|
||||
network: IrcNetwork;
|
||||
toggleUpdate: () => void;
|
||||
}
|
||||
|
||||
const ListItemDropdown = ({
|
||||
network,
|
||||
toggleUpdate
|
||||
}: ListItemDropdownProps) => {
|
||||
const cancelModalButtonRef = useRef(null);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false);
|
||||
const deleteMutation = useMutation(
|
||||
(id: number) => APIClient.irc.deleteNetwork(id),
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(["networks"]);
|
||||
queryClient.invalidateQueries(["networks", network.id]);
|
||||
|
||||
toast.custom((t) => <Toast type="success" body={`Network ${network.name} was deleted`} t={t}/>);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const restartMutation = useMutation(
|
||||
(id: number) => APIClient.irc.restartNetwork(id),
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.custom((t) => <Toast type="success"
|
||||
body={`${network.name} was successfully restarted`}
|
||||
t={t}/>);
|
||||
|
||||
queryClient.invalidateQueries(["networks"]);
|
||||
queryClient.invalidateQueries(["networks", network.id]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const restart = (id: number) => {
|
||||
restartMutation.mutate(id);
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu as="div">
|
||||
<DeleteModal
|
||||
isOpen={deleteModalIsOpen}
|
||||
toggle={toggleDeleteModal}
|
||||
buttonRef={cancelModalButtonRef}
|
||||
deleteAction={() => {
|
||||
deleteMutation.mutate(network.id);
|
||||
toggleDeleteModal();
|
||||
}}
|
||||
title={`Remove network: ${network.name}`}
|
||||
text="Are you sure you want to remove this network? This action cannot be undone."
|
||||
/>
|
||||
<Menu.Button className="px-4 py-2">
|
||||
<EllipsisHorizontalIcon
|
||||
className="w-5 h-5 text-gray-700 hover:text-gray-900 dark:text-gray-100 dark:hover:text-gray-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</Menu.Button>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-100"
|
||||
enterFrom="transform opacity-0 scale-95"
|
||||
enterTo="transform opacity-100 scale-100"
|
||||
leave="transition ease-in duration-75"
|
||||
leaveFrom="transform opacity-100 scale-100"
|
||||
leaveTo="transform opacity-0 scale-95"
|
||||
>
|
||||
<Menu.Items
|
||||
className="absolute right-0 w-32 sm:w-56 mt-2 origin-top-right bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700 rounded-md shadow-lg ring-1 ring-black ring-opacity-10 focus:outline-none"
|
||||
>
|
||||
<div className="px-1 py-1">
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<button
|
||||
className={classNames(
|
||||
active ? "bg-blue-600 text-white" : "text-gray-900 dark:text-gray-300",
|
||||
"font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"
|
||||
)}
|
||||
onClick={() => toggleUpdate()}
|
||||
>
|
||||
<PencilSquareIcon
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-blue-500",
|
||||
"w-5 h-5 mr-2"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Edit
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
{/*<Menu.Item>*/}
|
||||
{/* {({ active }) => (*/}
|
||||
{/* <button*/}
|
||||
{/* className={classNames(*/}
|
||||
{/* active ? "bg-blue-600 text-white" : "text-gray-900 dark:text-gray-300",*/}
|
||||
{/* "font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"*/}
|
||||
{/* )}*/}
|
||||
{/* onClick={() => onToggle(!network.enabled)}*/}
|
||||
{/* >*/}
|
||||
{/* <SwitchHorizontalIcon*/}
|
||||
{/* className={classNames(*/}
|
||||
{/* active ? "text-white" : "text-blue-500",*/}
|
||||
{/* "w-5 h-5 mr-2"*/}
|
||||
{/* )}*/}
|
||||
{/* aria-hidden="true"*/}
|
||||
{/* />*/}
|
||||
{/* {network.enabled ? "Disable" : "Enable"}*/}
|
||||
{/* </button>*/}
|
||||
{/* )}*/}
|
||||
{/*</Menu.Item>*/}
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<button
|
||||
className={classNames(
|
||||
active ? "bg-blue-600 text-white" : "text-gray-900 dark:text-gray-300",
|
||||
"font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"
|
||||
)}
|
||||
onClick={() => restart(network.id)}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className={classNames(
|
||||
active ? "text-white" : "text-blue-500",
|
||||
"w-5 h-5 mr-2"
|
||||
)}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M5.636 5.636a9 9 0 1012.728 0M12 3v9" />
|
||||
</svg>
|
||||
|
||||
Restart
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
</div>
|
||||
<div className="px-1 py-1">
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<button
|
||||
className={classNames(
|
||||
active ? "bg-red-600 text-white" : "text-gray-900 dark:text-gray-300",
|
||||
"font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"
|
||||
)}
|
||||
onClick={() => toggleDeleteModal()}
|
||||
>
|
||||
<TrashIcon
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-red-500",
|
||||
"w-5 h-5 mr-2"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Delete
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
</div>
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue