fix: fix dotenv loader inconsistent and many ui issues
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
AUTH_TYPE = "basic" # or oidc
|
||||
BASIC_USER = "konobangu"
|
||||
BASIC_PASSWORD = "konobangu"
|
||||
# OIDC_ISSUER="https://auth.logto.io/oidc"
|
||||
# OIDC_AUDIENCE = "https://konobangu.com/api"
|
||||
# OIDC_CLIENT_ID = "client_id"
|
||||
# OIDC_CLIENT_SECRET = "client_secret" # optional
|
||||
# OIDC_EXTRA_SCOPES = "read:konobangu write:konobangu"
|
||||
AUTH__AUTH_TYPE = "basic" # or oidc
|
||||
AUTH__BASIC_USER = "konobangu"
|
||||
AUTH__BASIC_PASSWORD = "konobangu"
|
||||
# AUTH__OIDC_ISSUER="https://auth.logto.io/oidc"
|
||||
# AUTH__OIDC_AUDIENCE = "https://konobangu.com/api"
|
||||
# AUTH__OIDC_CLIENT_ID = "client_id"
|
||||
# AUTH__OIDC_CLIENT_SECRET = "client_secret" # optional
|
||||
# AUTH__OIDC_EXTRA_SCOPES = "read:konobangu write:konobangu"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
AUTH_TYPE = "basic" # or oidc
|
||||
# OIDC_ISSUER="https://auth.logto.io/oidc"
|
||||
# OIDC_AUDIENCE = "https://konobangu.com/api"
|
||||
# OIDC_CLIENT_ID = "client_id"
|
||||
# OIDC_CLIENT_SECRET = "client_secret" # optional
|
||||
# OIDC_EXTRA_SCOPES = "read:konobangu write:konobangu"
|
||||
AUTH__AUTH_TYPE = "basic" # or oidc
|
||||
# AUTH__OIDC_ISSUER="https://auth.logto.io/oidc"
|
||||
# AUTH__OIDC_AUDIENCE = "https://konobangu.com/api"
|
||||
# AUTH__OIDC_CLIENT_ID = "client_id"
|
||||
# AUTH__OIDC_CLIENT_SECRET = "client_secret" # optional
|
||||
# AUTH__OIDC_EXTRA_SCOPES = "read:konobangu write:konobangu"
|
||||
|
||||
@@ -20,15 +20,23 @@ export default defineConfig({
|
||||
index: './src/main.tsx',
|
||||
},
|
||||
define: {
|
||||
'process.env.AUTH_TYPE': JSON.stringify(process.env.AUTH_TYPE),
|
||||
'process.env.OIDC_CLIENT_ID': JSON.stringify(process.env.OIDC_CLIENT_ID),
|
||||
'process.env.OIDC_CLIENT_SECRET': JSON.stringify(
|
||||
process.env.OIDC_CLIENT_SECRET
|
||||
'process.env.AUTH__AUTH_TYPE': JSON.stringify(
|
||||
process.env.AUTH__AUTH_TYPE
|
||||
),
|
||||
'process.env.OIDC_ISSUER': JSON.stringify(process.env.OIDC_ISSUER),
|
||||
'process.env.OIDC_AUDIENCE': JSON.stringify(process.env.OIDC_AUDIENCE),
|
||||
'process.env.OIDC_EXTRA_SCOPES': JSON.stringify(
|
||||
process.env.OIDC_EXTRA_SCOPES
|
||||
'process.env.AUTH__OIDC_CLIENT_ID': JSON.stringify(
|
||||
process.env.AUTH__OIDC_CLIENT_ID
|
||||
),
|
||||
'process.env.AUTH__OIDC_CLIENT_SECRET': JSON.stringify(
|
||||
process.env.AUTH__OIDC_CLIENT_SECRET
|
||||
),
|
||||
'process.env.AUTH__OIDC_ISSUER': JSON.stringify(
|
||||
process.env.AUTH__OIDC_ISSUER
|
||||
),
|
||||
'process.env.AUTH__OIDC_AUDIENCE': JSON.stringify(
|
||||
process.env.AUTH__OIDC_AUDIENCE
|
||||
),
|
||||
'process.env.AUTH__OIDC_EXTRA_SCOPES': JSON.stringify(
|
||||
process.env.AUTH__OIDC_EXTRA_SCOPES
|
||||
),
|
||||
},
|
||||
},
|
||||
@@ -39,7 +47,7 @@ export default defineConfig({
|
||||
setupMiddlewares: [
|
||||
(middlewares) => {
|
||||
middlewares.unshift((req, res, next) => {
|
||||
if (process.env.AUTH_TYPE === 'basic') {
|
||||
if (process.env.AUTH__AUTH_TYPE === 'basic') {
|
||||
res.setHeader('WWW-Authenticate', 'Basic realm="konobangu"');
|
||||
|
||||
const authorization =
|
||||
@@ -49,8 +57,8 @@ export default defineConfig({
|
||||
.split(':');
|
||||
|
||||
if (
|
||||
user !== process.env.BASIC_USER ||
|
||||
password !== process.env.BASIC_PASSWORD
|
||||
user !== process.env.AUTH__BASIC_USER ||
|
||||
password !== process.env.AUTH__BASIC_PASSWORD
|
||||
) {
|
||||
res.statusCode = 401;
|
||||
res.write('Unauthorized');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { MoreHorizontal } from "lucide-react";
|
||||
import { Eye, MoreHorizontal } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -18,7 +18,7 @@ import { ComponentProps, PropsWithChildren } from "react";
|
||||
interface DropdownMenuActionsProps<Id>
|
||||
extends ComponentProps<typeof DropdownMenuPrimitive.Root> {
|
||||
id: Id;
|
||||
showDetail?: boolean;
|
||||
showDetail?: boolean | "dropdown-menu";
|
||||
showEdit?: boolean;
|
||||
showDelete?: boolean;
|
||||
onDetail?: (id: Id) => void;
|
||||
@@ -38,34 +38,49 @@ export function DropdownMenuActions<Id>({
|
||||
...rest
|
||||
}: PropsWithChildren<DropdownMenuActionsProps<Id>>) {
|
||||
return (
|
||||
<DropdownMenu {...rest}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<div className="flex gap-2 items-center justify-center">
|
||||
{showDetail === true && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="flex h-8 w-8 p-0 data-[state=open]:bg-muted"
|
||||
onClick={() => onDetail?.(id)}
|
||||
>
|
||||
<MoreHorizontal />
|
||||
<span className="sr-only">Open menu</span>
|
||||
<Eye />
|
||||
<span className="sr-only">Detail</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-[160px]">
|
||||
{children}
|
||||
{showDetail && (
|
||||
<DropdownMenuItem onClick={() => onDetail?.(id)}>
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{showEdit && (
|
||||
<DropdownMenuItem onClick={() => onEdit?.(id)}>Edit</DropdownMenuItem>
|
||||
)}
|
||||
{(showDetail || showEdit) && showDelete && <DropdownMenuSeparator />}
|
||||
{showDelete && (
|
||||
<DropdownMenuItem onClick={() => onDelete?.(id)}>
|
||||
Delete
|
||||
<DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
<DropdownMenu {...rest}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="flex h-8 w-8 p-0 data-[state=open]:bg-muted"
|
||||
>
|
||||
<MoreHorizontal />
|
||||
<span className="sr-only">Open menu</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-[160px]">
|
||||
{children}
|
||||
{showDetail === "dropdown-menu" && (
|
||||
<DropdownMenuItem onClick={() => onDetail?.(id)}>
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{showEdit && (
|
||||
<DropdownMenuItem onClick={() => onEdit?.(id)}>
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{(showDetail === "dropdown-menu" || showEdit || children) &&
|
||||
showDelete && <DropdownMenuSeparator />}
|
||||
{showDelete && (
|
||||
<DropdownMenuItem onClick={() => onDelete?.(id)}>
|
||||
Delete
|
||||
<DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -105,6 +105,13 @@ query GetSubscriptionDetail ($id: Int!) {
|
||||
feedSource
|
||||
}
|
||||
}
|
||||
subscriberTask {
|
||||
nodes {
|
||||
id
|
||||
taskType
|
||||
status
|
||||
}
|
||||
}
|
||||
credential3rd {
|
||||
id
|
||||
username
|
||||
|
||||
@@ -8,5 +8,5 @@ export const AUTH_METHOD = {
|
||||
export type AuthMethodType = ValueOf<typeof AUTH_METHOD>;
|
||||
|
||||
export function getAppAuthMethod(): AuthMethodType {
|
||||
return process.env.AUTH_TYPE as AuthMethodType;
|
||||
return process.env.AUTH__AUTH_TYPE as AuthMethodType;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@ import { LogLevel, type OpenIdConfiguration } from 'oidc-client-rx';
|
||||
export function buildOidcConfig(): OpenIdConfiguration {
|
||||
const origin = window.location.origin;
|
||||
|
||||
const resource = process.env.OIDC_AUDIENCE!;
|
||||
const resource = process.env.AUTH__OIDC_AUDIENCE!;
|
||||
|
||||
return {
|
||||
authority: process.env.OIDC_ISSUER!,
|
||||
authority: process.env.AUTH__OIDC_ISSUER!,
|
||||
redirectUrl: `${origin}/auth/oidc/callback`,
|
||||
postLogoutRedirectUri: `${origin}/`,
|
||||
clientId: process.env.OIDC_CLIENT_ID!,
|
||||
clientSecret: process.env.OIDC_CLIENT_SECRET,
|
||||
scope: process.env.OIDC_EXTRA_SCOPES
|
||||
? `openid profile email offline_access ${process.env.OIDC_EXTRA_SCOPES}`
|
||||
clientId: process.env.AUTH__OIDC_CLIENT_ID!,
|
||||
clientSecret: process.env.AUTH__OIDC_CLIENT_SECRET,
|
||||
scope: process.env.AUTH__OIDC_EXTRA_SCOPES
|
||||
? `openid profile email offline_access ${process.env.AUTH__OIDC_EXTRA_SCOPES}`
|
||||
: 'openid profile email offline_access',
|
||||
triggerAuthorizationResultEvent: true,
|
||||
responseType: 'code',
|
||||
|
||||
@@ -26,7 +26,7 @@ type Documents = {
|
||||
"\n mutation InsertSubscription($data: SubscriptionsInsertInput!) {\n subscriptionsCreateOne(data: $data) {\n id\n createdAt\n updatedAt\n displayName\n category\n sourceUrl\n enabled\n credentialId\n }\n }\n": typeof types.InsertSubscriptionDocument,
|
||||
"\n mutation UpdateSubscriptions(\n $data: SubscriptionsUpdateInput!,\n $filters: SubscriptionsFilterInput!,\n ) {\n subscriptionsUpdate (\n data: $data\n filter: $filters\n ) {\n id\n createdAt\n updatedAt\n displayName\n category\n sourceUrl\n enabled\n }\n}\n": typeof types.UpdateSubscriptionsDocument,
|
||||
"\n mutation DeleteSubscriptions($filters: SubscriptionsFilterInput) {\n subscriptionsDelete(filter: $filters)\n }\n": typeof types.DeleteSubscriptionsDocument,
|
||||
"\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filters: { id: {\n eq: $id\n } }) {\n nodes {\n id\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n": typeof types.GetSubscriptionDetailDocument,
|
||||
"\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filters: { id: {\n eq: $id\n } }) {\n nodes {\n id\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n subscriberTask {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n": typeof types.GetSubscriptionDetailDocument,
|
||||
"\n mutation SyncSubscriptionFeedsIncremental($filter: SubscriptionsFilterInput!) {\n subscriptionsSyncOneFeedsIncremental(filter: $filter) {\n id\n }\n }\n": typeof types.SyncSubscriptionFeedsIncrementalDocument,
|
||||
"\n mutation SyncSubscriptionFeedsFull($filter: SubscriptionsFilterInput!) {\n subscriptionsSyncOneFeedsFull(filter: $filter) {\n id\n }\n }\n": typeof types.SyncSubscriptionFeedsFullDocument,
|
||||
"\n mutation SyncSubscriptionSources($filter: SubscriptionsFilterInput!) {\n subscriptionsSyncOneSources(filter: $filter) {\n id\n }\n }\n": typeof types.SyncSubscriptionSourcesDocument,
|
||||
@@ -47,7 +47,7 @@ const documents: Documents = {
|
||||
"\n mutation InsertSubscription($data: SubscriptionsInsertInput!) {\n subscriptionsCreateOne(data: $data) {\n id\n createdAt\n updatedAt\n displayName\n category\n sourceUrl\n enabled\n credentialId\n }\n }\n": types.InsertSubscriptionDocument,
|
||||
"\n mutation UpdateSubscriptions(\n $data: SubscriptionsUpdateInput!,\n $filters: SubscriptionsFilterInput!,\n ) {\n subscriptionsUpdate (\n data: $data\n filter: $filters\n ) {\n id\n createdAt\n updatedAt\n displayName\n category\n sourceUrl\n enabled\n }\n}\n": types.UpdateSubscriptionsDocument,
|
||||
"\n mutation DeleteSubscriptions($filters: SubscriptionsFilterInput) {\n subscriptionsDelete(filter: $filters)\n }\n": types.DeleteSubscriptionsDocument,
|
||||
"\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filters: { id: {\n eq: $id\n } }) {\n nodes {\n id\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n": types.GetSubscriptionDetailDocument,
|
||||
"\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filters: { id: {\n eq: $id\n } }) {\n nodes {\n id\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n subscriberTask {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n": types.GetSubscriptionDetailDocument,
|
||||
"\n mutation SyncSubscriptionFeedsIncremental($filter: SubscriptionsFilterInput!) {\n subscriptionsSyncOneFeedsIncremental(filter: $filter) {\n id\n }\n }\n": types.SyncSubscriptionFeedsIncrementalDocument,
|
||||
"\n mutation SyncSubscriptionFeedsFull($filter: SubscriptionsFilterInput!) {\n subscriptionsSyncOneFeedsFull(filter: $filter) {\n id\n }\n }\n": types.SyncSubscriptionFeedsFullDocument,
|
||||
"\n mutation SyncSubscriptionSources($filter: SubscriptionsFilterInput!) {\n subscriptionsSyncOneSources(filter: $filter) {\n id\n }\n }\n": types.SyncSubscriptionSourcesDocument,
|
||||
@@ -121,7 +121,7 @@ export function gql(source: "\n mutation DeleteSubscriptions($filters: Subscr
|
||||
/**
|
||||
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function gql(source: "\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filters: { id: {\n eq: $id\n } }) {\n nodes {\n id\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n"): (typeof documents)["\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filters: { id: {\n eq: $id\n } }) {\n nodes {\n id\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n"];
|
||||
export function gql(source: "\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filters: { id: {\n eq: $id\n } }) {\n nodes {\n id\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n subscriberTask {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n"): (typeof documents)["\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filters: { id: {\n eq: $id\n } }) {\n nodes {\n id\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n subscriberTask {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n"];
|
||||
/**
|
||||
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
@@ -1441,6 +1441,8 @@ export type SubscriberTasks = {
|
||||
status: SubscriberTaskStatusEnum;
|
||||
subscriber?: Maybe<Subscribers>;
|
||||
subscriberId: Scalars['Int']['output'];
|
||||
subscription?: Maybe<Subscriptions>;
|
||||
subscriptionId?: Maybe<Scalars['Int']['output']>;
|
||||
taskType: SubscriberTaskTypeEnum;
|
||||
};
|
||||
|
||||
@@ -1473,6 +1475,7 @@ export type SubscriberTasksFilterInput = {
|
||||
runAt?: InputMaybe<TextFilterInput>;
|
||||
status?: InputMaybe<StringFilterInput>;
|
||||
subscriberId?: InputMaybe<SubscriberIdFilterInput>;
|
||||
subscriptionId?: InputMaybe<IntegerFilterInput>;
|
||||
taskType?: InputMaybe<StringFilterInput>;
|
||||
};
|
||||
|
||||
@@ -1489,6 +1492,7 @@ export type SubscriberTasksOrderInput = {
|
||||
runAt?: InputMaybe<OrderByEnum>;
|
||||
status?: InputMaybe<OrderByEnum>;
|
||||
subscriberId?: InputMaybe<OrderByEnum>;
|
||||
subscriptionId?: InputMaybe<OrderByEnum>;
|
||||
taskType?: InputMaybe<OrderByEnum>;
|
||||
};
|
||||
|
||||
@@ -1745,6 +1749,7 @@ export type Subscriptions = {
|
||||
sourceUrl: Scalars['String']['output'];
|
||||
subscriber?: Maybe<Subscribers>;
|
||||
subscriberId: Scalars['Int']['output'];
|
||||
subscriberTask: SubscriberTasksConnection;
|
||||
subscriptionBangumi: SubscriptionBangumiConnection;
|
||||
subscriptionEpisode: SubscriptionEpisodeConnection;
|
||||
updatedAt: Scalars['String']['output'];
|
||||
@@ -1772,6 +1777,13 @@ export type SubscriptionsFeedArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionsSubscriberTaskArgs = {
|
||||
filters?: InputMaybe<SubscriberTasksFilterInput>;
|
||||
orderBy?: InputMaybe<SubscriberTasksOrderInput>;
|
||||
pagination?: InputMaybe<PaginationInput>;
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionsSubscriptionBangumiArgs = {
|
||||
filters?: InputMaybe<SubscriptionBangumiFilterInput>;
|
||||
orderBy?: InputMaybe<SubscriptionBangumiOrderInput>;
|
||||
@@ -1971,7 +1983,7 @@ export type GetSubscriptionDetailQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type GetSubscriptionDetailQuery = { __typename?: 'Query', subscriptions: { __typename?: 'SubscriptionsConnection', nodes: Array<{ __typename?: 'Subscriptions', id: number, displayName: string, createdAt: string, updatedAt: string, category: SubscriptionCategoryEnum, sourceUrl: string, enabled: boolean, feed: { __typename?: 'FeedsConnection', nodes: Array<{ __typename?: 'Feeds', id: number, createdAt: string, updatedAt: string, token: string, feedType: FeedTypeEnum, feedSource: FeedSourceEnum }> }, credential3rd?: { __typename?: 'Credential3rd', id: number, username?: string | null } | null, bangumi: { __typename?: 'BangumiConnection', nodes: Array<{ __typename?: 'Bangumi', createdAt: string, updatedAt: string, id: number, mikanBangumiId?: string | null, displayName: string, season: number, seasonRaw?: string | null, fansub?: string | null, mikanFansubId?: string | null, rssLink?: string | null, posterLink?: string | null, homepage?: string | null }> } }> } };
|
||||
export type GetSubscriptionDetailQuery = { __typename?: 'Query', subscriptions: { __typename?: 'SubscriptionsConnection', nodes: Array<{ __typename?: 'Subscriptions', id: number, displayName: string, createdAt: string, updatedAt: string, category: SubscriptionCategoryEnum, sourceUrl: string, enabled: boolean, feed: { __typename?: 'FeedsConnection', nodes: Array<{ __typename?: 'Feeds', id: number, createdAt: string, updatedAt: string, token: string, feedType: FeedTypeEnum, feedSource: FeedSourceEnum }> }, subscriberTask: { __typename?: 'SubscriberTasksConnection', nodes: Array<{ __typename?: 'SubscriberTasks', id: string, taskType: SubscriberTaskTypeEnum, status: SubscriberTaskStatusEnum }> }, credential3rd?: { __typename?: 'Credential3rd', id: number, username?: string | null } | null, bangumi: { __typename?: 'BangumiConnection', nodes: Array<{ __typename?: 'Bangumi', createdAt: string, updatedAt: string, id: number, mikanBangumiId?: string | null, displayName: string, season: number, seasonRaw?: string | null, fansub?: string | null, mikanFansubId?: string | null, rssLink?: string | null, posterLink?: string | null, homepage?: string | null }> } }> } };
|
||||
|
||||
export type SyncSubscriptionFeedsIncrementalMutationVariables = Exact<{
|
||||
filter: SubscriptionsFilterInput;
|
||||
@@ -2030,7 +2042,7 @@ export const GetSubscriptionsDocument = {"kind":"Document","definitions":[{"kind
|
||||
export const InsertSubscriptionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"InsertSubscription"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"data"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsInsertInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptionsCreateOne"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"data"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"category"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrl"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"credentialId"}}]}}]}}]} as unknown as DocumentNode<InsertSubscriptionMutation, InsertSubscriptionMutationVariables>;
|
||||
export const UpdateSubscriptionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateSubscriptions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"data"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsUpdateInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filters"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsFilterInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptionsUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"data"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"category"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrl"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}}]}}]}}]} as unknown as DocumentNode<UpdateSubscriptionsMutation, UpdateSubscriptionsMutationVariables>;
|
||||
export const DeleteSubscriptionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteSubscriptions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filters"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsFilterInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptionsDelete"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filters"}}}]}]}}]} as unknown as DocumentNode<DeleteSubscriptionsMutation, DeleteSubscriptionsMutationVariables>;
|
||||
export const GetSubscriptionDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSubscriptionDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"category"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrl"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"feed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"token"}},{"kind":"Field","name":{"kind":"Name","value":"feedType"}},{"kind":"Field","name":{"kind":"Name","value":"feedSource"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"credential3rd"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"bangumi"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"mikanBangumiId"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"season"}},{"kind":"Field","name":{"kind":"Name","value":"seasonRaw"}},{"kind":"Field","name":{"kind":"Name","value":"fansub"}},{"kind":"Field","name":{"kind":"Name","value":"mikanFansubId"}},{"kind":"Field","name":{"kind":"Name","value":"rssLink"}},{"kind":"Field","name":{"kind":"Name","value":"posterLink"}},{"kind":"Field","name":{"kind":"Name","value":"homepage"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetSubscriptionDetailQuery, GetSubscriptionDetailQueryVariables>;
|
||||
export const GetSubscriptionDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSubscriptionDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"category"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrl"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"feed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"token"}},{"kind":"Field","name":{"kind":"Name","value":"feedType"}},{"kind":"Field","name":{"kind":"Name","value":"feedSource"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"subscriberTask"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"taskType"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"credential3rd"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"bangumi"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"mikanBangumiId"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"season"}},{"kind":"Field","name":{"kind":"Name","value":"seasonRaw"}},{"kind":"Field","name":{"kind":"Name","value":"fansub"}},{"kind":"Field","name":{"kind":"Name","value":"mikanFansubId"}},{"kind":"Field","name":{"kind":"Name","value":"rssLink"}},{"kind":"Field","name":{"kind":"Name","value":"posterLink"}},{"kind":"Field","name":{"kind":"Name","value":"homepage"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetSubscriptionDetailQuery, GetSubscriptionDetailQueryVariables>;
|
||||
export const SyncSubscriptionFeedsIncrementalDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SyncSubscriptionFeedsIncremental"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsFilterInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptionsSyncOneFeedsIncremental"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode<SyncSubscriptionFeedsIncrementalMutation, SyncSubscriptionFeedsIncrementalMutationVariables>;
|
||||
export const SyncSubscriptionFeedsFullDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SyncSubscriptionFeedsFull"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsFilterInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptionsSyncOneFeedsFull"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode<SyncSubscriptionFeedsFullMutation, SyncSubscriptionFeedsFullMutationVariables>;
|
||||
export const SyncSubscriptionSourcesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SyncSubscriptionSources"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsFilterInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptionsSyncOneSources"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode<SyncSubscriptionSourcesMutation, SyncSubscriptionSourcesMutationVariables>;
|
||||
|
||||
@@ -51,6 +51,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { prettyTaskType } from '../tasks/-pretty-task-type';
|
||||
import { SubscriptionSyncDialogContent } from './-sync';
|
||||
|
||||
export const Route = createFileRoute('/_app/subscriptions/detail/$id')({
|
||||
@@ -212,18 +213,6 @@ function SubscriptionDetailRouteComponent() {
|
||||
</CardDescription>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" size="sm">
|
||||
<RefreshCcwIcon className="h-4 w-4" />
|
||||
Sync
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<SubscriptionSyncDialogContent
|
||||
id={subscription.id}
|
||||
onCancel={handleReload}
|
||||
/>
|
||||
</Dialog>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -446,6 +435,64 @@ function SubscriptionDetailRouteComponent() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="font-medium text-sm">Associated Tasks</Label>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" size="sm">
|
||||
<RefreshCcwIcon className="h-4 w-4" />
|
||||
Sync
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<SubscriptionSyncDialogContent
|
||||
id={subscription.id}
|
||||
onCancel={handleReload}
|
||||
/>
|
||||
</Dialog>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{subscription.subscriberTask?.nodes &&
|
||||
subscription.subscriberTask.nodes.length > 0 ? (
|
||||
subscription.subscriberTask.nodes.map((task) => (
|
||||
<Card
|
||||
key={task.id}
|
||||
className="group relative cursor-pointer p-4 transition-colors hover:bg-accent/50"
|
||||
onClick={() =>
|
||||
navigate({
|
||||
to: '/tasks/detail/$id',
|
||||
params: {
|
||||
id: task.id,
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="font-medium text-sm capitalize">
|
||||
<span>{prettyTaskType(task.taskType)} Task</span>
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<code className="break-all rounded bg-muted px-2 py-1 font-mono text-xs">
|
||||
{task.id}
|
||||
</code>
|
||||
|
||||
<div className="text-muted-foreground text-xs">
|
||||
{task.status}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))
|
||||
) : (
|
||||
<div className="col-span-full py-8 text-center text-muted-foreground">
|
||||
No associated tasks now
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{subscription.bangumi?.nodes &&
|
||||
subscription.bangumi.nodes.length > 0 && (
|
||||
<>
|
||||
@@ -465,6 +512,7 @@ function SubscriptionDetailRouteComponent() {
|
||||
src={`/api/static${bangumi.posterLink}`}
|
||||
alt="Poster"
|
||||
className="h-full w-full object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export function prettyTaskType(taskType: string) {
|
||||
return taskType.replace(/_/g, ' ');
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
import { format } from 'date-fns';
|
||||
import { ArrowLeft, RefreshCw } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { prettyTaskType } from './-pretty-task-type';
|
||||
import { getStatusBadge } from './-status-badge';
|
||||
|
||||
export const Route = createFileRoute('/_app/tasks/detail/$id')({
|
||||
@@ -182,7 +183,9 @@ function TaskDetailRouteComponent() {
|
||||
<div className="space-y-2">
|
||||
<Label className="font-medium text-sm">Task Type</Label>
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<Badge variant="secondary">{task.taskType}</Badge>
|
||||
<Badge variant="secondary" className="capitalize">
|
||||
{prettyTaskType(task.taskType)}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
} from '@/infra/errors/apollo';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { prettyTaskType } from './-pretty-task-type';
|
||||
import { getStatusBadge } from './-status-badge';
|
||||
|
||||
export const Route = createFileRoute('/_app/tasks/manage')({
|
||||
@@ -202,7 +203,9 @@ function TaskManageRouteComponent() {
|
||||
# {task.id}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Badge variant="outline">{task.taskType}</Badge>
|
||||
<Badge variant="outline" className="capitalize">
|
||||
{prettyTaskType(task.taskType)}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-1 flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user