mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Start library management UI implementation
Minor layout fixes Minor refactorings
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import ConfigEntryDto from "Frontend/generated/de/grimsi/gameyfin/config/dto/ConfigEntryDto";
|
||||
import React from "react";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import CheckboxInput from "Frontend/components/general/CheckboxInput";
|
||||
import SelectInput from "Frontend/components/general/SelectInput";
|
||||
import Input from "Frontend/components/general/input/Input";
|
||||
import CheckboxInput from "Frontend/components/general/input/CheckboxInput";
|
||||
import SelectInput from "Frontend/components/general/input/SelectInput";
|
||||
|
||||
export default function ConfigFormField({configElement, ...props}: any) {
|
||||
function inputElement(configElement: ConfigEntryDto) {
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
import React from "react";
|
||||
import React, {useEffect} from "react";
|
||||
import ConfigFormField from "Frontend/components/administration/ConfigFormField";
|
||||
import withConfigPage from "Frontend/components/administration/withConfigPage";
|
||||
import Section from "Frontend/components/general/Section";
|
||||
import * as Yup from 'yup';
|
||||
import {Button, Divider, Tooltip} from "@heroui/react";
|
||||
import {Plus} from "@phosphor-icons/react";
|
||||
import {LibraryEndpoint} from "Frontend/generated/endpoints";
|
||||
import LibraryDto from "Frontend/generated/de/grimsi/gameyfin/libraries/LibraryDto";
|
||||
import {LibraryOverviewCard} from "Frontend/components/general/cards/LibraryOverviewCard";
|
||||
import {ListData, useListData} from "@react-stately/data";
|
||||
|
||||
function LibraryManagementLayout({getConfig, formik}: any) {
|
||||
const libraries: ListData<LibraryDto> = useListData({});
|
||||
|
||||
useEffect(() => {
|
||||
LibraryEndpoint.getAllLibraries().then(
|
||||
(response) => libraries.items = response as LibraryDto[]
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
|
||||
<Section title="Library"/>
|
||||
{/* TODO */}
|
||||
|
||||
<Section title="Permissions"/>
|
||||
<ConfigFormField configElement={getConfig("library.allow-public-access")}/>
|
||||
|
||||
@@ -23,6 +34,24 @@ function LibraryManagementLayout({getConfig, formik}: any) {
|
||||
<ConfigFormField configElement={getConfig("library.metadata.update.schedule")}
|
||||
isDisabled={!formik.values.library.metadata.update.enabled}/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-baseline justify-between">
|
||||
<h2 className={"text-xl font-bold mt-8 mb-1"}>Libraries</h2>
|
||||
<Tooltip content="Add new library">
|
||||
<Button isIconOnly variant="flat" onPress={() => {
|
||||
libraries.append({id: 1, name: "Library", path: "/path/to/library"} as LibraryDto)
|
||||
}}>
|
||||
<Plus/>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Divider className="mb-4"/>
|
||||
{libraries.items.length > 0 ?
|
||||
<div className="grid grid-cols-300px gap-4">
|
||||
{libraries.items.map((library) => <LibraryOverviewCard library={library} key={library.name}/>)}
|
||||
</div> :
|
||||
"No libraries configured. Add your first library!"
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {PluginManagementEndpoint} from "Frontend/generated/endpoints";
|
||||
import PluginDto from "Frontend/generated/de/grimsi/gameyfin/core/plugins/management/PluginDto";
|
||||
import {PluginManagementCard} from "Frontend/components/general/PluginManagementCard";
|
||||
import {PluginManagementCard} from "Frontend/components/general/cards/PluginManagementCard";
|
||||
import {Button, Divider, Tooltip, useDisclosure} from "@heroui/react";
|
||||
import {ListNumbers} from "@phosphor-icons/react";
|
||||
import PluginPrioritiesModal from "Frontend/components/general/PluginPrioritiesModal";
|
||||
import PluginPrioritiesModal from "Frontend/components/general/modals/PluginPrioritiesModal";
|
||||
|
||||
export default function PluginManagement() {
|
||||
const [plugins, setPlugins] = useState<PluginDto[]>([]);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Section from "Frontend/components/general/Section";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import Input from "Frontend/components/general/input/Input";
|
||||
import {addToast, Button, Input as NextUiInput, Tooltip} from "@heroui/react";
|
||||
import {Form, Formik} from "formik";
|
||||
import {ArrowCounterClockwise, Check, Info, Trash} from "@phosphor-icons/react";
|
||||
|
||||
@@ -45,6 +45,7 @@ function SsoManagementLayout({getConfig, formik, setSaveMessage}: any) {
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-row">
|
||||
<div className="flex flex-col flex-1">
|
||||
<Section title="SSO configuration"/>
|
||||
<ConfigFormField configElement={getConfig("sso.oidc.enabled")}/>
|
||||
|
||||
<Section title="SSO user handling"/>
|
||||
|
||||
@@ -4,11 +4,11 @@ import withConfigPage from "Frontend/components/administration/withConfigPage";
|
||||
import Section from "Frontend/components/general/Section";
|
||||
import {ConfigEndpoint, UserEndpoint} from "Frontend/generated/endpoints";
|
||||
import UserInfoDto from "Frontend/generated/de/grimsi/gameyfin/users/dto/UserInfoDto";
|
||||
import {UserManagementCard} from "Frontend/components/general/UserManagementCard";
|
||||
import {UserManagementCard} from "Frontend/components/general/cards/UserManagementCard";
|
||||
import {SmallInfoField} from "Frontend/components/general/SmallInfoField";
|
||||
import {Info, UserPlus} from "@phosphor-icons/react";
|
||||
import {Button, Divider, Tooltip, useDisclosure} from "@heroui/react";
|
||||
import InviteUserModal from "Frontend/components/general/InviteUserModal";
|
||||
import InviteUserModal from "Frontend/components/general/modals/InviteUserModal";
|
||||
|
||||
function UserManagementLayout({getConfig, formik}: any) {
|
||||
const inviteUserModal = useDisclosure();
|
||||
@@ -36,7 +36,7 @@ function UserManagementLayout({getConfig, formik}: any) {
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-baseline justify-between">
|
||||
<h2 className={"text-xl font-bold mt-8 mb-1"}>Users</h2>
|
||||
<h2 className="text-xl font-bold mt-8 mb-1">Users</h2>
|
||||
{!autoRegisterNewUsers &&
|
||||
<SmallInfoField className="mb-4 text-warning" icon={Info}
|
||||
message="Automatic user registration for SSO users is disabled"/>
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import {Form, Formik} from "formik";
|
||||
import {addToast, Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import Input from "Frontend/components/general/input/Input";
|
||||
import {MessageEndpoint} from "Frontend/generated/endpoints";
|
||||
import * as Yup from "yup";
|
||||
import MessageTemplateDto from "Frontend/generated/de/grimsi/gameyfin/messages/templates/MessageTemplateDto";
|
||||
|
||||
@@ -128,7 +128,7 @@ export default function withConfigPage(WrappedComponent: React.ComponentType<any
|
||||
>
|
||||
{(formik) => (
|
||||
<Form>
|
||||
<div className="flex flex-row flex-grow justify-between mb-8">
|
||||
<div className="flex flex-row flex-grow justify-between">
|
||||
<h1 className="text-2xl font-bold">{title}</h1>
|
||||
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
|
||||
@@ -11,7 +11,7 @@ export default function PluginLogo({plugin}: PluginLogoProps) {
|
||||
return (
|
||||
<>
|
||||
{plugin.hasLogo ?
|
||||
<Image src={`/images/plugins/${plugin.id}/logo`} width={64} height={64} radius="none"/> :
|
||||
<Image isBlurred src={`/images/plugins/${plugin.id}/logo`} width={64} height={64} radius="none"/> :
|
||||
<Plug size={64} weight="fill"/>
|
||||
}
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import {Card} from "@heroui/react";
|
||||
import LibraryDto from "Frontend/generated/de/grimsi/gameyfin/libraries/LibraryDto";
|
||||
|
||||
export function LibraryOverviewCard({library}: { library: LibraryDto }) {
|
||||
return (
|
||||
<Card className="flex flex-row justify-between p-2">
|
||||
<div className="flex flex-col flex-1 items-center gap-4">
|
||||
<p className="text-2xl font-bold">{library.name}</p>
|
||||
<p>{library.path}</p>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,7 @@ import {PluginManagementEndpoint} from "Frontend/generated/endpoints";
|
||||
import PluginDto from "Frontend/generated/de/grimsi/gameyfin/core/plugins/management/PluginDto";
|
||||
import PluginState from "Frontend/generated/org/pf4j/PluginState";
|
||||
import React, {ReactNode, useEffect, useState} from "react";
|
||||
import PluginDetailsModal from "Frontend/components/general/PluginDetailsModal";
|
||||
import PluginDetailsModal from "Frontend/components/general/modals/PluginDetailsModal";
|
||||
import PluginLogo from "Frontend/components/general/PluginLogo";
|
||||
|
||||
export function PluginManagementCard({plugin, updatePlugin}: {
|
||||
+3
-3
@@ -5,12 +5,12 @@ import {useEffect, useState} from "react";
|
||||
import {MessageEndpoint, PasswordResetEndpoint, UserEndpoint} from "Frontend/generated/endpoints";
|
||||
import {AvatarEndpoint} from "Frontend/endpoints/endpoints";
|
||||
import Avatar from "Frontend/components/general/Avatar";
|
||||
import ConfirmUserDeletionModal from "Frontend/components/general/ConfirmUserDeletionModal";
|
||||
import PasswordResetTokenModal from "Frontend/components/general/PasswortResetTokenModal";
|
||||
import ConfirmUserDeletionModal from "Frontend/components/general/modals/ConfirmUserDeletionModal";
|
||||
import PasswordResetTokenModal from "Frontend/components/general/modals/PasswortResetTokenModal";
|
||||
import TokenDto from "Frontend/generated/de/grimsi/gameyfin/shared/token/TokenDto";
|
||||
import UserInfoDto from "Frontend/generated/de/grimsi/gameyfin/users/dto/UserInfoDto";
|
||||
import RoleChip from "Frontend/components/general/RoleChip";
|
||||
import AssignRolesModal from "Frontend/components/general/AssignRolesModal";
|
||||
import AssignRolesModal from "Frontend/components/general/modals/AssignRolesModal";
|
||||
|
||||
export function UserManagementCard({user}: { user: UserInfoDto }) {
|
||||
const userDeletionConfirmationModal = useDisclosure();
|
||||
+1
-1
@@ -4,7 +4,7 @@ import {Form, Formik} from "formik";
|
||||
import {PluginConfigEndpoint, PluginManagementEndpoint} from "Frontend/generated/endpoints";
|
||||
import PluginDto from "Frontend/generated/de/grimsi/gameyfin/core/plugins/management/PluginDto";
|
||||
import PluginConfigElement from "Frontend/generated/de/grimsi/gameyfin/pluginapi/core/PluginConfigElement";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import Input from "Frontend/components/general/input/Input";
|
||||
import PluginLogo from "Frontend/components/general/PluginLogo";
|
||||
|
||||
interface PluginDetailsModalProps {
|
||||
+1
-1
@@ -4,7 +4,7 @@ import {RegistrationEndpoint} from "Frontend/generated/endpoints";
|
||||
import UserRegistrationDto from "Frontend/generated/de/grimsi/gameyfin/users/dto/UserRegistrationDto";
|
||||
import {Form, Formik} from "formik";
|
||||
import * as Yup from "yup";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import Input from "Frontend/components/general/input/Input";
|
||||
|
||||
interface SignUpModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -34,4 +34,5 @@ const menuItems: MenuItem[] = [
|
||||
}
|
||||
]
|
||||
|
||||
export const AdministrationView = withSideMenu(menuItems);
|
||||
export const AdministrationView = withSideMenu(menuItems);
|
||||
export default AdministrationView;
|
||||
@@ -1,7 +1,7 @@
|
||||
import {addToast, Button, Card, CardBody, CardHeader} from "@heroui/react";
|
||||
import {useNavigate, useSearchParams} from "react-router-dom";
|
||||
import {Form, Formik} from "formik";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import Input from "Frontend/components/general/input/Input";
|
||||
import * as Yup from "yup";
|
||||
import {RegistrationEndpoint} from "Frontend/generated/endpoints";
|
||||
import React, {useEffect, useState} from "react";
|
||||
|
||||
@@ -3,9 +3,9 @@ import {useEffect, useState} from "react";
|
||||
import {Button, Card, CardBody, CardHeader, Link, useDisclosure} from "@heroui/react";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
import {Form, Formik} from "formik";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import PasswordResetModal from "Frontend/components/general/PasswordResetModal";
|
||||
import SignUpModal from "Frontend/components/general/SignUpModal";
|
||||
import Input from "Frontend/components/general/input/Input";
|
||||
import PasswordResetModal from "Frontend/components/general/modals/PasswordResetModal";
|
||||
import SignUpModal from "Frontend/components/general/modals/SignUpModal";
|
||||
import {RegistrationEndpoint} from "Frontend/generated/endpoints";
|
||||
|
||||
export default function LoginView() {
|
||||
|
||||
@@ -83,7 +83,7 @@ export default function MainLayout() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider/>
|
||||
<Divider className="mt-8"/>
|
||||
<div className="flex flex-col w-full 2xl:w-3/4 m-auto">
|
||||
<footer className="flex flex-row items-center justify-between py-4 px-12">
|
||||
<p>Gameyfin {PackageJson.version}</p>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {addToast, Button, Card, CardBody, CardHeader} from "@heroui/react";
|
||||
import {useNavigate, useSearchParams} from "react-router-dom";
|
||||
import {Form, Formik} from "formik";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import Input from "Frontend/components/general/input/Input";
|
||||
import * as Yup from "yup";
|
||||
import {PasswordResetEndpoint} from "Frontend/generated/endpoints";
|
||||
import React, {useEffect, useState} from "react";
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import Wizard from "Frontend/components/wizard/Wizard";
|
||||
import WizardStep from "Frontend/components/wizard/WizardStep";
|
||||
import Input from "Frontend/components/general/Input";
|
||||
import Input from "Frontend/components/general/input/Input";
|
||||
import {HandWaving, Palette, User} from "@phosphor-icons/react";
|
||||
import {addToast, Card} from "@heroui/react";
|
||||
import {SetupEndpoint} from "Frontend/generated/endpoints";
|
||||
|
||||
@@ -3,7 +3,7 @@ import {addToast, Button, Input} from "@heroui/react";
|
||||
import {LibraryEndpoint, SystemEndpoint} from "Frontend/generated/endpoints";
|
||||
import {useState} from "react";
|
||||
import GameDto from "Frontend/generated/de/grimsi/gameyfin/games/dto/GameDto";
|
||||
import {GameOverviewCard} from "Frontend/components/games/GameOverviewCard";
|
||||
import {GameOverviewCard} from "Frontend/components/general/cards/GameOverviewCard";
|
||||
|
||||
export default function TestView() {
|
||||
const [gameTitle, setGameTitle] = useState("");
|
||||
|
||||
@@ -123,6 +123,11 @@ class GameService(
|
||||
return results.filter { it.value.title == bestMatchingTitle }
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the results from the metadata plugins into a single Game entity
|
||||
* The merging is done by taking the first non-null value for each field
|
||||
* The plugin with the highest possible priority is used as the source for each field
|
||||
*/
|
||||
private fun mergeResults(results: List<Map.Entry<GameMetadataProvider, GameMetadata?>>, path: Path): Game {
|
||||
val mergedGame = Game(path = path.toString())
|
||||
val metadataMap = mutableMapOf<String, FieldMetadata>()
|
||||
|
||||
@@ -6,7 +6,7 @@ dependencies {
|
||||
ksp("care.better.pf4j:pf4j-kotlin-symbol-processing:${rootProject.extra["pf4jKspVersion"]}")
|
||||
|
||||
// IGDB API client
|
||||
implementation("io.github.husnjak:igdb-api-jvm:1.2.0")
|
||||
implementation("io.github.husnjak:igdb-api-jvm:1.3.1")
|
||||
|
||||
// Fuzzy string matching
|
||||
implementation("me.xdrop:fuzzywuzzy:1.4.0")
|
||||
|
||||
Reference in New Issue
Block a user