mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
09953a3f78
* chore: bump version to v2.3.0-preview * Customize start page (#803) * Update ConfigService to support complex Objects Implemented tests for ConfigService * Added DB migration for config table * Fixed version in banner.txt not being displayed * Implement Library ordering Implement "Show recently added games on homepage" * Fix build.gradle.kts * FIx bug when creating libraries * Fix TypeScript errors Fix library sorting * Bump actions/checkout from 5 to 6 (#811) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Added automatic scanning using file system watchers (#813) * Implement collections (#814) * Backend implementation for collections * Fix database schema and migration script * Refactor some config values Fix ArrayInput not being deactivatable * Remove "AutoRegisterNewUsers" config option * Fix bug when removing ignored paths * Add UI for collections (WIP) * Fix table actions not synced with state Fix tests * Finish implementation of collection feature * Fix tests * Bump actions/checkout from 5 to 6 (#815) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fix "allow guests to create game requests" not being enabled when guest access is activated * Fix: Disable loading of EditGameMetadataModal and MatchGameModal in GameView when user is not admin * Bump actions/checkout from 5 to 6 (#819) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Overhaul startpage (#823) * WIP: Update start page layout * Performance improvements (lazy loading and virtualized grids/lists) Fix various smaller issues * Implement use of blurhash for all images in backend and covers in frontend * Fix bugs and test * Fix code analysis issues * Remove "UI settings" since they have been made obsolete * Remove length limit from "image.originalUrl" (#824) * Remove alpine based image (#825) * Fix bug when games from library are still in a collection, thus prevention deletion of said library * Delete image files in background * Fix layout --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
127 lines
5.4 KiB
TypeScript
127 lines
5.4 KiB
TypeScript
import {useNavigate, useParams} from "react-router";
|
|
import React, {useEffect} from "react";
|
|
import {addToast, Button} from "@heroui/react";
|
|
import {ArrowLeftIcon, CheckIcon} from "@phosphor-icons/react";
|
|
import {useSnapshot} from "valtio/react";
|
|
import CollectionAdminDto from "Frontend/generated/org/gameyfin/app/collections/dto/CollectionAdminDto";
|
|
import {collectionState} from "Frontend/state/CollectionState";
|
|
import {Form, Formik} from "formik";
|
|
import * as Yup from "yup";
|
|
import Input from "Frontend/components/general/input/Input";
|
|
import Section from "Frontend/components/general/Section";
|
|
import {deepDiff} from "Frontend/util/utils";
|
|
import {CollectionEndpoint} from "Frontend/generated/endpoints";
|
|
import CollectionUpdateDto from "Frontend/generated/org/gameyfin/app/collections/dto/CollectionUpdateDto";
|
|
import TextAreaInput from "Frontend/components/general/input/TextAreaInput";
|
|
import CollectionHeader from "Frontend/components/general/covers/CollectionHeader";
|
|
import CollectionGamesTable from "Frontend/components/general/modals/CollectionGamesTable";
|
|
import CheckboxInput from "Frontend/components/general/input/CheckboxInput";
|
|
|
|
|
|
export default function CollectionManagementView() {
|
|
const {collectionId} = useParams();
|
|
const navigate = useNavigate();
|
|
const [collectionSaved, setCollectionSaved] = React.useState(false);
|
|
const collections = useSnapshot(collectionState);
|
|
|
|
// Parse and validate collectionId early
|
|
const collectionIdNum = collectionId ? parseInt(collectionId) : null;
|
|
|
|
// Early return if invalid collection ID
|
|
useEffect(() => {
|
|
if (!collectionIdNum || (collections.isLoaded && !collections.state[collectionIdNum])) {
|
|
navigate("/administration/games");
|
|
}
|
|
}, [collections, collectionIdNum, navigate]);
|
|
|
|
// If collectionId is invalid, return null (will redirect via useEffect)
|
|
if (!collectionIdNum) {
|
|
return null;
|
|
}
|
|
|
|
// At this point, collectionIdNum is guaranteed to be a number
|
|
const collection = collections.state[collectionIdNum] as CollectionAdminDto;
|
|
|
|
async function handleSubmit(values: CollectionUpdateDto): Promise<void> {
|
|
const changed = deepDiff(collection, values) as CollectionUpdateDto;
|
|
|
|
if (Object.keys(changed).length === 0) return;
|
|
|
|
changed.id = collection.id;
|
|
await CollectionEndpoint.updateCollection(changed);
|
|
setCollectionSaved(true);
|
|
setTimeout(() => setCollectionSaved(false), 2000);
|
|
}
|
|
|
|
async function deleteCollection(): Promise<void> {
|
|
try {
|
|
await CollectionEndpoint.deleteCollection(collection.id);
|
|
|
|
addToast({
|
|
title: "Collection deleted",
|
|
description: `Collection ${collection.name} deleted!`,
|
|
color: "success"
|
|
});
|
|
|
|
navigate("/administration/games");
|
|
} catch (e) {
|
|
addToast({
|
|
title: "Error deleting collection",
|
|
description: `Collection ${collection.name} could not be deleted!`,
|
|
color: "warning"
|
|
});
|
|
}
|
|
}
|
|
|
|
return collection && (
|
|
<div className="flex flex-col gap-4">
|
|
<div className="flex flex-row gap-4 items-center">
|
|
<Button isIconOnly variant="light" onPress={() => history.back()}>
|
|
<ArrowLeftIcon/>
|
|
</Button>
|
|
<h1 className="text-2xl font-bold">Manage Collection</h1>
|
|
</div>
|
|
<CollectionHeader collection={collection} className="h-32"/>
|
|
<Formik
|
|
initialValues={collection}
|
|
onSubmit={handleSubmit}
|
|
enableReinitialize={true}
|
|
validationSchema={Yup.object({
|
|
name: Yup.string()
|
|
.required("Collection name is required")
|
|
.max(255, "Collection name must be 255 characters or less")
|
|
})}
|
|
>
|
|
{(formik) => (
|
|
<Form>
|
|
<div className="flex flex-row grow justify-between mb-4">
|
|
<h1 className="text-2xl font-bold">Edit collection details</h1>
|
|
<Button
|
|
color="primary"
|
|
isLoading={formik.isSubmitting}
|
|
isDisabled={formik.isSubmitting || collectionSaved || !formik.dirty}
|
|
type="submit"
|
|
>
|
|
{formik.isSubmitting ? "" : collectionSaved ? <CheckIcon/> : "Save"}
|
|
</Button>
|
|
</div>
|
|
|
|
<Input label="Collection name" name="name"/>
|
|
<TextAreaInput label="Collection description" name="description"/>
|
|
<CheckboxInput label="Display on homepage" name="metadata.displayOnHomepage" className="mb-4"/>
|
|
|
|
<div className="flex flex-col gap-4">
|
|
<h1 className="text-2xl font-bold">Manage games in collection</h1>
|
|
<CollectionGamesTable collectionId={collectionIdNum}/>
|
|
</div>
|
|
|
|
<Section title="Danger zone"/>
|
|
<Button color="danger" onPress={deleteCollection}>
|
|
Delete collection
|
|
</Button>
|
|
</Form>
|
|
)}
|
|
</Formik>
|
|
</div>
|
|
);
|
|
} |