diff --git a/packages/api/src/router/integration/integration-router.ts b/packages/api/src/router/integration/integration-router.ts index 4934429f2..8d9f18ffc 100644 --- a/packages/api/src/router/integration/integration-router.ts +++ b/packages/api/src/router/integration/integration-router.ts @@ -33,6 +33,7 @@ import { integrationSavePermissionsSchema, integrationUpdateSchema, } from "@homarr/validation/integration"; +import { mediaRequestOptionsSchema, mediaRequestRequestSchema } from "@homarr/validation/widgets/media-request"; import { createOneIntegrationMiddleware } from "../../middlewares/integration"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../../trpc"; @@ -670,6 +671,20 @@ export const integrationRouter = createTRPCRouter({ return results.flat(); }), + getMediaRequestOptions: protectedProcedure + .concat(createOneIntegrationMiddleware("query", "jellyseerr", "overseerr", "seerr")) + .input(mediaRequestOptionsSchema) + .query(async ({ ctx, input }) => { + const integration = await createIntegrationAsync(ctx.integration); + return await integration.getSeriesInformationAsync(input.mediaType, input.mediaId); + }), + requestMedia: protectedProcedure + .concat(createOneIntegrationMiddleware("interact", "jellyseerr", "overseerr", "seerr")) + .input(mediaRequestRequestSchema) + .mutation(async ({ ctx, input }) => { + const integration = await createIntegrationAsync(ctx.integration); + return await integration.requestMediaAsync(input.mediaType, input.mediaId, input.seasons); + }), }); interface IntegrationRouterContext { diff --git a/packages/api/src/router/search-engine/search-engine-router.ts b/packages/api/src/router/search-engine/search-engine-router.ts index ddfc892a9..8c72baf6e 100644 --- a/packages/api/src/router/search-engine/search-engine-router.ts +++ b/packages/api/src/router/search-engine/search-engine-router.ts @@ -6,12 +6,9 @@ import { createLogger } from "@homarr/core/infrastructure/logs"; import { asc, eq, like } from "@homarr/db"; import { getServerSettingByKeyAsync, updateServerSettingByKeyAsync } from "@homarr/db/queries"; import { searchEngines, users } from "@homarr/db/schema"; -import { createIntegrationAsync } from "@homarr/integrations"; import { byIdSchema, paginatedSchema, searchSchema } from "@homarr/validation/common"; import { searchEngineEditSchema, searchEngineManageSchema } from "@homarr/validation/search-engine"; -import { mediaRequestOptionsSchema, mediaRequestRequestSchema } from "@homarr/validation/widgets/media-request"; -import { createOneIntegrationMiddleware } from "../../middlewares/integration"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../../trpc"; const logger = createLogger({ module: "searchEngineRouter" }); @@ -148,20 +145,6 @@ export const searchEngineRouter = createTRPCRouter({ limit: input.limit, }); }), - getMediaRequestOptions: protectedProcedure - .concat(createOneIntegrationMiddleware("query", "jellyseerr", "overseerr")) - .input(mediaRequestOptionsSchema) - .query(async ({ ctx, input }) => { - const integration = await createIntegrationAsync(ctx.integration); - return await integration.getSeriesInformationAsync(input.mediaType, input.mediaId); - }), - requestMedia: protectedProcedure - .concat(createOneIntegrationMiddleware("interact", "jellyseerr", "overseerr")) - .input(mediaRequestRequestSchema) - .mutation(async ({ ctx, input }) => { - const integration = await createIntegrationAsync(ctx.integration); - return await integration.requestMediaAsync(input.mediaType, input.mediaId, input.seasons); - }), create: permissionRequiredProcedure .requiresPermission("search-engine-create") .input(searchEngineManageSchema) diff --git a/packages/modals-collection/src/search-engines/request-media-modal.tsx b/packages/modals-collection/src/search-engines/request-media-modal.tsx index 89306f3af..c75647969 100644 --- a/packages/modals-collection/src/search-engines/request-media-modal.tsx +++ b/packages/modals-collection/src/search-engines/request-media-modal.tsx @@ -1,6 +1,6 @@ import { useMemo } from "react"; -import { Button, Group, Image, LoadingOverlay, Stack, Text } from "@mantine/core"; -import type { MRT_ColumnDef } from "mantine-react-table"; +import { Badge, Button, Group, Image, LoadingOverlay, Stack, Text } from "@mantine/core"; +import type { MRT_ColumnDef, MRT_Row } from "mantine-react-table"; import { MRT_Table } from "mantine-react-table"; import { clientApi } from "@homarr/api/client"; @@ -16,13 +16,13 @@ interface RequestMediaModalProps { } export const RequestMediaModal = createModal(({ actions, innerProps }) => { - const { data, isPending: isPendingQuery } = clientApi.searchEngine.getMediaRequestOptions.useQuery({ + const { data, isPending: isPendingQuery } = clientApi.integration.getMediaRequestOptions.useQuery({ integrationId: innerProps.integrationId, mediaId: innerProps.mediaId, mediaType: innerProps.mediaType, }); - const { mutate, isPending: isPendingMutation } = clientApi.searchEngine.requestMedia.useMutation({ + const { mutate, isPending: isPendingMutation } = clientApi.integration.requestMedia.useMutation({ onSuccess() { actions.closeModal(); showSuccessNotification({ @@ -33,6 +33,7 @@ export const RequestMediaModal = createModal(({ actions, const isPending = isPendingQuery || isPendingMutation; const t = useI18n(); + const requestedSeasons = new Set(data?.requestedSeasons ?? []); const columns = useMemo[]>( () => [ @@ -44,8 +45,18 @@ export const RequestMediaModal = createModal(({ actions, accessorKey: "episodeCount", header: t("search.engine.media.request.modal.table.header.episodes"), }, + { + id: "status", + header: t("search.engine.media.request.modal.table.header.status"), + Cell: ({ row }) => + requestedSeasons.has(row.original.seasonNumber) ? ( + + {t("search.engine.media.request.modal.table.status.requested")} + + ) : null, + }, ], - [], + [data?.requestedSeasons], ); const table = useTranslatedMantineReactTable({ @@ -56,7 +67,7 @@ export const RequestMediaModal = createModal(({ actions, enablePagination: false, enableSorting: false, enableSelectAll: true, - enableRowSelection: true, + enableRowSelection: (row: MRT_Row) => !requestedSeasons.has(row.original.seasonNumber), mantineTableProps: { highlightOnHover: false, striped: "odd",