mirror of
https://github.com/idanoo/autobrr
synced 2025-07-26 02:09:13 +00:00
feat(web): better tooltips and uniformity (#474)
* - fix: changed all {text,bg}-{teal,indigo}-* color properties to {text,bg}-{blue}-* so there is only one dominant primary color in the UI -- blue - enhancement: added `cursor: pointer` to the PageButton component (used in pagination) - enhancement: modified TitleCell to use the new Tooltip component and modified the width selectors to a more sane default value, now instead of scrolling one just has to tap the cell to see it's untruncated value - enhancement: modified the Tooltip component to use react-popper-tooltip (which in turn uses popper.js) which is a much better alternative, since it uses auto-positioning in case there's not enough space and some things aren't as broken as in the previous version (e.g. there was a problem with forcing the previous tooltip to use a specific width) - enhancement: added a useMedia hook selector from the react-use repository, which might come in handy in the future for better/easier decoupling of Desktop and Mobile UI/UX patterns via JS (versus CSS-only) - enhancement: made the mobile navbar more visible and clear. also fixed previous path === "/" bug which was fixed on desktop. - fix: fixed table headers/footers so they're rounded - enhancement: made pagination components more compact (buttons and show N result selector) * changed {ring, border}-indigo-* to ring-blue-* * build: add yarn.lock * fix: formatting warnings * fix: formatting warnings * fix: more formatting warnings * fix: more formatting
This commit is contained in:
parent
71d0424b61
commit
ac988f28f4
43 changed files with 531 additions and 318 deletions
|
@ -77,8 +77,7 @@ export default function Base() {
|
|||
)}
|
||||
>
|
||||
Docs
|
||||
<ArrowTopRightOnSquareIcon className="inline ml-1 h-5 w-5"
|
||||
aria-hidden="true"/>
|
||||
<ArrowTopRightOnSquareIcon className="inline ml-1 h-5 w-5" aria-hidden="true" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -125,7 +124,7 @@ export default function Base() {
|
|||
to="/settings"
|
||||
className={classNames(
|
||||
active ? "bg-gray-100 dark:bg-gray-600" : "",
|
||||
"block px-4 py-2 text-sm text-gray-700 dark:text-gray-200"
|
||||
"block px-4 py-2 text-sm text-gray-900 dark:text-gray-200"
|
||||
)}
|
||||
>
|
||||
Settings
|
||||
|
@ -138,7 +137,7 @@ export default function Base() {
|
|||
to="/logout"
|
||||
className={classNames(
|
||||
active ? "bg-gray-100 dark:bg-gray-600" : "",
|
||||
"block px-4 py-2 text-sm text-gray-700 dark:text-gray-200"
|
||||
"block px-4 py-2 text-sm text-gray-900 dark:text-gray-200"
|
||||
)}
|
||||
>
|
||||
Logout
|
||||
|
@ -175,17 +174,17 @@ export default function Base() {
|
|||
key={item.path}
|
||||
to={item.path}
|
||||
className={({ isActive }) => classNames(
|
||||
// TODO: Double check whether this is correct
|
||||
"dark:bg-gray-900 dark:text-white block px-3 py-2 rounded-md text-base",
|
||||
isActive ? "font-bold bg-gray-300 text-black" : "font-medium"
|
||||
"shadow-sm border bg-gray-100 border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-white block px-3 py-2 rounded-md text-base",
|
||||
isActive ? "underline underline-offset-2 decoration-2 decoration-sky-500 font-bold text-black" : "font-medium"
|
||||
)}
|
||||
end={item.path === "/"}
|
||||
>
|
||||
{item.name}
|
||||
</NavLink>
|
||||
)}
|
||||
<Link
|
||||
to="/logout"
|
||||
className="dark:bg-gray-900 dark:text-white block px-3 py-2 rounded-md text-base font-medium"
|
||||
className="shadow-sm border bg-gray-100 border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-white block px-3 py-2 rounded-md text-base font-medium"
|
||||
>
|
||||
Logout
|
||||
</Link>
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import {useEffect, useRef, useState} from "react";
|
||||
import {ExclamationTriangleIcon} from "@heroicons/react/24/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 {APIClient} from "../api/APIClient";
|
||||
import {Checkbox} from "../components/Checkbox";
|
||||
import {classNames} from "../utils";
|
||||
import {SettingsContext} from "../utils/Context";
|
||||
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";
|
||||
|
||||
type LogEvent = {
|
||||
time: string;
|
||||
|
@ -75,15 +74,15 @@ export const Logs = () => {
|
|||
|
||||
return (
|
||||
<main>
|
||||
<header className="py-10">
|
||||
<header className="pt-10 pb-5">
|
||||
<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">
|
||||
<div className="flex justify-center mt-1">
|
||||
<ExclamationTriangleIcon
|
||||
className="h-5 w-5 text-yellow-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p className="ml-2 text-sm text-gray-800 dark:text-gray-400">This only shows new logs, no history.</p>
|
||||
<p className="ml-2 text-sm text-black dark:text-gray-400">This page shows only new logs, i.e. no history.</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
@ -99,7 +98,7 @@ export const Logs = () => {
|
|||
type="text"
|
||||
autoComplete="off"
|
||||
className={classNames(
|
||||
"focus:ring-indigo-500 dark:focus:ring-blue-500 focus:border-indigo-500 dark:focus:border-blue-500 border-gray-300 dark:border-gray-700",
|
||||
"focus:ring-blue-500 dark:focus:ring-blue-500 focus:border-blue-500 dark:focus:border-blue-500 border-gray-300 dark:border-gray-700",
|
||||
"block w-full dark:bg-gray-800 shadow-sm dark:text-gray-100 sm:text-sm rounded-md"
|
||||
)}
|
||||
placeholder="Enter a string to filter logs by..."
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {NavLink, Outlet, useLocation} from "react-router-dom";
|
||||
import { NavLink, Outlet, useLocation } from "react-router-dom";
|
||||
import {
|
||||
BellIcon,
|
||||
ChatBubbleLeftRightIcon,
|
||||
|
@ -9,7 +9,7 @@ import {
|
|||
RssIcon
|
||||
} from "@heroicons/react/24/outline";
|
||||
|
||||
import {classNames} from "../utils";
|
||||
import { classNames } from "../utils";
|
||||
|
||||
interface NavTabType {
|
||||
name: string;
|
||||
|
@ -45,9 +45,9 @@ function SubNavLink({ item }: NavLinkProps) {
|
|||
to={item.href}
|
||||
end
|
||||
className={({ isActive }) => classNames(
|
||||
"border-transparent text-gray-900 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-gray-300 group border-l-4 px-3 py-2 flex items-center text-sm font-medium",
|
||||
"border-transparent text-gray-900 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 hover:text-gray-900 dark:hover:text-gray-300 group border-l-4 px-3 py-2 flex items-center text-sm font-medium",
|
||||
isActive ?
|
||||
"font-bold bg-teal-50 dark:bg-gray-700 border-teal-500 dark:border-blue-500 text-teal-700 dark:text-white hover:bg-teal-50 dark:hover:bg-gray-500 hover:text-teal-700 dark:hover:text-gray-200" : ""
|
||||
"font-bold bg-blue-50 dark:bg-gray-700 border-sky-500 dark:border-blue-500 text-sky-700 dark:text-white hover:bg-blue-100 dark:hover:bg-gray-500 hover:text-sky-700 dark:hover:text-gray-200" : ""
|
||||
)}
|
||||
aria-current={splitLocation[2] === item.href ? "page" : undefined}
|
||||
>
|
||||
|
|
|
@ -81,7 +81,7 @@ export const Login = () => {
|
|||
<div className="mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-blue-500"
|
||||
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-blue-500"
|
||||
>
|
||||
Sign in
|
||||
</button>
|
||||
|
|
|
@ -66,9 +66,9 @@ export const Onboarding = () => {
|
|||
<div className="mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-blue-500"
|
||||
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-blue-500"
|
||||
>
|
||||
Create an account!
|
||||
Create account!
|
||||
</button>
|
||||
</div>
|
||||
</Form>
|
||||
|
|
|
@ -34,7 +34,7 @@ function SelectColumnFilter({
|
|||
<label className="flex items-baseline gap-x-2">
|
||||
<span className="text-gray-700"><>{render("Header")}:</></span>
|
||||
<select
|
||||
className="border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||
className="border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||
name={id}
|
||||
id={id}
|
||||
value={filterValue}
|
||||
|
@ -80,7 +80,7 @@ function Table({ columns, data }: TableProps) {
|
|||
// Render the UI for your table
|
||||
return (
|
||||
<div className="inline-block min-w-full mt-4 mb-2 align-middle">
|
||||
<div className="bg-white shadow dark:bg-gray-800 rounded-lg">
|
||||
<div className="bg-white shadow-lg dark:bg-gray-800 rounded-md rounded-md overflow-auto">
|
||||
<table {...getTableProps()} className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<thead className="bg-gray-50 dark:bg-gray-800">
|
||||
{headerGroups.map((headerGroup) => {
|
||||
|
@ -95,7 +95,7 @@ function Table({ columns, data }: TableProps) {
|
|||
<th
|
||||
key={`${rowKey}-${columnKey}`}
|
||||
scope="col"
|
||||
className="first:pl-5 pl-3 pr-3 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase group"
|
||||
className="first:pl-5 first:rounded-tl-md last:rounded-tr-md pl-3 pr-3 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase group"
|
||||
{...columnRest}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
|
|
|
@ -72,7 +72,7 @@ export function FilterActions({ filter, values }: FilterActionsProps) {
|
|||
<div className="ml-4 mt-4 flex-shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-blue-500"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-blue-500"
|
||||
onClick={() => push(newAction)}
|
||||
>
|
||||
Add new
|
||||
|
@ -436,7 +436,7 @@ function FilterActionsItem({ action, clients, idx, remove }: FilterActionsItemPr
|
|||
setFieldValue(field?.name ?? "", value);
|
||||
}}
|
||||
className={classNames(
|
||||
field.value ? "bg-teal-500 dark:bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
field.value ? "bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
)}
|
||||
>
|
||||
|
@ -456,7 +456,7 @@ function FilterActionsItem({ action, clients, idx, remove }: FilterActionsItemPr
|
|||
<div className="min-w-0 flex-1 sm:flex sm:items-center sm:justify-between">
|
||||
<div className="truncate">
|
||||
<div className="flex text-sm">
|
||||
<p className="ml-4 font-medium text-indigo-600 dark:text-gray-100 truncate">
|
||||
<p className="ml-4 font-medium text-blue-600 dark:text-gray-100 truncate">
|
||||
{action.name}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -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/24/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;
|
||||
|
@ -122,7 +122,7 @@ const FormButtonsGroup = ({ values, deleteAction, reset }: FormButtonsGroupProps
|
|||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="ml-4 relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
className="ml-4 relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
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,
|
||||
|
@ -13,14 +14,14 @@ import {
|
|||
TrashIcon
|
||||
} 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[],
|
||||
|
@ -85,7 +86,7 @@ export default function Filters() {
|
|||
<div className="flex-shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-blue-500"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-blue-500"
|
||||
onClick={toggleCreateFilter}
|
||||
>
|
||||
Add new
|
||||
|
@ -139,8 +140,8 @@ function FilterList({ toggleCreateFilter }: any) {
|
|||
|
||||
return (
|
||||
<div className="max-w-screen-xl mx-auto pb-12 px-4 sm:px-6 lg:px-8 relative">
|
||||
<div className="align-middle min-w-full rounded-t-md rounded-b-lg shadow-lg bg-gray-50 dark:bg-gray-800">
|
||||
<div className="flex justify-between px-4 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
|
||||
<div className="align-middle min-w-full rounded-t-lg rounded-b-lg shadow-lg bg-gray-50 dark:bg-gray-800">
|
||||
<div className="rounded-t-lg flex justify-between px-4 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
|
||||
<div className="flex gap-4">
|
||||
<StatusButton data={filtered.all} label="All" value="" currentValue={status} dispatch={dispatchFilter} />
|
||||
<StatusButton data={filtered.enabled} label="Enabled" value="enabled" currentValue={status} dispatch={dispatchFilter} />
|
||||
|
@ -389,7 +390,7 @@ function FilterListItem({ filter, idx }: FilterListItemProps) {
|
|||
<li
|
||||
key={filter.id}
|
||||
className={classNames(
|
||||
"flex items-center hover:bg-gray-100 dark:hover:bg-[#222225]",
|
||||
"flex items-center hover:bg-gray-100 dark:hover:bg-[#222225] rounded-b-lg",
|
||||
idx % 2 === 0 ?
|
||||
"bg-white dark:bg-[#2e2e31]" :
|
||||
"bg-gray-50 dark:bg-gray-800"
|
||||
|
@ -402,7 +403,7 @@ function FilterListItem({ filter, idx }: FilterListItemProps) {
|
|||
checked={enabled}
|
||||
onChange={toggleActive}
|
||||
className={classNames(
|
||||
enabled ? "bg-teal-500 dark:bg-blue-500" : "bg-gray-200 dark:bg-gray-700",
|
||||
enabled ? "bg-blue-500 dark:bg-blue-500" : "bg-gray-200 dark:bg-gray-700",
|
||||
"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
)}
|
||||
>
|
||||
|
@ -514,37 +515,35 @@ const ListboxFilter = ({
|
|||
onChange,
|
||||
children
|
||||
}: ListboxFilterProps) => (
|
||||
<div className="">
|
||||
<Listbox
|
||||
refName={id}
|
||||
value={currentValue}
|
||||
onChange={onChange}
|
||||
>
|
||||
<div className="relative">
|
||||
<Listbox.Button className="relative w-full py-2 pr-5 text-left cursor-default dark:text-gray-400 sm:text-sm">
|
||||
<span className="block truncate">{label}</span>
|
||||
<span className="absolute inset-y-0 right-0 flex items-center pointer-events-none">
|
||||
<ChevronDownIcon
|
||||
className="w-3 h-3 text-gray-600 hover:text-gray-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
<Listbox
|
||||
refName={id}
|
||||
value={currentValue}
|
||||
onChange={onChange}
|
||||
>
|
||||
<div className="relative">
|
||||
<Listbox.Button className="relative w-full py-2 pr-5 text-left dark:text-gray-400 sm:text-sm">
|
||||
<span className="block truncate">{label}</span>
|
||||
<span className="absolute inset-y-0 right-0 flex items-center pointer-events-none">
|
||||
<ChevronDownIcon
|
||||
className="w-3 h-3 text-gray-600 hover:text-gray-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options
|
||||
className="w-48 absolute z-10 w-full mt-1 right-0 overflow-auto text-base bg-white dark:bg-gray-800 rounded-md shadow-lg max-h-60 border border-opacity-5 border-black dark:border-gray-700 dark:border-opacity-40 focus:outline-none sm:text-sm"
|
||||
>
|
||||
<Listbox.Options
|
||||
className="w-48 absolute z-10 w-full mt-1 right-0 overflow-auto text-base bg-white dark:bg-gray-800 rounded-md shadow-lg max-h-60 border border-opacity-5 border-black dark:border-gray-700 dark:border-opacity-40 focus:outline-none sm:text-sm"
|
||||
>
|
||||
{children}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</Listbox>
|
||||
</div>
|
||||
{children}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</Listbox>
|
||||
);
|
||||
|
||||
// a unique option from a list
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import * as React from "react";
|
||||
import {useQuery} from "react-query";
|
||||
import {Listbox, Transition} from "@headlessui/react";
|
||||
import {CheckIcon, ChevronDownIcon} from "@heroicons/react/24/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;
|
||||
|
@ -31,7 +31,7 @@ const ListboxFilter = ({
|
|||
onChange={onChange}
|
||||
>
|
||||
<div className="relative mt-1">
|
||||
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left bg-white dark:bg-gray-800 rounded-lg shadow-md cursor-default dark:text-gray-400 sm:text-sm">
|
||||
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left bg-white dark:bg-gray-800 rounded-lg shadow-md cursor-pointer dark:text-gray-400 sm:text-sm">
|
||||
<span className="block truncate">{label}</span>
|
||||
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
||||
<ChevronDownIcon
|
||||
|
@ -63,7 +63,7 @@ export const IndexerSelectColumnFilter = ({
|
|||
column: { filterValue, setFilter, id }
|
||||
}: FilterProps<object>) => {
|
||||
const { data, isSuccess } = useQuery(
|
||||
"release_indexers",
|
||||
"indexer_options",
|
||||
() => APIClient.release.indexerOptions(),
|
||||
{
|
||||
keepPreviousData: true,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react";
|
||||
import {useQuery} from "react-query";
|
||||
import {Column, useFilters, usePagination, useSortBy, useTable} from "react-table";
|
||||
import { useQuery } from "react-query";
|
||||
import { Column, useFilters, usePagination, useSortBy, useTable } from "react-table";
|
||||
import {
|
||||
ChevronDoubleLeftIcon,
|
||||
ChevronDoubleRightIcon,
|
||||
|
@ -8,13 +8,13 @@ import {
|
|||
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;
|
||||
|
@ -182,7 +182,7 @@ export const ReleaseTable = () => {
|
|||
))
|
||||
)}
|
||||
</div>
|
||||
<div className="bg-white shadow-lg dark:bg-gray-800 rounded-lg">
|
||||
<div className="bg-white shadow-lg dark:bg-gray-800 rounded-md overflow-auto">
|
||||
<table {...getTableProps()} className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<thead className="bg-gray-50 dark:bg-gray-800">
|
||||
{headerGroups.map((headerGroup) => {
|
||||
|
@ -197,7 +197,7 @@ export const ReleaseTable = () => {
|
|||
<th
|
||||
key={`${rowKey}-${columnKey}`}
|
||||
scope="col"
|
||||
className="first:pl-5 pl-3 pr-3 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase group"
|
||||
className="first:pl-5 pl-3 pr-3 py-3 first:rounded-tl-md last:rounded-tr-md text-xs font-medium tracking-wider text-left text-gray-500 uppercase group"
|
||||
{...columnRest}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
|
@ -259,13 +259,13 @@ export const ReleaseTable = () => {
|
|||
</div>
|
||||
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
||||
<div className="flex items-baseline gap-x-2">
|
||||
<span className="text-sm text-gray-700">
|
||||
<span className="text-sm text-gray-700 dark:text-gray-500">
|
||||
Page <span className="font-medium">{pageIndex + 1}</span> of <span className="font-medium">{pageOptions.length}</span>
|
||||
</span>
|
||||
<label>
|
||||
<span className="sr-only bg-gray-700">Items Per Page</span>
|
||||
<select
|
||||
className="block w-full border-gray-300 rounded-md shadow-sm cursor-pointer dark:bg-gray-800 dark:border-gray-800 dark:text-gray-600 dark:hover:text-gray-500 focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||
className="py-1 pl-2 pr-8 text-sm block w-full border-gray-300 rounded-md shadow-sm cursor-pointer dark:bg-gray-800 dark:border-gray-600 dark:text-gray-400 dark:hover:text-gray-500 focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||
value={pageSize}
|
||||
onChange={e => {
|
||||
setPageSize(Number(e.target.value));
|
||||
|
@ -280,7 +280,7 @@ export const ReleaseTable = () => {
|
|||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<nav className="relative z-0 inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
||||
<nav className="inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
||||
<DataTable.PageButton
|
||||
className="rounded-l-md"
|
||||
onClick={() => gotoPage(0)}
|
||||
|
|
|
@ -12,7 +12,7 @@ function ActionSettings() {
|
|||
<div className="ml-4 mt-4 flex-shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
Add new
|
||||
</button>
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
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/24/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);
|
||||
|
||||
const { isLoading, data } = useQuery(
|
||||
const { data } = useQuery(
|
||||
["apikeys"],
|
||||
() => APIClient.apikeys.getAll(),
|
||||
{
|
||||
|
@ -40,7 +40,7 @@ function APISettings() {
|
|||
<div className="ml-4 mt-4 flex-shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
onClick={toggleAddForm}
|
||||
>
|
||||
Add new
|
||||
|
|
|
@ -47,7 +47,7 @@ function DownloadClientSettingsListItem({ client, idx }: DLSettingsItemProps) {
|
|||
checked={client.enabled}
|
||||
onChange={onToggleMutation}
|
||||
className={classNames(
|
||||
client.enabled ? "bg-teal-500 dark:bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
client.enabled ? "bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
)}
|
||||
>
|
||||
|
@ -65,8 +65,8 @@ function DownloadClientSettingsListItem({ client, idx }: DLSettingsItemProps) {
|
|||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">{client.host}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">{DownloadClientTypeNameMap[client.type]}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<span className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdateClient}>
|
||||
Edit
|
||||
<span className="text-blue-600 dark:text-gray-300 hover:text-blue-900 cursor-pointer" onClick={toggleUpdateClient}>
|
||||
Edit
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -82,8 +82,9 @@ function DownloadClientSettings() {
|
|||
{ refetchOnWindowFocus: false }
|
||||
);
|
||||
|
||||
if (error)
|
||||
return (<p>An error has occurred: </p>);
|
||||
if (error) {
|
||||
return <p>Failed to fetch download clients</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="lg:col-span-9">
|
||||
|
@ -95,16 +96,16 @@ function DownloadClientSettings() {
|
|||
<div className="ml-4 mt-4">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">Clients</h3>
|
||||
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
Manage download clients.
|
||||
Manage download clients.
|
||||
</p>
|
||||
</div>
|
||||
<div className="ml-4 mt-4 flex-shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
onClick={toggleAddClient}
|
||||
>
|
||||
Add new
|
||||
Add new
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +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 {ArrowsRightLeftIcon, EllipsisHorizontalIcon, PencilSquareIcon, TrashIcon} from "@heroicons/react/24/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(
|
||||
|
@ -101,7 +101,7 @@ function ListItem({ feed }: ListItemProps) {
|
|||
checked={feed.enabled}
|
||||
onChange={toggleActive}
|
||||
className={classNames(
|
||||
feed.enabled ? "bg-teal-500 dark:bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
feed.enabled ? "bg-blue-500 dark:bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
)}
|
||||
>
|
||||
|
|
|
@ -53,7 +53,7 @@ const ListItem = ({ indexer }: ListItemProps) => {
|
|||
checked={indexer.enabled ?? false}
|
||||
onChange={toggleUpdate}
|
||||
className={classNames(
|
||||
indexer.enabled ? "bg-teal-500 dark:bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
indexer.enabled ? "bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
)}
|
||||
>
|
||||
|
@ -70,7 +70,7 @@ const ListItem = ({ indexer }: ListItemProps) => {
|
|||
<td className="px-6 py-4 w-full whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">{indexer.name}</td>
|
||||
<td className="px-6 py-4 w-full whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">{ImplementationBadges[indexer.implementation]}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<span className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 dark:hover:text-blue-500 cursor-pointer" onClick={toggleUpdate}>
|
||||
<span className="text-blue-600 dark:text-gray-300 hover:text-blue-900 dark:hover:text-blue-500 cursor-pointer" onClick={toggleUpdate}>
|
||||
Edit
|
||||
</span>
|
||||
</td>
|
||||
|
@ -107,7 +107,7 @@ function IndexerSettings() {
|
|||
<button
|
||||
type="button"
|
||||
onClick={toggleAddIndexer}
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-blue-500"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-blue-500"
|
||||
>
|
||||
Add new
|
||||
</button>
|
||||
|
|
|
@ -50,7 +50,7 @@ export const IrcSettings = () => {
|
|||
<button
|
||||
type="button"
|
||||
onClick={toggleAddNetwork}
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
Add new
|
||||
</button>
|
||||
|
|
|
@ -32,7 +32,7 @@ function NotificationSettings() {
|
|||
<button
|
||||
type="button"
|
||||
onClick={toggleAddNotifications}
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 dark:bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
Add new
|
||||
</button>
|
||||
|
@ -101,7 +101,7 @@ function ListItem({ notification }: ListItemProps) {
|
|||
checked={notification.enabled}
|
||||
onChange={toggleUpdateForm}
|
||||
className={classNames(
|
||||
notification.enabled ? "bg-teal-500 dark:bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
notification.enabled ? "bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||
"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
)}
|
||||
>
|
||||
|
@ -130,7 +130,7 @@ function ListItem({ notification }: ListItemProps) {
|
|||
</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex items-center">
|
||||
<span className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdateForm}>
|
||||
<span className="text-blue-600 dark:text-gray-300 hover:text-blue-900 cursor-pointer" onClick={toggleUpdateForm}>
|
||||
Edit
|
||||
</span>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue