fix: fix issues
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import type { NavMainGroup } from '@/infra/routes/nav';
|
||||
import {
|
||||
BookOpen,
|
||||
Folders,
|
||||
@@ -9,6 +8,7 @@ import {
|
||||
Telescope,
|
||||
Tv,
|
||||
} from 'lucide-react';
|
||||
import type { NavMainGroup } from '@/infra/routes/nav';
|
||||
|
||||
export const AppNavMainData: NavMainGroup[] = [
|
||||
{
|
||||
@@ -49,13 +49,13 @@ export const AppNavMainData: NavMainGroup[] = [
|
||||
{
|
||||
title: 'Manage',
|
||||
link: {
|
||||
to: '/bangumi/recorder',
|
||||
to: '/bangumi',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Feed',
|
||||
link: {
|
||||
to: '/bangumi/feed',
|
||||
to: '/bangumi',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useMatches } from '@tanstack/react-router';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
@@ -27,13 +27,8 @@ import {
|
||||
useSidebar,
|
||||
} from '@/components/ui/sidebar';
|
||||
import type { NavMainGroup, NavMainItem } from '@/infra/routes/nav';
|
||||
import { useMatches } from '@tanstack/react-router';
|
||||
|
||||
export function NavMain({
|
||||
groups,
|
||||
}: {
|
||||
groups: NavMainGroup[];
|
||||
}) {
|
||||
export function NavMain({ groups }: { groups: NavMainGroup[] }) {
|
||||
const matches = useMatches();
|
||||
const { state } = useSidebar();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type VariantProps, cva } from "class-variance-authority";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/presentation/utils";
|
||||
|
||||
@@ -1,20 +1,32 @@
|
||||
import { type LinkComponent, createLink } from "@tanstack/react-router";
|
||||
import type { AnchorHTMLAttributes, ComponentProps } from "react";
|
||||
import { createLink, type LinkComponentProps } from "@tanstack/react-router";
|
||||
import type { AnchorHTMLAttributes } from "react";
|
||||
|
||||
export interface BasicLinkProps
|
||||
extends AnchorHTMLAttributes<HTMLAnchorElement> {}
|
||||
extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href"> {
|
||||
href: string;
|
||||
to?: undefined;
|
||||
}
|
||||
|
||||
const BasicLinkComponent = (props: ComponentProps<"a">) => {
|
||||
const BasicLinkComponent = (props: BasicLinkProps) => {
|
||||
return <a {...props} />;
|
||||
};
|
||||
|
||||
const CreatedLinkComponent = createLink(BasicLinkComponent);
|
||||
|
||||
export const ProLink: LinkComponent<typeof BasicLinkComponent> = (props) => {
|
||||
export const ProLink = (
|
||||
props: LinkComponentProps<typeof BasicLinkComponent> | BasicLinkProps
|
||||
) => {
|
||||
if (props.href) {
|
||||
return <BasicLinkComponent {...(props as any)} />;
|
||||
}
|
||||
return <CreatedLinkComponent preload={"intent"} {...props} />;
|
||||
return (
|
||||
<CreatedLinkComponent
|
||||
preload={"intent"}
|
||||
{...(props as LinkComponentProps<typeof BasicLinkComponent>)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export type ProLinkProps = ComponentProps<typeof ProLink>;
|
||||
export type ProLinkProps =
|
||||
| LinkComponentProps<typeof BasicLinkComponent>
|
||||
| BasicLinkProps;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AlertCircle } from "lucide-react";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { AlertCircle } from "lucide-react";
|
||||
|
||||
export interface QueryErrorViewProps {
|
||||
title?: string;
|
||||
|
||||
@@ -83,10 +83,8 @@ export const DELETE_SUBSCRIPTIONS = gql`
|
||||
`;
|
||||
|
||||
export const GET_SUBSCRIPTION_DETAIL = gql`
|
||||
query GetSubscriptionDetail ($id: Int!) {
|
||||
subscriptions(filter: { id: {
|
||||
eq: $id
|
||||
} }) {
|
||||
query GetSubscriptionDetail ($filter: SubscriptionsFilterInput!) {
|
||||
subscriptions(filter: $filter) {
|
||||
nodes {
|
||||
id
|
||||
subscriberId
|
||||
@@ -106,7 +104,15 @@ query GetSubscriptionDetail ($id: Int!) {
|
||||
feedSource
|
||||
}
|
||||
}
|
||||
subscriberTask {
|
||||
subscriberTask(pagination: {
|
||||
page: {
|
||||
page: 0,
|
||||
limit: 3,
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
runAt: DESC,
|
||||
}) {
|
||||
nodes {
|
||||
id
|
||||
taskType
|
||||
@@ -117,7 +123,15 @@ query GetSubscriptionDetail ($id: Int!) {
|
||||
id
|
||||
username
|
||||
}
|
||||
cron {
|
||||
cron (pagination: {
|
||||
page: {
|
||||
page: 0,
|
||||
limit: 3,
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: DESC,
|
||||
}) {
|
||||
nodes {
|
||||
id
|
||||
cronExpr
|
||||
|
||||
@@ -30,7 +30,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 $filter: SubscriptionsFilterInput!,\n ) {\n subscriptionsUpdate (\n data: $data\n filter: $filter\n ) {\n id\n createdAt\n updatedAt\n displayName\n category\n sourceUrl\n enabled\n }\n}\n": typeof types.UpdateSubscriptionsDocument,
|
||||
"\n mutation DeleteSubscriptions($filter: SubscriptionsFilterInput) {\n subscriptionsDelete(filter: $filter)\n }\n": typeof types.DeleteSubscriptionsDocument,
|
||||
"\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filter: { id: {\n eq: $id\n } }) {\n nodes {\n id\n subscriberId\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 cron {\n nodes {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n enabled\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n subscriberTaskCron\n }\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 ($filter: SubscriptionsFilterInput!) {\n subscriptions(filter: $filter) {\n nodes {\n id\n subscriberId\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(pagination: {\n page: {\n page: 0,\n limit: 3,\n }\n },\n orderBy: {\n runAt: DESC,\n }) {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n cron (pagination: {\n page: {\n page: 0,\n limit: 3,\n }\n },\n orderBy: {\n createdAt: DESC,\n }) {\n nodes {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n enabled\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n subscriberTaskCron\n }\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 query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority,\n subscription {\n displayName\n sourceUrl\n }\n cron {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n": typeof types.GetTasksDocument,
|
||||
"\n mutation InsertSubscriberTask($data: SubscriberTasksInsertInput!) {\n subscriberTasksCreateOne(data: $data) {\n id\n }\n }\n": typeof types.InsertSubscriberTaskDocument,
|
||||
"\n mutation DeleteTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksDelete(filter: $filter)\n }\n": typeof types.DeleteTasksDocument,
|
||||
@@ -53,7 +53,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 $filter: SubscriptionsFilterInput!,\n ) {\n subscriptionsUpdate (\n data: $data\n filter: $filter\n ) {\n id\n createdAt\n updatedAt\n displayName\n category\n sourceUrl\n enabled\n }\n}\n": types.UpdateSubscriptionsDocument,
|
||||
"\n mutation DeleteSubscriptions($filter: SubscriptionsFilterInput) {\n subscriptionsDelete(filter: $filter)\n }\n": types.DeleteSubscriptionsDocument,
|
||||
"\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filter: { id: {\n eq: $id\n } }) {\n nodes {\n id\n subscriberId\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 cron {\n nodes {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n enabled\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n subscriberTaskCron\n }\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 ($filter: SubscriptionsFilterInput!) {\n subscriptions(filter: $filter) {\n nodes {\n id\n subscriberId\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(pagination: {\n page: {\n page: 0,\n limit: 3,\n }\n },\n orderBy: {\n runAt: DESC,\n }) {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n cron (pagination: {\n page: {\n page: 0,\n limit: 3,\n }\n },\n orderBy: {\n createdAt: DESC,\n }) {\n nodes {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n enabled\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n subscriberTaskCron\n }\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 query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority,\n subscription {\n displayName\n sourceUrl\n }\n cron {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n": types.GetTasksDocument,
|
||||
"\n mutation InsertSubscriberTask($data: SubscriberTasksInsertInput!) {\n subscriberTasksCreateOne(data: $data) {\n id\n }\n }\n": types.InsertSubscriberTaskDocument,
|
||||
"\n mutation DeleteTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksDelete(filter: $filter)\n }\n": types.DeleteTasksDocument,
|
||||
@@ -141,7 +141,7 @@ export function gql(source: "\n mutation DeleteSubscriptions($filter: Subscri
|
||||
/**
|
||||
* 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(filter: { id: {\n eq: $id\n } }) {\n nodes {\n id\n subscriberId\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 cron {\n nodes {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n enabled\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n subscriberTaskCron\n }\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(filter: { id: {\n eq: $id\n } }) {\n nodes {\n id\n subscriberId\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 cron {\n nodes {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n enabled\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n subscriberTaskCron\n }\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 ($filter: SubscriptionsFilterInput!) {\n subscriptions(filter: $filter) {\n nodes {\n id\n subscriberId\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(pagination: {\n page: {\n page: 0,\n limit: 3,\n }\n },\n orderBy: {\n runAt: DESC,\n }) {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n cron (pagination: {\n page: {\n page: 0,\n limit: 3,\n }\n },\n orderBy: {\n createdAt: DESC,\n }) {\n nodes {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n enabled\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n subscriberTaskCron\n }\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 ($filter: SubscriptionsFilterInput!) {\n subscriptions(filter: $filter) {\n nodes {\n id\n subscriberId\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(pagination: {\n page: {\n page: 0,\n limit: 3,\n }\n },\n orderBy: {\n runAt: DESC,\n }) {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n cron (pagination: {\n page: {\n page: 0,\n limit: 3,\n }\n },\n orderBy: {\n createdAt: DESC,\n }) {\n nodes {\n id\n cronExpr\n nextRun\n lastRun\n lastError\n enabled\n status\n lockedAt\n lockedBy\n createdAt\n updatedAt\n timeoutMs\n maxAttempts\n priority\n attempts\n subscriberTaskCron\n }\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.
|
||||
*/
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,7 +12,10 @@ export class IntlService {
|
||||
return this.Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
}
|
||||
|
||||
formatTimestamp(timestamp: number, options?: Intl.DateTimeFormatOptions) {
|
||||
formatDatetimeWithTz(
|
||||
timestamp: number | string | Date,
|
||||
options?: Intl.DateTimeFormatOptions
|
||||
) {
|
||||
const defaultOptions: Intl.DateTimeFormatOptions = {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ProLinkProps } from '@/components/ui/pro-link';
|
||||
import { type } from 'arktype';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
import type { ProLinkProps } from '@/components/ui/pro-link';
|
||||
|
||||
export interface NavMainItem {
|
||||
link?: ProLinkProps;
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import { CheckIcon, Edit, Eye, EyeOff } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@@ -15,13 +19,10 @@ import { Label } from '@/components/ui/label';
|
||||
import { QueryErrorView } from '@/components/ui/query-error-view';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { GET_CREDENTIAL_3RD_DETAIL } from '@/domains/recorder/schema/credential3rd';
|
||||
import { useInject } from '@/infra/di/inject';
|
||||
import type { GetCredential3rdDetailQuery } from '@/infra/graphql/gql/graphql';
|
||||
import { IntlService } from '@/infra/intl/intl.service';
|
||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import { format } from 'date-fns/format';
|
||||
import { CheckIcon, Edit, Eye, EyeOff } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { Credential3rdCheckAvailableViewDialogContent } from './-check-available';
|
||||
|
||||
export const Route = createFileRoute('/_app/credential3rd/detail/$id')({
|
||||
@@ -34,6 +35,7 @@ export const Route = createFileRoute('/_app/credential3rd/detail/$id')({
|
||||
function Credential3rdDetailRouteComponent() {
|
||||
const { id } = Route.useParams();
|
||||
const navigate = useNavigate();
|
||||
const intlService = useInject(IntlService);
|
||||
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
@@ -41,7 +43,7 @@ function Credential3rdDetailRouteComponent() {
|
||||
GET_CREDENTIAL_3RD_DETAIL,
|
||||
{
|
||||
variables: {
|
||||
id: Number.parseInt(id),
|
||||
id: Number.parseInt(id, 10),
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -177,10 +179,7 @@ function Credential3rdDetailRouteComponent() {
|
||||
<Label className="font-medium text-sm">Created at</Label>
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{format(
|
||||
new Date(credential.createdAt),
|
||||
'yyyy-MM-dd HH:mm:ss'
|
||||
)}
|
||||
{intlService.formatDatetimeWithTz(credential.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -189,10 +188,7 @@ function Credential3rdDetailRouteComponent() {
|
||||
<Label className="font-medium text-sm">Updated at</Label>
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{format(
|
||||
new Date(credential.updatedAt),
|
||||
'yyyy-MM-dd HH:mm:ss'
|
||||
)}
|
||||
{intlService.formatDatetimeWithTz(credential.updatedAt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { Dialog } from '@radix-ui/react-dialog';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import {
|
||||
type ColumnDef,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
type PaginationState,
|
||||
type Row,
|
||||
type SortingState,
|
||||
useReactTable,
|
||||
type VisibilityState,
|
||||
} from '@tanstack/react-table';
|
||||
import { Eye, EyeOff, Plus } from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ContainerHeader } from '@/components/ui/container-header';
|
||||
@@ -21,33 +38,17 @@ import {
|
||||
DELETE_CREDENTIAL_3RD,
|
||||
GET_CREDENTIAL_3RD,
|
||||
} from '@/domains/recorder/schema/credential3rd';
|
||||
import { useInject } from '@/infra/di/inject';
|
||||
import {
|
||||
apolloErrorToMessage,
|
||||
getApolloQueryError,
|
||||
} from '@/infra/errors/apollo';
|
||||
import type { GetCredential3rdQuery } from '@/infra/graphql/gql/graphql';
|
||||
import { IntlService } from '@/infra/intl/intl.service';
|
||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||
import { useDebouncedSkeleton } from '@/presentation/hooks/use-debounded-skeleton';
|
||||
import { useEvent } from '@/presentation/hooks/use-event';
|
||||
import { cn } from '@/presentation/utils';
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { Dialog } from '@radix-ui/react-dialog';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import {
|
||||
type ColumnDef,
|
||||
type PaginationState,
|
||||
type Row,
|
||||
type SortingState,
|
||||
type VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
useReactTable,
|
||||
} from '@tanstack/react-table';
|
||||
import { format } from 'date-fns';
|
||||
import { Eye, EyeOff, Plus } from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Credential3rdCheckAvailableViewDialogContent } from './-check-available';
|
||||
|
||||
export const Route = createFileRoute('/_app/credential3rd/manage')({
|
||||
@@ -59,6 +60,7 @@ export const Route = createFileRoute('/_app/credential3rd/manage')({
|
||||
|
||||
function CredentialManageRouteComponent() {
|
||||
const navigate = useNavigate();
|
||||
const intlService = useInject(IntlService);
|
||||
|
||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
|
||||
createdAt: false,
|
||||
@@ -94,18 +96,18 @@ function CredentialManageRouteComponent() {
|
||||
const [deleteCredential] = useMutation(DELETE_CREDENTIAL_3RD, {
|
||||
onCompleted: async () => {
|
||||
const refetchResult = await refetch();
|
||||
const error = getApolloQueryError(refetchResult);
|
||||
if (error) {
|
||||
const e = getApolloQueryError(refetchResult);
|
||||
if (e) {
|
||||
toast.error('Failed to delete credential', {
|
||||
description: apolloErrorToMessage(error),
|
||||
description: apolloErrorToMessage(e),
|
||||
});
|
||||
return;
|
||||
}
|
||||
toast.success('Credential deleted');
|
||||
},
|
||||
onError: (error) => {
|
||||
onError: (e) => {
|
||||
toast.error('Failed to delete credential', {
|
||||
description: error.message,
|
||||
description: e.message,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -212,7 +214,7 @@ function CredentialManageRouteComponent() {
|
||||
const createdAt = row.original.createdAt;
|
||||
return (
|
||||
<div className="text-sm">
|
||||
{format(new Date(createdAt), 'yyyy-MM-dd HH:mm:ss')}
|
||||
{intlService.formatDatetimeWithTz(createdAt)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -224,7 +226,7 @@ function CredentialManageRouteComponent() {
|
||||
const updatedAt = row.original.updatedAt;
|
||||
return (
|
||||
<div className="text-sm">
|
||||
{format(new Date(updatedAt), 'yyyy-MM-dd HH:mm:ss')}
|
||||
{intlService.formatDatetimeWithTz(updatedAt)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -266,7 +268,13 @@ function CredentialManageRouteComponent() {
|
||||
},
|
||||
];
|
||||
return cs;
|
||||
}, [handleDeleteRecord, navigate, showPasswords, togglePasswordVisibility]);
|
||||
}, [
|
||||
handleDeleteRecord,
|
||||
navigate,
|
||||
showPasswords,
|
||||
togglePasswordVisibility,
|
||||
intlService.formatDatetimeWithTz,
|
||||
]);
|
||||
|
||||
const table = useReactTable({
|
||||
data: useMemo(() => credentials?.nodes ?? [], [credentials]),
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import {
|
||||
Edit,
|
||||
ExternalLink,
|
||||
ListIcon,
|
||||
Pause,
|
||||
Play,
|
||||
PlusIcon,
|
||||
RefreshCcwIcon,
|
||||
Trash2,
|
||||
} from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@@ -13,6 +27,7 @@ import { DetailEmptyView } from '@/components/ui/detail-empty-view';
|
||||
import { Dialog, DialogTrigger } from '@/components/ui/dialog';
|
||||
import { Img } from '@/components/ui/img';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { ProLink } from '@/components/ui/pro-link';
|
||||
import { QueryErrorView } from '@/components/ui/query-error-view';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { UPDATE_CRONS } from '@/domains/recorder/schema/cron';
|
||||
@@ -33,27 +48,14 @@ import {
|
||||
FeedSourceEnum,
|
||||
FeedTypeEnum,
|
||||
type GetSubscriptionDetailQuery,
|
||||
type GetSubscriptionDetailQueryVariables,
|
||||
type InsertFeedMutation,
|
||||
type InsertFeedMutationVariables,
|
||||
SubscriptionCategoryEnum,
|
||||
type UpdateCronsMutation,
|
||||
type UpdateCronsMutationVariables,
|
||||
} from '@/infra/graphql/gql/graphql';
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import { format } from 'date-fns';
|
||||
import {
|
||||
Edit,
|
||||
ExternalLink,
|
||||
ListIcon,
|
||||
Pause,
|
||||
Play,
|
||||
PlusIcon,
|
||||
RefreshCcwIcon,
|
||||
Trash2,
|
||||
} from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { IntlService } from '@/infra/intl/intl.service';
|
||||
import { prettyTaskType } from '../tasks/-pretty-task-type';
|
||||
import { SubscriptionCronCreationDialogContent } from './-cron-creation';
|
||||
import { SubscriptionTaskCreationDialogContent } from './-task-creation';
|
||||
@@ -66,6 +68,7 @@ function SubscriptionDetailRouteComponent() {
|
||||
const { id } = Route.useParams();
|
||||
const navigate = useNavigate();
|
||||
const subscriptionService = useInject(SubscriptionService);
|
||||
const intlService = useInject(IntlService);
|
||||
|
||||
const handleReload = async () => {
|
||||
const result = await refetch();
|
||||
@@ -77,12 +80,23 @@ function SubscriptionDetailRouteComponent() {
|
||||
}
|
||||
};
|
||||
|
||||
const { data, loading, error, refetch } =
|
||||
useQuery<GetSubscriptionDetailQuery>(GET_SUBSCRIPTION_DETAIL, {
|
||||
const {
|
||||
data,
|
||||
loading,
|
||||
error: subscriptionError,
|
||||
refetch,
|
||||
} = useQuery<GetSubscriptionDetailQuery, GetSubscriptionDetailQueryVariables>(
|
||||
GET_SUBSCRIPTION_DETAIL,
|
||||
{
|
||||
variables: {
|
||||
id: Number.parseInt(id),
|
||||
filter: {
|
||||
id: {
|
||||
eq: Number.parseInt(id, 10),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const handleEnterEditMode = () => {
|
||||
navigate({
|
||||
@@ -203,8 +217,8 @@ function SubscriptionDetailRouteComponent() {
|
||||
return <DetailCardSkeleton />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <QueryErrorView message={error.message} />;
|
||||
if (subscriptionError) {
|
||||
return <QueryErrorView message={subscriptionError.message} />;
|
||||
}
|
||||
|
||||
if (!subscription) {
|
||||
@@ -342,10 +356,7 @@ function SubscriptionDetailRouteComponent() {
|
||||
<Label className="font-medium text-sm">Created at</Label>
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{format(
|
||||
new Date(subscription.createdAt),
|
||||
'yyyy-MM-dd HH:mm:ss'
|
||||
)}
|
||||
{intlService.formatDatetimeWithTz(subscription.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -354,10 +365,7 @@ function SubscriptionDetailRouteComponent() {
|
||||
<Label className="font-medium text-sm">Updated at</Label>
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{format(
|
||||
new Date(subscription.updatedAt),
|
||||
'yyyy-MM-dd HH:mm:ss'
|
||||
)}
|
||||
{intlService.formatDatetimeWithTz(subscription.updatedAt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -374,7 +382,7 @@ function SubscriptionDetailRouteComponent() {
|
||||
insertFeed({
|
||||
variables: {
|
||||
data: {
|
||||
subscriptionId: Number.parseInt(id),
|
||||
subscriptionId: Number.parseInt(id, 10),
|
||||
feedType: FeedTypeEnum.Rss,
|
||||
feedSource: FeedSourceEnum.SubscriptionEpisode,
|
||||
},
|
||||
@@ -429,7 +437,7 @@ function SubscriptionDetailRouteComponent() {
|
||||
</code>
|
||||
|
||||
<div className="text-muted-foreground text-xs">
|
||||
{format(new Date(feed.createdAt), 'MM-dd HH:mm')}
|
||||
{intlService.formatDatetimeWithTz(feed.createdAt)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -684,24 +692,22 @@ function SubscriptionDetailRouteComponent() {
|
||||
Updated At
|
||||
</Label>
|
||||
<div className="font-mono text-sm">
|
||||
{format(
|
||||
new Date(bangumi.updatedAt),
|
||||
'yyyy-MM-dd'
|
||||
{intlService.formatDatetimeWithTz(
|
||||
bangumi.updatedAt
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{bangumi.homepage && (
|
||||
<div className="mt-3 border-t pt-3">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
window.open(bangumi.homepage!, '_blank')
|
||||
}
|
||||
>
|
||||
<ExternalLink className="mr-2 h-3 w-3" />
|
||||
Homepage
|
||||
<Button variant="outline" size="sm" asChild>
|
||||
<ProLink
|
||||
href={bangumi.homepage}
|
||||
target="_blank"
|
||||
>
|
||||
<ExternalLink className="mr-2 h-3 w-3" />
|
||||
Homepage
|
||||
</ProLink>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import {
|
||||
type ColumnDef,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
type PaginationState,
|
||||
type SortingState,
|
||||
useReactTable,
|
||||
type VisibilityState,
|
||||
} from '@tanstack/react-table';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ContainerHeader } from '@/components/ui/container-header';
|
||||
import { DataTablePagination } from '@/components/ui/data-table-pagination';
|
||||
@@ -22,31 +37,19 @@ import {
|
||||
type SubscriptionDto,
|
||||
UPDATE_SUBSCRIPTIONS,
|
||||
} from '@/domains/recorder/schema/subscriptions';
|
||||
import { useInject } from '@/infra/di/inject';
|
||||
import {
|
||||
apolloErrorToMessage,
|
||||
getApolloQueryError,
|
||||
} from '@/infra/errors/apollo';
|
||||
import type { GetSubscriptionsQuery } from '@/infra/graphql/gql/graphql';
|
||||
import type {
|
||||
GetSubscriptionsQuery,
|
||||
GetSubscriptionsQueryVariables,
|
||||
} from '@/infra/graphql/gql/graphql';
|
||||
import { IntlService } from '@/infra/intl/intl.service';
|
||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||
import { useDebouncedSkeleton } from '@/presentation/hooks/use-debounded-skeleton';
|
||||
import { cn } from '@/presentation/utils';
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import {
|
||||
type ColumnDef,
|
||||
type PaginationState,
|
||||
type SortingState,
|
||||
type VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
useReactTable,
|
||||
} from '@tanstack/react-table';
|
||||
import { format } from 'date-fns';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { SubscriptionTaskCreationDialogContent } from './-task-creation';
|
||||
|
||||
export const Route = createFileRoute('/_app/subscriptions/manage')({
|
||||
@@ -58,6 +61,7 @@ export const Route = createFileRoute('/_app/subscriptions/manage')({
|
||||
|
||||
function SubscriptionManageRouteComponent() {
|
||||
const navigate = useNavigate();
|
||||
const intlService = useInject(IntlService);
|
||||
|
||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
|
||||
createdAt: false,
|
||||
@@ -69,7 +73,12 @@ function SubscriptionManageRouteComponent() {
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
const { loading, error, data, refetch } = useQuery<GetSubscriptionsQuery>(
|
||||
const {
|
||||
loading,
|
||||
error: subscriptionsError,
|
||||
data,
|
||||
refetch,
|
||||
} = useQuery<GetSubscriptionsQuery, GetSubscriptionsQueryVariables>(
|
||||
GET_SUBSCRIPTIONS,
|
||||
{
|
||||
variables: {
|
||||
@@ -138,11 +147,11 @@ function SubscriptionManageRouteComponent() {
|
||||
<div className="px-1">
|
||||
<Switch
|
||||
checked={enabled}
|
||||
onCheckedChange={(enabled) =>
|
||||
onCheckedChange={(checked) =>
|
||||
updateSubscription({
|
||||
variables: {
|
||||
data: {
|
||||
enabled,
|
||||
enabled: checked,
|
||||
},
|
||||
filter: {
|
||||
id: {
|
||||
@@ -189,7 +198,7 @@ function SubscriptionManageRouteComponent() {
|
||||
const createdAt = row.original.createdAt;
|
||||
return (
|
||||
<div className="text-sm">
|
||||
{format(new Date(createdAt), 'yyyy-MM-dd HH:mm:ss')}
|
||||
{intlService.formatDatetimeWithTz(createdAt)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -201,7 +210,7 @@ function SubscriptionManageRouteComponent() {
|
||||
const updatedAt = row.original.updatedAt;
|
||||
return (
|
||||
<div className="text-sm">
|
||||
{format(new Date(updatedAt), 'yyyy-MM-dd HH:mm:ss')}
|
||||
{intlService.formatDatetimeWithTz(updatedAt)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -247,7 +256,12 @@ function SubscriptionManageRouteComponent() {
|
||||
},
|
||||
];
|
||||
return cs;
|
||||
}, [updateSubscription, deleteSubscription, navigate]);
|
||||
}, [
|
||||
updateSubscription,
|
||||
deleteSubscription,
|
||||
navigate,
|
||||
intlService.formatDatetimeWithTz,
|
||||
]);
|
||||
|
||||
const table = useReactTable({
|
||||
data: useMemo(() => subscriptions?.nodes ?? [], [subscriptions]),
|
||||
@@ -274,8 +288,10 @@ function SubscriptionManageRouteComponent() {
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return <QueryErrorView message={error.message} onRetry={refetch} />;
|
||||
if (subscriptionsError) {
|
||||
return (
|
||||
<QueryErrorView message={subscriptionsError.message} onRetry={refetch} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { format } from 'date-fns';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
@@ -153,7 +152,7 @@ function CronDetailRouteComponent() {
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{cron.nextRun
|
||||
? format(new Date(cron.nextRun), 'yyyy-MM-dd HH:mm:ss')
|
||||
? intlService.formatDatetimeWithTz(cron.nextRun)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -164,7 +163,7 @@ function CronDetailRouteComponent() {
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{cron.lastRun
|
||||
? format(new Date(cron.lastRun), 'yyyy-MM-dd HH:mm:ss')
|
||||
? intlService.formatDatetimeWithTz(cron.lastRun)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -175,7 +174,7 @@ function CronDetailRouteComponent() {
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{cron.lockedAt
|
||||
? format(new Date(cron.lockedAt), 'yyyy-MM-dd HH:mm:ss')
|
||||
? intlService.formatDatetimeWithTz(cron.lockedAt)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -201,10 +200,7 @@ function CronDetailRouteComponent() {
|
||||
<Label className="font-medium text-sm">Created at</Label>
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{intlService.formatTimestamp(
|
||||
cron.createdAt,
|
||||
'yyyy-MM-dd HH:mm:ss'
|
||||
)}
|
||||
{intlService.formatDatetimeWithTz(cron.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -213,31 +209,12 @@ function CronDetailRouteComponent() {
|
||||
<Label className="font-medium text-sm">Updated at</Label>
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{format(new Date(cron.updatedAt), 'yyyy-MM-dd HH:mm:ss')}
|
||||
{intlService.formatDatetimeWithTz(cron.updatedAt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Cron Expression Display */}
|
||||
{cron.cronExpr && (
|
||||
<>
|
||||
<Separator />
|
||||
<div className="space-y-2">
|
||||
<Label className="font-medium text-sm">
|
||||
Cron expression
|
||||
</Label>
|
||||
<CronDisplay
|
||||
expression={cron.cronExpr}
|
||||
timezone="UTC"
|
||||
showDescription={true}
|
||||
showNextRuns={true}
|
||||
withCard={false}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Subscriber Task Details */}
|
||||
{subscriberTaskCron && (
|
||||
<>
|
||||
@@ -257,6 +234,25 @@ function CronDetailRouteComponent() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Cron Expression Display */}
|
||||
{cron.cronExpr && (
|
||||
<>
|
||||
<Separator />
|
||||
<div className="space-y-2">
|
||||
<Label className="font-medium text-sm">
|
||||
Cron expression
|
||||
</Label>
|
||||
<CronDisplay
|
||||
expression={cron.cronExpr}
|
||||
timezone="UTC"
|
||||
showDescription={true}
|
||||
showNextRuns={true}
|
||||
withCard={false}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Related Subscriber Tasks */}
|
||||
{cron.subscriberTask?.nodes &&
|
||||
cron.subscriberTask.nodes.length > 0 && (
|
||||
@@ -277,11 +273,11 @@ function CronDetailRouteComponent() {
|
||||
<Badge variant="outline">{task.status}</Badge>
|
||||
</div>
|
||||
<div className="mt-2 text-muted-foreground text-sm">
|
||||
Priority: {task.priority} | Retry: {task.attempts}
|
||||
/{task.maxAttempts}
|
||||
Priority: {task.priority} | Attempts:{' '}
|
||||
{task.attempts}/{task.maxAttempts}
|
||||
</div>
|
||||
{task.subscription && (
|
||||
<div className="mt-1 text-sm">
|
||||
<div className="mt-2 text-sm">
|
||||
<span className="font-medium">
|
||||
Subscription:
|
||||
</span>{' '}
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
useReactTable,
|
||||
type VisibilityState,
|
||||
} from '@tanstack/react-table';
|
||||
import { format } from 'date-fns';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -26,6 +25,7 @@ import {
|
||||
DELETE_CRONS,
|
||||
GET_CRONS,
|
||||
} from '@/domains/recorder/schema/cron';
|
||||
import { useInject } from '@/infra/di/inject';
|
||||
import {
|
||||
apolloErrorToMessage,
|
||||
getApolloQueryError,
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
type GetCronsQuery,
|
||||
type GetCronsQueryVariables,
|
||||
} from '@/infra/graphql/gql/graphql';
|
||||
import { IntlService } from '@/infra/intl/intl.service';
|
||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||
import { useDebouncedSkeleton } from '@/presentation/hooks/use-debounded-skeleton';
|
||||
import { getStatusBadge } from './-status-badge';
|
||||
@@ -50,6 +51,7 @@ export const Route = createFileRoute('/_app/tasks/cron/manage')({
|
||||
|
||||
function TaskCronManageRouteComponent() {
|
||||
const navigate = useNavigate();
|
||||
const intlService = useInject(IntlService);
|
||||
|
||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
@@ -224,7 +226,7 @@ function TaskCronManageRouteComponent() {
|
||||
<span className="text-muted-foreground">Next run: </span>
|
||||
<span>
|
||||
{cron.nextRun
|
||||
? format(new Date(cron.nextRun), 'MM/dd HH:mm')
|
||||
? intlService.formatDatetimeWithTz(cron.nextRun)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -233,7 +235,7 @@ function TaskCronManageRouteComponent() {
|
||||
<span className="text-muted-foreground">Last run: </span>
|
||||
<span>
|
||||
{cron.lastRun
|
||||
? format(new Date(cron.lastRun), 'MM/dd HH:mm')
|
||||
? intlService.formatDatetimeWithTz(cron.lastRun)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -251,7 +253,7 @@ function TaskCronManageRouteComponent() {
|
||||
<span className="text-muted-foreground">Lock at: </span>
|
||||
<span>
|
||||
{cron.lockedAt
|
||||
? format(new Date(cron.lockedAt), 'MM/dd HH:mm')
|
||||
? intlService.formatDatetimeWithTz(cron.lockedAt)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@@ -14,8 +19,11 @@ import { Label } from '@/components/ui/label';
|
||||
import { QueryErrorView } from '@/components/ui/query-error-view';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { GET_TASKS, RETRY_TASKS } from '@/domains/recorder/schema/tasks';
|
||||
import { getApolloQueryError } from '@/infra/errors/apollo';
|
||||
import { apolloErrorToMessage } from '@/infra/errors/apollo';
|
||||
import { useInject } from '@/infra/di/inject';
|
||||
import {
|
||||
apolloErrorToMessage,
|
||||
getApolloQueryError,
|
||||
} from '@/infra/errors/apollo';
|
||||
import {
|
||||
type GetTasksQuery,
|
||||
type GetTasksQueryVariables,
|
||||
@@ -23,13 +31,8 @@ import {
|
||||
type RetryTasksMutationVariables,
|
||||
SubscriberTaskStatusEnum,
|
||||
} from '@/infra/graphql/gql/graphql';
|
||||
import { IntlService } from '@/infra/intl/intl.service';
|
||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { format } from 'date-fns';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { prettyTaskType } from './-pretty-task-type';
|
||||
import { getStatusBadge } from './-status-badge';
|
||||
|
||||
@@ -43,10 +46,14 @@ export const Route = createFileRoute('/_app/tasks/detail/$id')({
|
||||
function TaskDetailRouteComponent() {
|
||||
const { id } = Route.useParams();
|
||||
|
||||
const { data, loading, error, refetch } = useQuery<
|
||||
GetTasksQuery,
|
||||
GetTasksQueryVariables
|
||||
>(GET_TASKS, {
|
||||
const intlService = useInject(IntlService);
|
||||
|
||||
const {
|
||||
data,
|
||||
loading,
|
||||
error: taskError,
|
||||
refetch,
|
||||
} = useQuery<GetTasksQuery, GetTasksQueryVariables>(GET_TASKS, {
|
||||
variables: {
|
||||
filter: {
|
||||
id: {
|
||||
@@ -102,8 +109,8 @@ function TaskDetailRouteComponent() {
|
||||
return <DetailCardSkeleton />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <QueryErrorView message={error.message} onRetry={refetch} />;
|
||||
if (taskError) {
|
||||
return <QueryErrorView message={taskError.message} onRetry={refetch} />;
|
||||
}
|
||||
|
||||
if (!task) {
|
||||
@@ -195,7 +202,7 @@ function TaskDetailRouteComponent() {
|
||||
</Label>
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{format(new Date(task.runAt), 'yyyy-MM-dd HH:mm:ss')}
|
||||
{intlService.formatDatetimeWithTz(task.runAt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -205,7 +212,7 @@ function TaskDetailRouteComponent() {
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{task.doneAt
|
||||
? format(new Date(task.doneAt), 'yyyy-MM-dd HH:mm:ss')
|
||||
? intlService.formatDatetimeWithTz(task.doneAt)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -216,7 +223,7 @@ function TaskDetailRouteComponent() {
|
||||
<div className="rounded-md bg-muted p-3">
|
||||
<span className="text-sm">
|
||||
{task.lockAt
|
||||
? format(new Date(task.lockAt), 'yyyy-MM-dd HH:mm:ss')
|
||||
? intlService.formatDatetimeWithTz(task.lockAt)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import {
|
||||
type ColumnDef,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
type PaginationState,
|
||||
type SortingState,
|
||||
useReactTable,
|
||||
type VisibilityState,
|
||||
} from '@tanstack/react-table';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ContainerHeader } from '@/components/ui/container-header';
|
||||
import { DataTablePagination } from '@/components/ui/data-table-pagination';
|
||||
import { DetailEmptyView } from '@/components/ui/detail-empty-view';
|
||||
import { DropdownMenuItem } from '@/components/ui/dropdown-menu';
|
||||
import { DropdownMenuActions } from '@/components/ui/dropdown-menu-actions';
|
||||
import { QueryErrorView } from '@/components/ui/query-error-view';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
@@ -11,6 +27,11 @@ import {
|
||||
RETRY_TASKS,
|
||||
type TaskDto,
|
||||
} from '@/domains/recorder/schema/tasks';
|
||||
import { useInject } from '@/infra/di/inject';
|
||||
import {
|
||||
apolloErrorToMessage,
|
||||
getApolloQueryError,
|
||||
} from '@/infra/errors/apollo';
|
||||
import {
|
||||
type DeleteTasksMutation,
|
||||
type DeleteTasksMutationVariables,
|
||||
@@ -20,30 +41,9 @@ import {
|
||||
type RetryTasksMutationVariables,
|
||||
SubscriberTaskStatusEnum,
|
||||
} from '@/infra/graphql/gql/graphql';
|
||||
import { IntlService } from '@/infra/intl/intl.service';
|
||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||
import { useDebouncedSkeleton } from '@/presentation/hooks/use-debounded-skeleton';
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import {
|
||||
type ColumnDef,
|
||||
type PaginationState,
|
||||
type SortingState,
|
||||
type VisibilityState,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
useReactTable,
|
||||
} from '@tanstack/react-table';
|
||||
import { format } from 'date-fns';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
|
||||
import { ContainerHeader } from '@/components/ui/container-header';
|
||||
import { DropdownMenuItem } from '@/components/ui/dropdown-menu';
|
||||
import {
|
||||
apolloErrorToMessage,
|
||||
getApolloQueryError,
|
||||
} from '@/infra/errors/apollo';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { prettyTaskType } from './-pretty-task-type';
|
||||
import { getStatusBadge } from './-status-badge';
|
||||
|
||||
@@ -64,10 +64,14 @@ function TaskManageRouteComponent() {
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
const { loading, error, data, refetch } = useQuery<
|
||||
GetTasksQuery,
|
||||
GetTasksQueryVariables
|
||||
>(GET_TASKS, {
|
||||
const intlService = useInject(IntlService);
|
||||
|
||||
const {
|
||||
loading,
|
||||
error: tasksError,
|
||||
data,
|
||||
refetch,
|
||||
} = useQuery<GetTasksQuery, GetTasksQueryVariables>(GET_TASKS, {
|
||||
variables: {
|
||||
pagination: {
|
||||
page: {
|
||||
@@ -168,8 +172,8 @@ function TaskManageRouteComponent() {
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return <QueryErrorView message={error.message} onRetry={refetch} />;
|
||||
if (tasksError) {
|
||||
return <QueryErrorView message={tasksError.message} onRetry={refetch} />;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -262,14 +266,14 @@ function TaskManageRouteComponent() {
|
||||
<div className="grid grid-cols-2 gap-2 text-sm">
|
||||
<div>
|
||||
<span className="text-muted-foreground">Run at: </span>
|
||||
<span>{format(new Date(task.runAt), 'MM/dd HH:mm')}</span>
|
||||
<span>{intlService.formatDatetimeWithTz(task.runAt)}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span className="text-muted-foreground">Done: </span>
|
||||
<span>
|
||||
{task.doneAt
|
||||
? format(new Date(task.doneAt), 'MM/dd HH:mm')
|
||||
? intlService.formatDatetimeWithTz(task.doneAt)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -287,7 +291,7 @@ function TaskManageRouteComponent() {
|
||||
<span className="text-muted-foreground">Lock at: </span>
|
||||
<span>
|
||||
{task.lockAt
|
||||
? format(new Date(task.lockAt), 'MM/dd HH:mm')
|
||||
? intlService.formatDatetimeWithTz(task.lockAt)
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user