mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-16 08:15:48 +00:00
v2.0.0.beta5 (#626)
* Fix wrong version property used in release.yml * Implement "Allow access to Gameyfin without login" * Implement filter by keyword (closes #613) * Fix bug where secret fields would be displayed as normal text * Optimize Gradle build performance * Fix ant path matchers * Fix NPE in role authority mapper (fixes #614)
This commit is contained in:
@@ -13,7 +13,7 @@ export default function ProfileMenu() {
|
||||
|
||||
async function logout() {
|
||||
if (auth.state.user?.managedBySso) {
|
||||
window.location.href = (await ConfigEndpoint.getLogoutUrl()) || "/";
|
||||
window.location.href = (await ConfigEndpoint.getSsoLogoutUrl()) || "/";
|
||||
} else {
|
||||
await auth.logout();
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ function LibraryManagementLayout({getConfig, formik}: any) {
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<Section title="Permissions"/>
|
||||
<ConfigFormField configElement={getConfig("library.allow-public-access")} isDisabled/>
|
||||
<ConfigFormField configElement={getConfig("library.allow-public-access")}/>
|
||||
|
||||
<Section title="Scanning"/>
|
||||
<div className="flex flex-col gap-4">
|
||||
|
||||
@@ -87,6 +87,8 @@ export default function EditGameMetadataModal({game, isOpen, onOpenChange}: Edit
|
||||
<ArrayInput key="features" name="features" label="Features"/>
|
||||
<ArrayInput key="perspectives" name="perspectives"
|
||||
label="Perspectives"/>
|
||||
<ArrayInput key="keywords" name="keywords"
|
||||
label="Keywords"/>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</ModalBody>
|
||||
|
||||
@@ -23,6 +23,7 @@ import SearchView from "Frontend/views/SearchView";
|
||||
import RecentlyAddedView from "Frontend/views/RecentlyAddedView";
|
||||
import LibraryView from "Frontend/views/LibraryView";
|
||||
import {RouterConfigurationBuilder} from "@vaadin/hilla-file-router/runtime.js";
|
||||
import {ConfigEndpoint} from "Frontend/generated/endpoints";
|
||||
|
||||
export const {router, routes} = new RouterConfigurationBuilder()
|
||||
.withReactRoutes([
|
||||
@@ -32,7 +33,7 @@ export const {router, routes} = new RouterConfigurationBuilder()
|
||||
children: [
|
||||
{
|
||||
element: <MainLayout/>,
|
||||
handle: {requiresLogin: true},
|
||||
handle: {requiresLogin: !ConfigEndpoint.isPublicAccessEnabled()},
|
||||
children: [
|
||||
{
|
||||
index: true, element: <HomeView/>
|
||||
@@ -64,6 +65,7 @@ export const {router, routes} = new RouterConfigurationBuilder()
|
||||
{
|
||||
path: 'administration',
|
||||
element: <AdministrationView/>,
|
||||
handle: {requiresLogin: true},
|
||||
children: [
|
||||
{
|
||||
path: 'libraries',
|
||||
|
||||
@@ -6,7 +6,7 @@ import GameyfinLogo from "Frontend/components/theming/GameyfinLogo";
|
||||
import * as PackageJson from "../../../../package.json";
|
||||
import {Outlet, useLocation, useNavigate} from "react-router";
|
||||
import {useAuth} from "Frontend/util/auth";
|
||||
import {ArrowLeft, DiceSix, Heart, House, ListMagnifyingGlass} from "@phosphor-icons/react";
|
||||
import {ArrowLeft, DiceSix, Heart, House, ListMagnifyingGlass, SignIn} from "@phosphor-icons/react";
|
||||
import Confetti, {ConfettiProps} from "react-confetti-boom";
|
||||
import {useTheme} from "next-themes";
|
||||
import {UserPreferenceService} from "Frontend/util/user-preference-service";
|
||||
@@ -103,9 +103,24 @@ export default function MainLayout() {
|
||||
<ScanProgressPopover/>
|
||||
</NavbarItem>
|
||||
}
|
||||
<NavbarItem>
|
||||
<ProfileMenu/>
|
||||
</NavbarItem>
|
||||
{auth.state.user &&
|
||||
<NavbarItem>
|
||||
<ProfileMenu/>
|
||||
</NavbarItem>
|
||||
}
|
||||
{!auth.state.user &&
|
||||
<NavbarItem>
|
||||
<Tooltip content="Sign in to your account" placement="bottom">
|
||||
<Button color="primary"
|
||||
radius="full"
|
||||
isIconOnly
|
||||
className="gradient-primary"
|
||||
onPress={() => navigate("/login")}>
|
||||
<SignIn fill="text-background/80"/>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</NavbarItem>
|
||||
}
|
||||
</NavbarContent>
|
||||
</Navbar>
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ export default function SearchView() {
|
||||
const knownThemes = useSnapshot(gameState).knownThemes;
|
||||
const knownFeatures = useSnapshot(gameState).knownFeatures;
|
||||
const knownPerspectives = useSnapshot(gameState).knownPerspectives;
|
||||
const knownKeywords = useSnapshot(gameState).knownKeywords;
|
||||
const libraries = useSnapshot(libraryState).libraries as LibraryDto[];
|
||||
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
@@ -31,6 +32,7 @@ export default function SearchView() {
|
||||
const [selectedThemes, setSelectedThemes] = useState<Set<string>>(new Set());
|
||||
const [selectedFeatures, setSelectedFeatures] = useState<Set<string>>(new Set());
|
||||
const [selectedPerspectives, setSelectedPerspectives] = useState<Set<string>>(new Set());
|
||||
const [selectedKeywords, setSelectedKeywords] = useState<Set<string>>(new Set());
|
||||
|
||||
// Load initial filter values from URL parameters on component mount
|
||||
useEffect(() => {
|
||||
@@ -42,6 +44,7 @@ export default function SearchView() {
|
||||
const themes = searchParams.getAll("theme");
|
||||
const features = searchParams.getAll("feature");
|
||||
const perspectives = searchParams.getAll("perspective");
|
||||
const keywords = searchParams.getAll("keyword");
|
||||
|
||||
setSearchTerm(term);
|
||||
setSelectedLibraries(new Set(libs));
|
||||
@@ -50,6 +53,7 @@ export default function SearchView() {
|
||||
setSelectedThemes(new Set(themes));
|
||||
setSelectedFeatures(new Set(features));
|
||||
setSelectedPerspectives(new Set(perspectives));
|
||||
setSelectedKeywords(new Set(keywords));
|
||||
|
||||
setInitialLoadComplete(true);
|
||||
}, []);
|
||||
@@ -102,15 +106,21 @@ export default function SearchView() {
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedKeywords.size > 0) {
|
||||
selectedKeywords.forEach(keyword => {
|
||||
newParams.append("keyword", keyword);
|
||||
});
|
||||
}
|
||||
|
||||
setSearchParams(newParams, {replace: true});
|
||||
}, [searchTerm, selectedLibraries, selectedDevelopers, selectedGenres,
|
||||
selectedThemes, selectedFeatures, selectedPerspectives]);
|
||||
selectedThemes, selectedFeatures, selectedPerspectives, selectedKeywords]);
|
||||
|
||||
const filteredGames = useMemo(() => filterGames(), [
|
||||
games, searchTerm,
|
||||
selectedLibraries, selectedDevelopers,
|
||||
selectedGenres, selectedThemes,
|
||||
selectedFeatures, selectedPerspectives
|
||||
selectedFeatures, selectedPerspectives, selectedKeywords
|
||||
]);
|
||||
|
||||
function filterGames(): GameDto[] {
|
||||
@@ -164,6 +174,13 @@ export default function SearchView() {
|
||||
);
|
||||
}
|
||||
|
||||
// Apply keyword filter
|
||||
if (selectedKeywords.size > 0) {
|
||||
filtered = filtered.filter(game =>
|
||||
game.keywords?.some(keyword => selectedKeywords.has(keyword))
|
||||
);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
@@ -183,10 +200,17 @@ export default function SearchView() {
|
||||
onChange={(event) => setSearchTerm(event.target.value)}
|
||||
onClear={() => setSearchTerm("")}
|
||||
/>
|
||||
<div className="flex flex-row flex-wrap gap-2 justify-center">
|
||||
<div
|
||||
className="w-full justify-center"
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))",
|
||||
gap: "0.5rem",
|
||||
margin: "0 auto"
|
||||
}}
|
||||
>
|
||||
<Select
|
||||
size="sm"
|
||||
className="max-w-xs"
|
||||
selectionMode="multiple"
|
||||
label="Libraries"
|
||||
placeholder="Filter by library"
|
||||
@@ -200,7 +224,6 @@ export default function SearchView() {
|
||||
</Select>
|
||||
<Select
|
||||
size="sm"
|
||||
className="max-w-xs"
|
||||
selectionMode="multiple"
|
||||
label="Developers"
|
||||
placeholder="Filter by developer"
|
||||
@@ -214,7 +237,6 @@ export default function SearchView() {
|
||||
</Select>
|
||||
<Select
|
||||
size="sm"
|
||||
className="max-w-xs"
|
||||
selectionMode="multiple"
|
||||
label="Genres"
|
||||
placeholder="Filter by genre"
|
||||
@@ -228,7 +250,6 @@ export default function SearchView() {
|
||||
</Select>
|
||||
<Select
|
||||
size="sm"
|
||||
className="max-w-xs"
|
||||
selectionMode="multiple"
|
||||
label="Themes"
|
||||
placeholder="Filter by theme"
|
||||
@@ -242,7 +263,6 @@ export default function SearchView() {
|
||||
</Select>
|
||||
<Select
|
||||
size="sm"
|
||||
className="max-w-xs"
|
||||
selectionMode="multiple"
|
||||
label="Features"
|
||||
placeholder="Filter by feature"
|
||||
@@ -256,7 +276,6 @@ export default function SearchView() {
|
||||
</Select>
|
||||
<Select
|
||||
size="sm"
|
||||
className="max-w-xs"
|
||||
selectionMode="multiple"
|
||||
label="Perspectives"
|
||||
placeholder="Filter by perspective"
|
||||
@@ -268,6 +287,19 @@ export default function SearchView() {
|
||||
<SelectItem key={perspective}>{toTitleCase(perspective)}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
<Select
|
||||
size="sm"
|
||||
selectionMode="multiple"
|
||||
label="Keywords"
|
||||
placeholder="Filter by keyword"
|
||||
selectedKeys={selectedKeywords}
|
||||
//@ts-ignore
|
||||
onSelectionChange={setSelectedKeywords}
|
||||
>
|
||||
{Array.from(knownKeywords).map((keyword) => (
|
||||
<SelectItem key={keyword}>{keyword}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
<div className="mt-4 w-full px-4 select-none">
|
||||
<CoverGrid games={filteredGames}/>
|
||||
|
||||
Reference in New Issue
Block a user