fix: fix cron builder
This commit is contained in:
parent
6cdd8c27ce
commit
5be5b9f634
@ -12,6 +12,7 @@ const config: CodegenConfig = {
|
|||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
enumsAsConst: true,
|
enumsAsConst: true,
|
||||||
|
useTypeImports: true,
|
||||||
scalars: {
|
scalars: {
|
||||||
SubscriberTaskType: {
|
SubscriberTaskType: {
|
||||||
input: 'recorder/bindings/SubscriberTaskInput#SubscriberTaskInput',
|
input: 'recorder/bindings/SubscriberTaskInput#SubscriberTaskInput',
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
import { getFutureMatches } from '@datasert/cronjs-matcher';
|
||||||
|
import { Calendar, Clock, Info, Settings, Zap } from 'lucide-react';
|
||||||
|
import {
|
||||||
|
type CSSProperties,
|
||||||
|
type FC,
|
||||||
|
memo,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
@ -20,16 +31,6 @@ import { Separator } from '@/components/ui/separator';
|
|||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||||
import { cn } from '@/presentation/utils';
|
import { cn } from '@/presentation/utils';
|
||||||
import { getFutureMatches } from '@datasert/cronjs-matcher';
|
|
||||||
import { Calendar, Clock, Info, Settings, Zap } from 'lucide-react';
|
|
||||||
import {
|
|
||||||
type CSSProperties,
|
|
||||||
type FC,
|
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import {
|
import {
|
||||||
type CronBuilderProps,
|
type CronBuilderProps,
|
||||||
CronField,
|
CronField,
|
||||||
@ -345,7 +346,7 @@ const CronBuilder: FC<CronBuilderProps> = ({
|
|||||||
<div className={cn(withCard && 'space-y-6', className)}>
|
<div className={cn(withCard && 'space-y-6', className)}>
|
||||||
<Tabs
|
<Tabs
|
||||||
value={activeTab}
|
value={activeTab}
|
||||||
onValueChange={(value) => handlePeriodChange(value as CronPeriod)}
|
onValueChange={(v) => handlePeriodChange(v as CronPeriod)}
|
||||||
>
|
>
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
<TabsList
|
<TabsList
|
||||||
@ -516,15 +517,114 @@ const CronFieldEditor: FC<CronFieldEditorProps> = ({
|
|||||||
const currentValue = fields[field];
|
const currentValue = fields[field];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={field} className="space-y-2">
|
<CronFieldItemEditor
|
||||||
|
key={field}
|
||||||
|
config={config}
|
||||||
|
field={field}
|
||||||
|
value={currentValue}
|
||||||
|
onChange={onChange}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CronFieldItemAnyOrSpecificOption = {
|
||||||
|
Any: 'any',
|
||||||
|
Specific: 'specific',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type CronFieldItemAnyOrSpecificOption =
|
||||||
|
(typeof CronFieldItemAnyOrSpecificOption)[keyof typeof CronFieldItemAnyOrSpecificOption];
|
||||||
|
|
||||||
|
interface CronFieldItemEditorProps {
|
||||||
|
config: CronFieldConfig;
|
||||||
|
field: CronField;
|
||||||
|
value: string;
|
||||||
|
onChange: (field: CronField, value: string) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeCronFieldItem(value: string): string {
|
||||||
|
if (value === '') {
|
||||||
|
return '<meta:empty>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.includes(' ')) {
|
||||||
|
return `<meta:contains-space:${encodeURIComponent(value)}>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeCronFieldItem(value: string): string {
|
||||||
|
if (value.startsWith('<meta:contains')) {
|
||||||
|
return decodeURIComponent(
|
||||||
|
// biome-ignore lint/performance/useTopLevelRegex: false
|
||||||
|
value.replace(/^<meta:contains-space:([^>]+)>$/, '$1')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === '<meta:empty>') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CronFieldItemEditor: FC<CronFieldItemEditorProps> = memo(
|
||||||
|
({ field, value, onChange, config, disabled = false }) => {
|
||||||
|
const [innerValue, _setInnerValue] = useState(() =>
|
||||||
|
decodeCronFieldItem(value)
|
||||||
|
);
|
||||||
|
|
||||||
|
const [anyOrSpecificOption, _setAnyOrSpecificOption] =
|
||||||
|
useState<CronFieldItemAnyOrSpecificOption>(() =>
|
||||||
|
innerValue === '*'
|
||||||
|
? CronFieldItemAnyOrSpecificOption.Any
|
||||||
|
: CronFieldItemAnyOrSpecificOption.Specific
|
||||||
|
);
|
||||||
|
|
||||||
|
// biome-ignore lint/correctness/useExhaustiveDependencies: false
|
||||||
|
useEffect(() => {
|
||||||
|
const nextValue = decodeCronFieldItem(value);
|
||||||
|
if (nextValue !== innerValue) {
|
||||||
|
_setInnerValue(nextValue);
|
||||||
|
}
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(v: string) => {
|
||||||
|
_setInnerValue(v);
|
||||||
|
onChange(field, encodeCronFieldItem(v));
|
||||||
|
},
|
||||||
|
[field, onChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
const setAnyOrSpecificOption = useCallback(
|
||||||
|
(v: CronFieldItemAnyOrSpecificOption) => {
|
||||||
|
_setAnyOrSpecificOption(v);
|
||||||
|
if (v === CronFieldItemAnyOrSpecificOption.Any) {
|
||||||
|
handleChange('*');
|
||||||
|
} else if (v === CronFieldItemAnyOrSpecificOption.Specific) {
|
||||||
|
handleChange('0');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[handleChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-2">
|
||||||
<Label className="font-medium text-sm capitalize">
|
<Label className="font-medium text-sm capitalize">
|
||||||
{field.replace(/([A-Z])/g, ' $1').toLowerCase()}
|
{field.replace(/([A-Z])/g, ' $1').toLowerCase()}
|
||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
{field === 'month' || field === 'dayOfWeek' ? (
|
{(field === 'month' || field === 'dayOfWeek') && (
|
||||||
<Select
|
<Select
|
||||||
value={currentValue}
|
value={innerValue}
|
||||||
onValueChange={(value) => onChange(field, value)}
|
onValueChange={handleChange}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
@ -539,12 +639,12 @@ const CronFieldEditor: FC<CronFieldEditorProps> = ({
|
|||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
// biome-ignore lint/nursery/noNestedTernary: <explanation>
|
)}
|
||||||
) : field === 'dayOfMonth' ? (
|
{field === 'dayOfMonth' && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Select
|
<Select
|
||||||
value={currentValue}
|
value={innerValue}
|
||||||
onValueChange={(value) => onChange(field, value)}
|
onValueChange={handleChange}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
@ -564,36 +664,39 @@ const CronFieldEditor: FC<CronFieldEditorProps> = ({
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
)}
|
||||||
|
{!(
|
||||||
|
field === 'month' ||
|
||||||
|
field === 'dayOfWeek' ||
|
||||||
|
field === 'dayOfMonth'
|
||||||
|
) && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<ToggleGroup
|
<ToggleGroup
|
||||||
type="single"
|
type="single"
|
||||||
value={currentValue === '*' ? '*' : 'specific'}
|
value={anyOrSpecificOption}
|
||||||
onValueChange={(value) => {
|
onValueChange={setAnyOrSpecificOption}
|
||||||
if (value === '*') {
|
|
||||||
onChange(field, '*');
|
|
||||||
} else if (value === 'specific' && currentValue === '*') {
|
|
||||||
onChange(field, '0');
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<ToggleGroupItem value="*" className="min-w-fit text-xs">
|
<ToggleGroupItem
|
||||||
|
value={CronFieldItemAnyOrSpecificOption.Any}
|
||||||
|
className="min-w-fit text-xs"
|
||||||
|
>
|
||||||
Any
|
Any
|
||||||
</ToggleGroupItem>
|
</ToggleGroupItem>
|
||||||
<ToggleGroupItem
|
<ToggleGroupItem
|
||||||
value="specific"
|
value={CronFieldItemAnyOrSpecificOption.Specific}
|
||||||
className="min-w-fit text-xs"
|
className="min-w-fit text-xs"
|
||||||
>
|
>
|
||||||
Specific
|
Specific
|
||||||
</ToggleGroupItem>
|
</ToggleGroupItem>
|
||||||
</ToggleGroup>
|
</ToggleGroup>
|
||||||
|
|
||||||
{currentValue !== '*' && (
|
{anyOrSpecificOption ===
|
||||||
|
CronFieldItemAnyOrSpecificOption.Specific && (
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
value={currentValue}
|
value={innerValue}
|
||||||
onChange={(e) => onChange(field, e.target.value)}
|
onChange={(e) => handleChange(e.target.value)}
|
||||||
placeholder={`0-${config.max}`}
|
placeholder={`0-${config.max}`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className="font-mono text-sm"
|
className="font-mono text-sm"
|
||||||
@ -608,18 +711,15 @@ const CronFieldEditor: FC<CronFieldEditorProps> = ({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
Supports: *, numbers, ranges (1-5), lists (1,3,5), steps
|
Supports: *, numbers, ranges (1-5), lists (1,3,5), steps (*/5)
|
||||||
(*/5)
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
}
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
function parseCronExpression(expression: string): Record<CronField, string> {
|
function parseCronExpression(expression: string): Record<CronField, string> {
|
||||||
const parts = expression.split(' ');
|
const parts = expression.split(' ');
|
||||||
|
@ -33,7 +33,11 @@ const CronInput = forwardRef<HTMLInputElement, CronInputProps>(
|
|||||||
|
|
||||||
const validationResult = useMemo((): CronValidationResult => {
|
const validationResult = useMemo((): CronValidationResult => {
|
||||||
if (!internalValue.trim()) {
|
if (!internalValue.trim()) {
|
||||||
return { isValid: false, error: 'Expression is required' };
|
return {
|
||||||
|
isValid: false,
|
||||||
|
error: 'Expression is required',
|
||||||
|
isEmpty: true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
import { parse } from '@datasert/cronjs-parser';
|
||||||
|
import {
|
||||||
|
AlertCircle,
|
||||||
|
Bolt,
|
||||||
|
Check,
|
||||||
|
Code2,
|
||||||
|
Copy,
|
||||||
|
Settings,
|
||||||
|
Type,
|
||||||
|
} from 'lucide-react';
|
||||||
|
import { type FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
@ -10,17 +21,6 @@ import {
|
|||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { cn } from '@/presentation/utils';
|
import { cn } from '@/presentation/utils';
|
||||||
import { parse } from '@datasert/cronjs-parser';
|
|
||||||
import {
|
|
||||||
AlertCircle,
|
|
||||||
Bolt,
|
|
||||||
Check,
|
|
||||||
Code2,
|
|
||||||
Copy,
|
|
||||||
Settings,
|
|
||||||
Type,
|
|
||||||
} from 'lucide-react';
|
|
||||||
import { type FC, useCallback, useEffect, useMemo, useState } from 'react';
|
|
||||||
import { CronBuilder } from './cron-builder';
|
import { CronBuilder } from './cron-builder';
|
||||||
import { CronDisplay } from './cron-display';
|
import { CronDisplay } from './cron-display';
|
||||||
import { CronInput } from './cron-input';
|
import { CronInput } from './cron-input';
|
||||||
@ -55,7 +55,7 @@ const Cron: FC<CronProps> = ({
|
|||||||
showPresets,
|
showPresets,
|
||||||
withCard = true,
|
withCard = true,
|
||||||
isFirstSibling = false,
|
isFirstSibling = false,
|
||||||
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <explanation>
|
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: false
|
||||||
}) => {
|
}) => {
|
||||||
const [internalValue, setInternalValue] = useState(value || '');
|
const [internalValue, setInternalValue] = useState(value || '');
|
||||||
const [internalActiveMode, setInternalActiveMode] =
|
const [internalActiveMode, setInternalActiveMode] =
|
||||||
@ -106,9 +106,9 @@ const Cron: FC<CronProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleActiveModeChange = useCallback(
|
const handleActiveModeChange = useCallback(
|
||||||
(mode: CronPrimitiveMode) => {
|
(m: CronPrimitiveMode) => {
|
||||||
setInternalActiveMode(mode);
|
setInternalActiveMode(m);
|
||||||
onActiveModeChange?.(mode);
|
onActiveModeChange?.(m);
|
||||||
},
|
},
|
||||||
[onActiveModeChange]
|
[onActiveModeChange]
|
||||||
);
|
);
|
||||||
@ -122,8 +122,8 @@ const Cron: FC<CronProps> = ({
|
|||||||
await navigator.clipboard.writeText(internalValue);
|
await navigator.clipboard.writeText(internalValue);
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
setTimeout(() => setCopied(false), 2000);
|
setTimeout(() => setCopied(false), 2000);
|
||||||
} catch (error) {
|
} catch (e) {
|
||||||
console.warn('Failed to copy to clipboard:', error);
|
console.warn('Failed to copy to clipboard:', e);
|
||||||
}
|
}
|
||||||
}, [internalValue]);
|
}, [internalValue]);
|
||||||
|
|
||||||
@ -241,8 +241,8 @@ const Cron: FC<CronProps> = ({
|
|||||||
<CardContent className={cn(!withCard && 'px-0')}>
|
<CardContent className={cn(!withCard && 'px-0')}>
|
||||||
<Tabs
|
<Tabs
|
||||||
value={internalActiveMode}
|
value={internalActiveMode}
|
||||||
onValueChange={(value) =>
|
onValueChange={(v) =>
|
||||||
handleActiveModeChange(value as 'input' | 'builder')
|
handleActiveModeChange(v as 'input' | 'builder')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<TabsList className="grid w-full grid-cols-2">
|
<TabsList className="grid w-full grid-cols-2">
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
export { Cron } from './cron';
|
export { Cron } from './cron';
|
||||||
export { CronInput } from './cron-input';
|
|
||||||
export { CronBuilder } from './cron-builder';
|
export { CronBuilder } from './cron-builder';
|
||||||
export { CronDisplay } from './cron-display';
|
export { CronDisplay } from './cron-display';
|
||||||
export { CronExample } from './cron-example';
|
export { CronExample } from './cron-example';
|
||||||
|
export { CronInput } from './cron-input';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
type CronProps,
|
|
||||||
type CronInputProps,
|
|
||||||
type CronBuilderProps,
|
type CronBuilderProps,
|
||||||
type CronDisplayProps,
|
type CronDisplayProps,
|
||||||
type CronExpression,
|
type CronExpression,
|
||||||
|
CronField,
|
||||||
|
type CronFieldConfig,
|
||||||
|
type CronInputProps,
|
||||||
|
type CronNextRun,
|
||||||
CronPeriod,
|
CronPeriod,
|
||||||
type CronPreset,
|
type CronPreset,
|
||||||
|
type CronProps,
|
||||||
type CronValidationResult,
|
type CronValidationResult,
|
||||||
type CronNextRun,
|
|
||||||
type CronFieldConfig,
|
|
||||||
CronField,
|
|
||||||
type PeriodConfig,
|
type PeriodConfig,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { CronPreset } from '@/components/domains/cron';
|
|
||||||
import type { GetCronsQuery } from '@/infra/graphql/gql/graphql';
|
|
||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
|
import type { GetCronsQuery } from '@/infra/graphql/gql/graphql';
|
||||||
|
|
||||||
export const GET_CRONS = gql`
|
export const GET_CRONS = gql`
|
||||||
query GetCrons($filter: CronFilterInput!, $orderBy: CronOrderInput!, $pagination: PaginationInput!) {
|
query GetCrons($filter: CronFilterInput!, $orderBy: CronOrderInput!, $pagination: PaginationInput!) {
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import { type } from 'arktype';
|
||||||
import { arkValidatorToTypeNarrower } from '@/infra/errors/arktype';
|
import { arkValidatorToTypeNarrower } from '@/infra/errors/arktype';
|
||||||
import {
|
import {
|
||||||
type GetSubscriptionsQuery,
|
type GetSubscriptionsQuery,
|
||||||
SubscriptionCategoryEnum,
|
SubscriptionCategoryEnum,
|
||||||
} from '@/infra/graphql/gql/graphql';
|
} from '@/infra/graphql/gql/graphql';
|
||||||
import { gql } from '@apollo/client';
|
|
||||||
import { type } from 'arktype';
|
|
||||||
import {
|
import {
|
||||||
|
extractMikanSubscriptionBangumiSourceUrl,
|
||||||
|
extractMikanSubscriptionSubscriberSourceUrl,
|
||||||
MikanSubscriptionBangumiSourceUrlSchema,
|
MikanSubscriptionBangumiSourceUrlSchema,
|
||||||
MikanSubscriptionSeasonSourceUrlSchema,
|
MikanSubscriptionSeasonSourceUrlSchema,
|
||||||
MikanSubscriptionSubscriberSourceUrlSchema,
|
MikanSubscriptionSubscriberSourceUrlSchema,
|
||||||
extractMikanSubscriptionBangumiSourceUrl,
|
|
||||||
extractMikanSubscriptionSubscriberSourceUrl,
|
|
||||||
} from './mikan';
|
} from './mikan';
|
||||||
|
|
||||||
export const GET_SUBSCRIPTIONS = gql`
|
export const GET_SUBSCRIPTIONS = gql`
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { GetTasksQuery } from '@/infra/graphql/gql/graphql';
|
|
||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
|
import type { GetTasksQuery } from '@/infra/graphql/gql/graphql';
|
||||||
|
|
||||||
export const GET_TASKS = gql`
|
export const GET_TASKS = gql`
|
||||||
query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {
|
query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {
|
||||||
|
30
apps/webui/src/infra/forms/compat.ts
Normal file
30
apps/webui/src/infra/forms/compat.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
type AllKeys<T> = T extends any ? keyof T : never;
|
||||||
|
|
||||||
|
type ToDefaultable<T> = Exclude<
|
||||||
|
T extends string | undefined
|
||||||
|
? T | ''
|
||||||
|
: T extends number | undefined
|
||||||
|
? T | number
|
||||||
|
: T extends undefined
|
||||||
|
? T | null
|
||||||
|
: T,
|
||||||
|
undefined
|
||||||
|
>;
|
||||||
|
|
||||||
|
type PickFieldFormUnion<T, K extends keyof T> = T extends any
|
||||||
|
? T[keyof T & K]
|
||||||
|
: never;
|
||||||
|
|
||||||
|
// compact more types;
|
||||||
|
export type FormDefaultValues<T> = {
|
||||||
|
-readonly [K in AllKeys<T>]-?: ToDefaultable<PickFieldFormUnion<T, K>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/shadcn-ui/ui/issues/427
|
||||||
|
*/
|
||||||
|
export function compatFormDefaultValues<T, K extends AllKeys<T> = AllKeys<T>>(
|
||||||
|
d: FormDefaultValues<Pick<T, K>>
|
||||||
|
): T {
|
||||||
|
return d as unknown as T;
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
|
import type { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
|
||||||
import { FragmentDefinitionNode } from 'graphql';
|
import type { FragmentDefinitionNode } from 'graphql';
|
||||||
import { Incremental } from './graphql';
|
import type { Incremental } from './graphql';
|
||||||
|
|
||||||
|
|
||||||
export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
|
export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import * as types from './graphql';
|
import * as types from './graphql';
|
||||||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of all GraphQL operations in the project.
|
* Map of all GraphQL operations in the project.
|
||||||
@ -31,7 +31,7 @@ type Documents = {
|
|||||||
"\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 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,
|
"\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 ($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,
|
||||||
"\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 cron {\n nodes {\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 }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n": typeof types.GetTasksDocument,
|
"\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 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,
|
"\n mutation DeleteTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksDelete(filter: $filter)\n }\n": typeof types.DeleteTasksDocument,
|
||||||
"\n mutation RetryTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksRetryOne(filter: $filter) {\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 }\n }\n": typeof types.RetryTasksDocument,
|
"\n mutation RetryTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksRetryOne(filter: $filter) {\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 }\n }\n": typeof types.RetryTasksDocument,
|
||||||
@ -54,7 +54,7 @@ const documents: Documents = {
|
|||||||
"\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 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,
|
"\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 ($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,
|
||||||
"\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 cron {\n nodes {\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 }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n": types.GetTasksDocument,
|
"\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 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,
|
"\n mutation DeleteTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksDelete(filter: $filter)\n }\n": types.DeleteTasksDocument,
|
||||||
"\n mutation RetryTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksRetryOne(filter: $filter) {\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 }\n }\n": types.RetryTasksDocument,
|
"\n mutation RetryTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksRetryOne(filter: $filter) {\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 }\n }\n": types.RetryTasksDocument,
|
||||||
@ -145,7 +145,7 @@ export function gql(source: "\nquery GetSubscriptionDetail ($id: Int!) {\n subs
|
|||||||
/**
|
/**
|
||||||
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function gql(source: "\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 cron {\n nodes {\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 }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n"): (typeof documents)["\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 cron {\n nodes {\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 }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n"];
|
export function gql(source: "\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 documents)["\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"];
|
||||||
/**
|
/**
|
||||||
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
|||||||
import { AUTH_PROVIDER } from '@/infra/auth/auth.provider';
|
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';
|
||||||
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
|
|
||||||
import { setContext } from '@apollo/client/link/context';
|
import { setContext } from '@apollo/client/link/context';
|
||||||
import { Injectable, inject } from '@outposts/injection-js';
|
import { Injectable, inject } from '@outposts/injection-js';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
import { AUTH_PROVIDER } from '@/infra/auth/auth.provider';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GraphQLService {
|
export class GraphQLService {
|
||||||
|
@ -1,3 +1,13 @@
|
|||||||
|
import { useMutation } from '@apollo/client';
|
||||||
|
import {
|
||||||
|
createFileRoute,
|
||||||
|
useCanGoBack,
|
||||||
|
useNavigate,
|
||||||
|
useRouter,
|
||||||
|
} from '@tanstack/react-router';
|
||||||
|
import { type } from 'arktype';
|
||||||
|
import { Loader2, Save } from 'lucide-react';
|
||||||
|
import { toast } from 'sonner';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
@ -24,7 +34,9 @@ import {
|
|||||||
INSERT_CREDENTIAL_3RD,
|
INSERT_CREDENTIAL_3RD,
|
||||||
} from '@/domains/recorder/schema/credential3rd';
|
} from '@/domains/recorder/schema/credential3rd';
|
||||||
import { useInject } from '@/infra/di/inject';
|
import { useInject } from '@/infra/di/inject';
|
||||||
|
import { compatFormDefaultValues } from '@/infra/forms/compat';
|
||||||
import {
|
import {
|
||||||
|
type Credential3rdInsertInput,
|
||||||
Credential3rdTypeEnum,
|
Credential3rdTypeEnum,
|
||||||
type InsertCredential3rdMutation,
|
type InsertCredential3rdMutation,
|
||||||
type InsertCredential3rdMutationVariables,
|
type InsertCredential3rdMutationVariables,
|
||||||
@ -35,16 +47,6 @@ import {
|
|||||||
CreateCompleteActionSchema,
|
CreateCompleteActionSchema,
|
||||||
} from '@/infra/routes/nav';
|
} from '@/infra/routes/nav';
|
||||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||||
import { useMutation } from '@apollo/client';
|
|
||||||
import {
|
|
||||||
createFileRoute,
|
|
||||||
useCanGoBack,
|
|
||||||
useNavigate,
|
|
||||||
useRouter,
|
|
||||||
} from '@tanstack/react-router';
|
|
||||||
import { type } from 'arktype';
|
|
||||||
import { Loader2, Save } from 'lucide-react';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
|
|
||||||
const RouteSearchSchema = type({
|
const RouteSearchSchema = type({
|
||||||
completeAction: CreateCompleteActionSchema.optional(),
|
completeAction: CreateCompleteActionSchema.optional(),
|
||||||
@ -98,21 +100,24 @@ function CredentialCreateRouteComponent() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const form = useAppForm({
|
const form = useAppForm({
|
||||||
defaultValues: {
|
defaultValues: compatFormDefaultValues<
|
||||||
|
Credential3rdInsertInput,
|
||||||
|
'credentialType' | 'username' | 'password' | 'userAgent'
|
||||||
|
>({
|
||||||
credentialType: Credential3rdTypeEnum.Mikan,
|
credentialType: Credential3rdTypeEnum.Mikan,
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
userAgent: '',
|
userAgent: '',
|
||||||
},
|
}),
|
||||||
validators: {
|
validators: {
|
||||||
onChangeAsync: Credential3rdInsertSchema,
|
onChangeAsync: Credential3rdInsertSchema,
|
||||||
onChangeAsyncDebounceMs: 300,
|
onChangeAsyncDebounceMs: 300,
|
||||||
onSubmit: Credential3rdInsertSchema,
|
onSubmit: Credential3rdInsertSchema,
|
||||||
},
|
},
|
||||||
onSubmit: async (form) => {
|
onSubmit: async (submittedForm) => {
|
||||||
const value = {
|
const value = {
|
||||||
...form.value,
|
...submittedForm.value,
|
||||||
userAgent: form.value.userAgent || platformService.userAgent,
|
userAgent: submittedForm.value.userAgent || platformService.userAgent,
|
||||||
};
|
};
|
||||||
await insertCredential3rd({
|
await insertCredential3rd({
|
||||||
variables: {
|
variables: {
|
||||||
@ -183,7 +188,7 @@ function CredentialCreateRouteComponent() {
|
|||||||
<Input
|
<Input
|
||||||
id={field.name}
|
id={field.name}
|
||||||
name={field.name}
|
name={field.name}
|
||||||
value={field.state.value}
|
value={field.state.value ?? ''}
|
||||||
onBlur={field.handleBlur}
|
onBlur={field.handleBlur}
|
||||||
onChange={(e) => field.handleChange(e.target.value)}
|
onChange={(e) => field.handleChange(e.target.value)}
|
||||||
placeholder="Please enter username"
|
placeholder="Please enter username"
|
||||||
@ -207,7 +212,7 @@ function CredentialCreateRouteComponent() {
|
|||||||
id={field.name}
|
id={field.name}
|
||||||
name={field.name}
|
name={field.name}
|
||||||
type="password"
|
type="password"
|
||||||
value={field.state.value}
|
value={field.state.value ?? ''}
|
||||||
onBlur={field.handleBlur}
|
onBlur={field.handleBlur}
|
||||||
onChange={(e) => field.handleChange(e.target.value)}
|
onChange={(e) => field.handleChange(e.target.value)}
|
||||||
placeholder="Please enter password"
|
placeholder="Please enter password"
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
import { useMutation, useQuery } from '@apollo/client';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { Eye, EyeOff, Save } from 'lucide-react';
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import { toast } from 'sonner';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
@ -32,18 +37,15 @@ import {
|
|||||||
apolloErrorToMessage,
|
apolloErrorToMessage,
|
||||||
getApolloQueryError,
|
getApolloQueryError,
|
||||||
} from '@/infra/errors/apollo';
|
} from '@/infra/errors/apollo';
|
||||||
|
import { compatFormDefaultValues } from '@/infra/forms/compat';
|
||||||
import type {
|
import type {
|
||||||
Credential3rdTypeEnum,
|
Credential3rdTypeEnum,
|
||||||
|
Credential3rdUpdateInput,
|
||||||
GetCredential3rdDetailQuery,
|
GetCredential3rdDetailQuery,
|
||||||
UpdateCredential3rdMutation,
|
UpdateCredential3rdMutation,
|
||||||
UpdateCredential3rdMutationVariables,
|
UpdateCredential3rdMutationVariables,
|
||||||
} from '@/infra/graphql/gql/graphql';
|
} from '@/infra/graphql/gql/graphql';
|
||||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||||
import { useMutation, useQuery } from '@apollo/client';
|
|
||||||
import { createFileRoute } from '@tanstack/react-router';
|
|
||||||
import { Eye, EyeOff, Save } from 'lucide-react';
|
|
||||||
import { useCallback, useState } from 'react';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/_app/credential3rd/edit/$id')({
|
export const Route = createFileRoute('/_app/credential3rd/edit/$id')({
|
||||||
component: Credential3rdEditRouteComponent,
|
component: Credential3rdEditRouteComponent,
|
||||||
@ -77,18 +79,21 @@ function FormView({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const form = useAppForm({
|
const form = useAppForm({
|
||||||
defaultValues: {
|
defaultValues: compatFormDefaultValues<
|
||||||
|
Credential3rdUpdateInput,
|
||||||
|
'credentialType' | 'username' | 'password' | 'userAgent'
|
||||||
|
>({
|
||||||
credentialType: credential.credentialType,
|
credentialType: credential.credentialType,
|
||||||
username: credential.username,
|
username: credential.username ?? '',
|
||||||
password: credential.password,
|
password: credential.password ?? '',
|
||||||
userAgent: credential.userAgent,
|
userAgent: credential.userAgent ?? '',
|
||||||
},
|
}),
|
||||||
validators: {
|
validators: {
|
||||||
onBlur: Credential3rdUpdateSchema,
|
onBlur: Credential3rdUpdateSchema,
|
||||||
onSubmit: Credential3rdUpdateSchema,
|
onSubmit: Credential3rdUpdateSchema,
|
||||||
},
|
},
|
||||||
onSubmit: (form) => {
|
onSubmit: (submittedForm) => {
|
||||||
const value = form.value;
|
const value = submittedForm.value;
|
||||||
updateCredential({
|
updateCredential({
|
||||||
variables: {
|
variables: {
|
||||||
data: value,
|
data: value,
|
||||||
@ -238,7 +243,7 @@ function Credential3rdEditRouteComponent() {
|
|||||||
const { loading, error, data, refetch } =
|
const { loading, error, data, refetch } =
|
||||||
useQuery<GetCredential3rdDetailQuery>(GET_CREDENTIAL_3RD_DETAIL, {
|
useQuery<GetCredential3rdDetailQuery>(GET_CREDENTIAL_3RD_DETAIL, {
|
||||||
variables: {
|
variables: {
|
||||||
id: Number.parseInt(id),
|
id: Number.parseInt(id, 10),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -246,10 +251,10 @@ function Credential3rdEditRouteComponent() {
|
|||||||
|
|
||||||
const onCompleted = useCallback(async () => {
|
const onCompleted = useCallback(async () => {
|
||||||
const refetchResult = await refetch();
|
const refetchResult = await refetch();
|
||||||
const error = getApolloQueryError(refetchResult);
|
const _error = getApolloQueryError(refetchResult);
|
||||||
if (error) {
|
if (_error) {
|
||||||
toast.error('Update credential failed', {
|
toast.error('Update credential failed', {
|
||||||
description: apolloErrorToMessage(error),
|
description: apolloErrorToMessage(_error),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast.success('Update credential successfully');
|
toast.success('Update credential successfully');
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
import { useMutation } from '@apollo/client';
|
||||||
|
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||||
|
import { Loader2, Save } from 'lucide-react';
|
||||||
|
import { toast } from 'sonner';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
@ -27,6 +31,7 @@ import {
|
|||||||
} from '@/domains/recorder/schema/subscriptions';
|
} from '@/domains/recorder/schema/subscriptions';
|
||||||
import { SubscriptionService } from '@/domains/recorder/services/subscription.service';
|
import { SubscriptionService } from '@/domains/recorder/services/subscription.service';
|
||||||
import { useInject } from '@/infra/di/inject';
|
import { useInject } from '@/infra/di/inject';
|
||||||
|
import { compatFormDefaultValues } from '@/infra/forms/compat';
|
||||||
import {
|
import {
|
||||||
Credential3rdTypeEnum,
|
Credential3rdTypeEnum,
|
||||||
type InsertSubscriptionMutation,
|
type InsertSubscriptionMutation,
|
||||||
@ -34,11 +39,6 @@ import {
|
|||||||
SubscriptionCategoryEnum,
|
SubscriptionCategoryEnum,
|
||||||
} from '@/infra/graphql/gql/graphql';
|
} from '@/infra/graphql/gql/graphql';
|
||||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||||
import { useMutation } from '@apollo/client';
|
|
||||||
import { createFileRoute } from '@tanstack/react-router';
|
|
||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import { Loader2, Save } from 'lucide-react';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
import { Credential3rdSelectContent } from './-credential3rd-select';
|
import { Credential3rdSelectContent } from './-credential3rd-select';
|
||||||
|
|
||||||
export const Route = createFileRoute('/_app/subscriptions/create')({
|
export const Route = createFileRoute('/_app/subscriptions/create')({
|
||||||
@ -71,22 +71,24 @@ function SubscriptionCreateRouteComponent() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const form = useAppForm({
|
const form = useAppForm({
|
||||||
defaultValues: {
|
defaultValues: compatFormDefaultValues<SubscriptionForm>({
|
||||||
displayName: '',
|
displayName: '',
|
||||||
category: undefined,
|
category: '',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
sourceUrl: '',
|
sourceUrl: '',
|
||||||
credentialId: '',
|
credentialId: Number.NaN,
|
||||||
year: undefined,
|
year: Number.NaN,
|
||||||
seasonStr: '',
|
seasonStr: '',
|
||||||
} as unknown as SubscriptionForm,
|
}),
|
||||||
validators: {
|
validators: {
|
||||||
onChangeAsync: SubscriptionFormSchema,
|
onChangeAsync: SubscriptionFormSchema,
|
||||||
onChangeAsyncDebounceMs: 300,
|
onChangeAsyncDebounceMs: 300,
|
||||||
onSubmit: SubscriptionFormSchema,
|
onSubmit: SubscriptionFormSchema,
|
||||||
},
|
},
|
||||||
onSubmit: async (form) => {
|
onSubmit: async (submittedForm) => {
|
||||||
const input = subscriptionService.transformInsertFormToInput(form.value);
|
const input = subscriptionService.transformInsertFormToInput(
|
||||||
|
submittedForm.value
|
||||||
|
);
|
||||||
await insertSubscription({
|
await insertSubscription({
|
||||||
variables: {
|
variables: {
|
||||||
data: input,
|
data: input,
|
||||||
@ -119,30 +121,6 @@ function SubscriptionCreateRouteComponent() {
|
|||||||
}}
|
}}
|
||||||
className="space-y-6"
|
className="space-y-6"
|
||||||
>
|
>
|
||||||
<form.Field name="displayName">
|
|
||||||
{(field) => (
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label htmlFor={field.name}>Display Name *</Label>
|
|
||||||
<Input
|
|
||||||
id={field.name}
|
|
||||||
name={field.name}
|
|
||||||
value={field.state.value}
|
|
||||||
onBlur={field.handleBlur}
|
|
||||||
onChange={(e) => field.handleChange(e.target.value)}
|
|
||||||
placeholder="Please enter display name"
|
|
||||||
autoComplete="off"
|
|
||||||
/>
|
|
||||||
{field.state.meta.errors && (
|
|
||||||
<FormFieldErrors
|
|
||||||
errors={field.state.meta.errors}
|
|
||||||
isDirty={field.state.meta.isDirty}
|
|
||||||
submissionAttempts={form.state.submissionAttempts}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</form.Field>
|
|
||||||
|
|
||||||
<form.Field name="category">
|
<form.Field name="category">
|
||||||
{(field) => (
|
{(field) => (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@ -192,7 +170,7 @@ function SubscriptionCreateRouteComponent() {
|
|||||||
<Select
|
<Select
|
||||||
value={field.state.value.toString()}
|
value={field.state.value.toString()}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
field.handleChange(Number.parseInt(value))
|
field.handleChange(Number.parseInt(value, 10))
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
@ -227,7 +205,7 @@ function SubscriptionCreateRouteComponent() {
|
|||||||
onBlur={field.handleBlur}
|
onBlur={field.handleBlur}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
field.handleChange(
|
field.handleChange(
|
||||||
Number.parseInt(e.target.value)
|
Number.parseInt(e.target.value, 10)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
placeholder={`Please enter full year (e.g. ${new Date().getFullYear()})`}
|
placeholder={`Please enter full year (e.g. ${new Date().getFullYear()})`}
|
||||||
@ -315,6 +293,29 @@ function SubscriptionCreateRouteComponent() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</form.Subscribe>
|
</form.Subscribe>
|
||||||
|
<form.Field name="displayName">
|
||||||
|
{(field) => (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor={field.name}>Display Name *</Label>
|
||||||
|
<Input
|
||||||
|
id={field.name}
|
||||||
|
name={field.name}
|
||||||
|
value={field.state.value}
|
||||||
|
onBlur={field.handleBlur}
|
||||||
|
onChange={(e) => field.handleChange(e.target.value)}
|
||||||
|
placeholder="Please enter display name"
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
{field.state.meta.errors && (
|
||||||
|
<FormFieldErrors
|
||||||
|
errors={field.state.meta.errors}
|
||||||
|
isDirty={field.state.meta.isDirty}
|
||||||
|
submissionAttempts={form.state.submissionAttempts}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</form.Field>
|
||||||
<form.Field name="enabled">
|
<form.Field name="enabled">
|
||||||
{(field) => (
|
{(field) => (
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
import { useMutation, useQuery } from '@apollo/client';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { Save } from 'lucide-react';
|
||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { toast } from 'sonner';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
@ -36,6 +41,7 @@ import {
|
|||||||
apolloErrorToMessage,
|
apolloErrorToMessage,
|
||||||
getApolloQueryError,
|
getApolloQueryError,
|
||||||
} from '@/infra/errors/apollo';
|
} from '@/infra/errors/apollo';
|
||||||
|
import { compatFormDefaultValues } from '@/infra/forms/compat';
|
||||||
import {
|
import {
|
||||||
Credential3rdTypeEnum,
|
Credential3rdTypeEnum,
|
||||||
type GetSubscriptionDetailQuery,
|
type GetSubscriptionDetailQuery,
|
||||||
@ -44,11 +50,6 @@ import {
|
|||||||
type UpdateSubscriptionsMutationVariables,
|
type UpdateSubscriptionsMutationVariables,
|
||||||
} from '@/infra/graphql/gql/graphql';
|
} from '@/infra/graphql/gql/graphql';
|
||||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||||
import { useMutation, useQuery } from '@apollo/client';
|
|
||||||
import { createFileRoute } from '@tanstack/react-router';
|
|
||||||
import { Save } from 'lucide-react';
|
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
import { Credential3rdSelectContent } from './-credential3rd-select';
|
import { Credential3rdSelectContent } from './-credential3rd-select';
|
||||||
|
|
||||||
export const Route = createFileRoute('/_app/subscriptions/edit/$id')({
|
export const Route = createFileRoute('/_app/subscriptions/edit/$id')({
|
||||||
@ -100,7 +101,9 @@ function FormView({
|
|||||||
category: subscription.category,
|
category: subscription.category,
|
||||||
enabled: subscription.enabled,
|
enabled: subscription.enabled,
|
||||||
sourceUrl: subscription.sourceUrl,
|
sourceUrl: subscription.sourceUrl,
|
||||||
credentialId: subscription.credential3rd?.id || '',
|
credentialId: subscription.credential3rd?.id ?? Number.NaN,
|
||||||
|
year: Number.NaN,
|
||||||
|
seasonStr: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -118,14 +121,16 @@ function FormView({
|
|||||||
}, [subscription, sourceUrlMeta]);
|
}, [subscription, sourceUrlMeta]);
|
||||||
|
|
||||||
const form = useAppForm({
|
const form = useAppForm({
|
||||||
defaultValues: defaultValues as unknown as SubscriptionForm,
|
defaultValues: compatFormDefaultValues<SubscriptionForm>(defaultValues),
|
||||||
validators: {
|
validators: {
|
||||||
onChangeAsync: SubscriptionFormSchema,
|
onChangeAsync: SubscriptionFormSchema,
|
||||||
onChangeAsyncDebounceMs: 300,
|
onChangeAsyncDebounceMs: 300,
|
||||||
onSubmit: SubscriptionFormSchema,
|
onSubmit: SubscriptionFormSchema,
|
||||||
},
|
},
|
||||||
onSubmit: async (form) => {
|
onSubmit: async (submittedForm) => {
|
||||||
const input = subscriptionService.transformInsertFormToInput(form.value);
|
const input = subscriptionService.transformInsertFormToInput(
|
||||||
|
submittedForm.value
|
||||||
|
);
|
||||||
|
|
||||||
await updateSubscription({
|
await updateSubscription({
|
||||||
variables: {
|
variables: {
|
||||||
@ -217,7 +222,7 @@ function FormView({
|
|||||||
<Select
|
<Select
|
||||||
value={field.state.value.toString()}
|
value={field.state.value.toString()}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
field.handleChange(Number.parseInt(value))
|
field.handleChange(Number.parseInt(value, 10))
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
@ -249,7 +254,9 @@ function FormView({
|
|||||||
min={1970}
|
min={1970}
|
||||||
onBlur={field.handleBlur}
|
onBlur={field.handleBlur}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
field.handleChange(Number.parseInt(e.target.value))
|
field.handleChange(
|
||||||
|
Number.parseInt(e.target.value, 10)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
placeholder={`Please enter full year (e.g. ${new Date().getFullYear()})`}
|
placeholder={`Please enter full year (e.g. ${new Date().getFullYear()})`}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@ -359,7 +366,7 @@ function SubscriptionEditRouteComponent() {
|
|||||||
const { loading, error, data, refetch } =
|
const { loading, error, data, refetch } =
|
||||||
useQuery<GetSubscriptionDetailQuery>(GET_SUBSCRIPTION_DETAIL, {
|
useQuery<GetSubscriptionDetailQuery>(GET_SUBSCRIPTION_DETAIL, {
|
||||||
variables: {
|
variables: {
|
||||||
id: Number.parseInt(id),
|
id: Number.parseInt(id, 10),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -367,10 +374,10 @@ function SubscriptionEditRouteComponent() {
|
|||||||
|
|
||||||
const onCompleted = useCallback(async () => {
|
const onCompleted = useCallback(async () => {
|
||||||
const refetchResult = await refetch();
|
const refetchResult = await refetch();
|
||||||
const error = getApolloQueryError(refetchResult);
|
const _error = getApolloQueryError(refetchResult);
|
||||||
if (error) {
|
if (_error) {
|
||||||
toast.error('Update subscription failed', {
|
toast.error('Update subscription failed', {
|
||||||
description: apolloErrorToMessage(error),
|
description: apolloErrorToMessage(_error),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast.success('Update subscription successfully');
|
toast.success('Update subscription successfully');
|
||||||
|
@ -1,9 +1,313 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
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 { CronDisplay } from '@/components/domains/cron';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from '@/components/ui/card';
|
||||||
|
import { ContainerHeader } from '@/components/ui/container-header';
|
||||||
|
import { DetailCardSkeleton } from '@/components/ui/detail-card-skeleton';
|
||||||
|
import { DetailEmptyView } from '@/components/ui/detail-empty-view';
|
||||||
|
import { Label } from '@/components/ui/label';
|
||||||
|
import { QueryErrorView } from '@/components/ui/query-error-view';
|
||||||
|
import { Separator } from '@/components/ui/separator';
|
||||||
|
import { GET_CRONS } from '@/domains/recorder/schema/cron';
|
||||||
|
import {
|
||||||
|
CronStatusEnum,
|
||||||
|
type GetCronsQuery,
|
||||||
|
type GetCronsQueryVariables,
|
||||||
|
} from '@/infra/graphql/gql/graphql';
|
||||||
|
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||||
|
import { getStatusBadge } from './-status-badge';
|
||||||
|
|
||||||
export const Route = createFileRoute('/_app/tasks/cron/detail/$id')({
|
export const Route = createFileRoute('/_app/tasks/cron/detail/$id')({
|
||||||
component: RouteComponent,
|
component: CronDetailRouteComponent,
|
||||||
})
|
staticData: {
|
||||||
|
breadcrumb: { label: 'Detail' },
|
||||||
|
} satisfies RouteStateDataOption,
|
||||||
|
});
|
||||||
|
|
||||||
function RouteComponent() {
|
function CronDetailRouteComponent() {
|
||||||
return <div>Hello "/_app/tasks/cron/detail/$id"!</div>
|
const { id } = Route.useParams();
|
||||||
|
|
||||||
|
const { data, loading, error, refetch } = useQuery<
|
||||||
|
GetCronsQuery,
|
||||||
|
GetCronsQueryVariables
|
||||||
|
>(GET_CRONS, {
|
||||||
|
variables: {
|
||||||
|
filter: {
|
||||||
|
id: {
|
||||||
|
eq: Number.parseInt(id, 10),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
page: {
|
||||||
|
page: 0,
|
||||||
|
limit: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
orderBy: {},
|
||||||
|
},
|
||||||
|
pollInterval: 5000, // Auto-refresh every 5 seconds for running crons
|
||||||
|
});
|
||||||
|
|
||||||
|
const cron = data?.cron?.nodes?.[0];
|
||||||
|
|
||||||
|
const subscriberTaskCron = useMemo(() => {
|
||||||
|
if (!cron) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return cron.subscriberTaskCron;
|
||||||
|
}, [cron]);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <DetailCardSkeleton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <QueryErrorView message={error.message} onRetry={refetch} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cron) {
|
||||||
|
return <DetailEmptyView message="Not found Cron task" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto max-w-4xl py-6">
|
||||||
|
<ContainerHeader
|
||||||
|
title="Cron task detail"
|
||||||
|
description={`View Cron task #${cron.id}`}
|
||||||
|
defaultBackTo="/tasks/cron/manage"
|
||||||
|
actions={
|
||||||
|
<Button variant="outline" size="sm" onClick={() => refetch()}>
|
||||||
|
<RefreshCw className="h-4 w-4" />
|
||||||
|
Refresh
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle>Cron task information</CardTitle>
|
||||||
|
<CardDescription className="mt-2">
|
||||||
|
View Cron task execution details
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{getStatusBadge(cron.status)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-6">
|
||||||
|
{/* Basic Information */}
|
||||||
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Cron ID</Label>
|
||||||
|
<div className="rounded-md bg-muted p-3">
|
||||||
|
<code className="text-sm">{cron.id}</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Priority</Label>
|
||||||
|
<div className="rounded-md bg-muted p-3">
|
||||||
|
<span className="text-sm">{cron.priority}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Retry count</Label>
|
||||||
|
<div className="rounded-md bg-muted p-3">
|
||||||
|
<span className="text-sm">
|
||||||
|
{cron.attempts} / {cron.maxAttempts}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Enabled</Label>
|
||||||
|
<div className="rounded-md bg-muted p-3">
|
||||||
|
<Badge variant={cron.enabled ? 'default' : 'secondary'}>
|
||||||
|
{cron.enabled ? 'Enabled' : 'Disabled'}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Next run time</Label>
|
||||||
|
<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')
|
||||||
|
: '-'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Last run time</Label>
|
||||||
|
<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')
|
||||||
|
: '-'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Locked time</Label>
|
||||||
|
<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')
|
||||||
|
: '-'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Locked by</Label>
|
||||||
|
<div className="rounded-md bg-muted p-3">
|
||||||
|
<code className="text-sm">{cron.lockedBy || '-'}</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Timeout</Label>
|
||||||
|
<div className="rounded-md bg-muted p-3">
|
||||||
|
<span className="text-sm">
|
||||||
|
{cron.timeoutMs ? `${cron.timeoutMs}ms` : 'No limit'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">Created at</Label>
|
||||||
|
<div className="rounded-md bg-muted p-3">
|
||||||
|
<span className="text-sm">
|
||||||
|
{format(new Date(cron.createdAt), 'yyyy-MM-dd HH:mm:ss')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<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')}
|
||||||
|
</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 && (
|
||||||
|
<>
|
||||||
|
<Separator />
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">
|
||||||
|
Subscriber task details
|
||||||
|
</Label>
|
||||||
|
<div className="rounded-md bg-muted p-3">
|
||||||
|
<pre className="overflow-x-auto whitespace-pre-wrap text-sm">
|
||||||
|
<code>
|
||||||
|
{JSON.stringify(subscriberTaskCron, null, 2)}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Related Subscriber Tasks */}
|
||||||
|
{cron.subscriberTask?.nodes &&
|
||||||
|
cron.subscriberTask.nodes.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Separator />
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">
|
||||||
|
Associated tasks
|
||||||
|
</Label>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{cron.subscriberTask.nodes.map((task, index) => (
|
||||||
|
<div
|
||||||
|
key={`${task.id}-${index}`}
|
||||||
|
className="rounded-md border bg-muted/50 p-3"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<code className="text-sm">{task.id}</code>
|
||||||
|
<Badge variant="outline">{task.status}</Badge>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 text-muted-foreground text-sm">
|
||||||
|
Priority: {task.priority} | Retry: {task.attempts}
|
||||||
|
/{task.maxAttempts}
|
||||||
|
</div>
|
||||||
|
{task.subscription && (
|
||||||
|
<div className="mt-1 text-sm">
|
||||||
|
<span className="font-medium">
|
||||||
|
Subscription:
|
||||||
|
</span>{' '}
|
||||||
|
{task.subscription.displayName}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Error Information */}
|
||||||
|
{cron.status === CronStatusEnum.Failed && cron.lastError && (
|
||||||
|
<>
|
||||||
|
<Separator />
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="font-medium text-sm">最后错误</Label>
|
||||||
|
<div className="rounded-md bg-destructive/10 p-3">
|
||||||
|
<p className="text-destructive text-sm">
|
||||||
|
{cron.lastError}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +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 { format } from 'date-fns';
|
||||||
|
import { RefreshCw } from 'lucide-react';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import { toast } from 'sonner';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ContainerHeader } from '@/components/ui/container-header';
|
import { ContainerHeader } from '@/components/ui/container-header';
|
||||||
import { DataTablePagination } from '@/components/ui/data-table-pagination';
|
import { DataTablePagination } from '@/components/ui/data-table-pagination';
|
||||||
import { DetailEmptyView } from '@/components/ui/detail-empty-view';
|
import { DetailEmptyView } from '@/components/ui/detail-empty-view';
|
||||||
import { DropdownMenuItem } from '@/components/ui/dropdown-menu';
|
|
||||||
import { DropdownMenuActions } from '@/components/ui/dropdown-menu-actions';
|
import { DropdownMenuActions } from '@/components/ui/dropdown-menu-actions';
|
||||||
import { QueryErrorView } from '@/components/ui/query-error-view';
|
import { QueryErrorView } from '@/components/ui/query-error-view';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
@ -25,21 +39,6 @@ import {
|
|||||||
} from '@/infra/graphql/gql/graphql';
|
} from '@/infra/graphql/gql/graphql';
|
||||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||||
import { useDebouncedSkeleton } from '@/presentation/hooks/use-debounded-skeleton';
|
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 { useMemo, useState } from 'react';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
import { getStatusBadge } from './-status-badge';
|
import { getStatusBadge } from './-status-badge';
|
||||||
|
|
||||||
export const Route = createFileRoute('/_app/tasks/cron/manage')({
|
export const Route = createFileRoute('/_app/tasks/cron/manage')({
|
||||||
@ -88,18 +87,18 @@ function TaskCronManageRouteComponent() {
|
|||||||
>(DELETE_CRONS, {
|
>(DELETE_CRONS, {
|
||||||
onCompleted: async () => {
|
onCompleted: async () => {
|
||||||
const refetchResult = await refetch();
|
const refetchResult = await refetch();
|
||||||
const error = getApolloQueryError(refetchResult);
|
const errorResult = getApolloQueryError(refetchResult);
|
||||||
if (error) {
|
if (errorResult) {
|
||||||
toast.error('Failed to delete tasks', {
|
toast.error('Failed to delete tasks', {
|
||||||
description: apolloErrorToMessage(error),
|
description: apolloErrorToMessage(errorResult),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
toast.success('Tasks deleted');
|
toast.success('Tasks deleted');
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (mutationError) => {
|
||||||
toast.error('Failed to delete tasks', {
|
toast.error('Failed to delete tasks', {
|
||||||
description: error.message,
|
description: mutationError.message,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -168,16 +167,16 @@ function TaskCronManageRouteComponent() {
|
|||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{showSkeleton &&
|
{showSkeleton &&
|
||||||
Array.from(new Array(10)).map((_, index) => (
|
Array.from(new Array(10)).map((_, index) => (
|
||||||
<Skeleton key={index} className="h-32 w-full" />
|
<Skeleton key={`skeleton-${index}`} className="h-32 w-full" />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{!showSkeleton && table.getRowModel().rows?.length > 0 ? (
|
{!showSkeleton && table.getRowModel().rows?.length > 0 ? (
|
||||||
table.getRowModel().rows.map((row, index) => {
|
table.getRowModel().rows.map((row) => {
|
||||||
const cron = row.original;
|
const cron = row.original;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="space-y-3 rounded-lg border bg-card p-4"
|
className="space-y-3 rounded-lg border bg-card p-4"
|
||||||
key={`${cron.id}-${index}`}
|
key={cron.id}
|
||||||
>
|
>
|
||||||
{/* Header with status and priority */}
|
{/* Header with status and priority */}
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
@ -215,17 +214,7 @@ function TaskCronManageRouteComponent() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
/>
|
||||||
{cron.status === CronStatusEnum.Failed && (
|
|
||||||
<DropdownMenuItem
|
|
||||||
onSelect={() => {
|
|
||||||
// TODO: Retry cron
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Retry
|
|
||||||
</DropdownMenuItem>
|
|
||||||
)}
|
|
||||||
</DropdownMenuActions>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
41
biome.json
41
biome.json
@ -1,27 +1,32 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.1.1/schema.json",
|
||||||
"extends": ["ultracite"],
|
"extends": ["ultracite"],
|
||||||
"javascript": {
|
"javascript": {
|
||||||
"globals": ["Liveblocks"]
|
"globals": ["Liveblocks"]
|
||||||
},
|
},
|
||||||
|
"assist": {
|
||||||
|
"actions": {
|
||||||
|
"source": {
|
||||||
|
"useSortedAttributes": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
"rules": {
|
"rules": {
|
||||||
"nursery": {
|
"nursery": {},
|
||||||
"noEnum": "off"
|
|
||||||
},
|
|
||||||
"style": {
|
"style": {
|
||||||
"noParameterProperties": "off",
|
"noParameterProperties": "off",
|
||||||
"noNonNullAssertion": "off"
|
"noNonNullAssertion": "off",
|
||||||
|
"noEnum": "off"
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
"noDangerouslySetInnerHtml": "off"
|
"noDangerouslySetInnerHtml": "off"
|
||||||
},
|
},
|
||||||
"suspicious": {
|
"suspicious": {
|
||||||
|
"noArrayIndexKey": "off",
|
||||||
"noEmptyBlockStatements": "off",
|
"noEmptyBlockStatements": "off",
|
||||||
"noExplicitAny": "off",
|
"noExplicitAny": "off",
|
||||||
"noConsole": "off",
|
"noConsole": "off"
|
||||||
"noConsoleLog": "off"
|
|
||||||
},
|
},
|
||||||
"a11y": {
|
"a11y": {
|
||||||
"noSvgWithoutTitle": "off"
|
"noSvgWithoutTitle": "off"
|
||||||
@ -45,7 +50,7 @@
|
|||||||
},
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"include": ["**/tsconfig.json", "**/tsconfig.*.json"],
|
"includes": ["**/tsconfig.json", "**/tsconfig.*.json"],
|
||||||
"json": {
|
"json": {
|
||||||
"parser": {
|
"parser": {
|
||||||
"allowComments": true
|
"allowComments": true
|
||||||
@ -53,11 +58,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"include": ["apps/webui/src/infra/graphql/gql/**/*"],
|
"includes": ["**/apps/webui/src/infra/graphql/gql/**/*"],
|
||||||
|
"assist": {
|
||||||
|
"actions": {
|
||||||
|
"source": {
|
||||||
|
"organizeImports": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
"rules": {
|
"rules": {
|
||||||
"style": {
|
"style": {
|
||||||
"useShorthandArrayType": "off",
|
|
||||||
"useConsistentArrayType": "off",
|
"useConsistentArrayType": "off",
|
||||||
"useImportType": "off"
|
"useImportType": "off"
|
||||||
}
|
}
|
||||||
@ -65,7 +76,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"include": ["apps/webui/src/components/ui/**/*"],
|
"includes": ["**/apps/webui/src/components/ui/**/*"],
|
||||||
"javascript": {
|
"javascript": {
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"quoteStyle": "double"
|
"quoteStyle": "double"
|
||||||
@ -75,10 +86,10 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"style": {
|
"style": {
|
||||||
"useBlockStatements": "off",
|
"useBlockStatements": "off",
|
||||||
"useImportType": "off"
|
"useImportType": "off",
|
||||||
|
"noNestedTernary": "off"
|
||||||
},
|
},
|
||||||
"nursery": {
|
"nursery": {
|
||||||
"noNestedTernary": "off",
|
|
||||||
"useSortedClasses": "off"
|
"useSortedClasses": "off"
|
||||||
},
|
},
|
||||||
"a11y": {
|
"a11y": {
|
||||||
@ -94,6 +105,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"files": {
|
"files": {
|
||||||
"ignore": [".vscode/*.json"]
|
"includes": ["**", "!**/.vscode/**/*.json"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
package.json
13
package.json
@ -3,10 +3,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"description": "Kono bangumi?",
|
"description": "Kono bangumi?",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": ["packages/*", "apps/*"],
|
||||||
"packages/*",
|
|
||||||
"apps/*"
|
|
||||||
],
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -18,22 +15,22 @@
|
|||||||
"bump-deps": "npx --yes npm-check-updates --deep -u && pnpm install",
|
"bump-deps": "npx --yes npm-check-updates --deep -u && pnpm install",
|
||||||
"clean": "git clean -xdf node_modules"
|
"clean": "git clean -xdf node_modules"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.12.1",
|
"packageManager": "pnpm@10.12.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=24"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-toolkit": "^1.39.6"
|
"es-toolkit": "^1.39.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "1.9.4",
|
"@biomejs/biome": "2.1.1",
|
||||||
"@types/node": "^24.0.10",
|
"@types/node": "^24.0.10",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"kill-port": "^2.0.1",
|
"kill-port": "^2.0.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"tsx": "^4.20.3",
|
"tsx": "^4.20.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"ultracite": "^4.2.13"
|
"ultracite": "^5.0.32"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
304
pnpm-lock.yaml
generated
304
pnpm-lock.yaml
generated
@ -16,8 +16,8 @@ importers:
|
|||||||
version: 1.39.6
|
version: 1.39.6
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@biomejs/biome':
|
'@biomejs/biome':
|
||||||
specifier: 1.9.4
|
specifier: 2.1.1
|
||||||
version: 1.9.4
|
version: 2.1.1
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^24.0.10
|
specifier: ^24.0.10
|
||||||
version: 24.0.10
|
version: 24.0.10
|
||||||
@ -37,8 +37,8 @@ importers:
|
|||||||
specifier: ^5.8.3
|
specifier: ^5.8.3
|
||||||
version: 5.8.3
|
version: 5.8.3
|
||||||
ultracite:
|
ultracite:
|
||||||
specifier: ^4.2.13
|
specifier: ^5.0.32
|
||||||
version: 4.2.13
|
version: 5.0.32(@types/node@24.0.10)(jsdom@25.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
|
||||||
|
|
||||||
apps/docs: {}
|
apps/docs: {}
|
||||||
|
|
||||||
@ -601,59 +601,65 @@ packages:
|
|||||||
resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
|
resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@biomejs/biome@1.9.4':
|
'@biomejs/biome@2.1.1':
|
||||||
resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==}
|
resolution: {integrity: sha512-HFGYkxG714KzG+8tvtXCJ1t1qXQMzgWzfvQaUjxN6UeKv+KvMEuliInnbZLJm6DXFXwqVi6446EGI0sGBLIYng==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@biomejs/cli-darwin-arm64@1.9.4':
|
'@biomejs/cli-darwin-arm64@2.1.1':
|
||||||
resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==}
|
resolution: {integrity: sha512-2Muinu5ok4tWxq4nu5l19el48cwCY/vzvI7Vjbkf3CYIQkjxZLyj0Ad37Jv2OtlXYaLvv+Sfu1hFeXt/JwRRXQ==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@biomejs/cli-darwin-x64@1.9.4':
|
'@biomejs/cli-darwin-x64@2.1.1':
|
||||||
resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==}
|
resolution: {integrity: sha512-cC8HM5lrgKQXLAK+6Iz2FrYW5A62pAAX6KAnRlEyLb+Q3+Kr6ur/sSuoIacqlp1yvmjHJqjYfZjPvHWnqxoEIA==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@biomejs/cli-linux-arm64-musl@1.9.4':
|
'@biomejs/cli-linux-arm64-musl@2.1.1':
|
||||||
resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==}
|
resolution: {integrity: sha512-/7FBLnTswu4jgV9ttI3AMIdDGqVEPIZd8I5u2D4tfCoj8rl9dnjrEQbAIDlWhUXdyWlFSz8JypH3swU9h9P+2A==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@biomejs/cli-linux-arm64@1.9.4':
|
'@biomejs/cli-linux-arm64@2.1.1':
|
||||||
resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
|
resolution: {integrity: sha512-tw4BEbhAUkWPe4WBr6IX04DJo+2jz5qpPzpW/SWvqMjb9QuHY8+J0M23V8EPY/zWU4IG8Ui0XESapR1CB49Q7g==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64-musl@1.9.4':
|
'@biomejs/cli-linux-x64-musl@2.1.1':
|
||||||
resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
|
resolution: {integrity: sha512-kUu+loNI3OCD2c12cUt7M5yaaSjDnGIksZwKnueubX6c/HWUyi/0mPbTBHR49Me3F0KKjWiKM+ZOjsmC+lUt9g==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64@1.9.4':
|
'@biomejs/cli-linux-x64@2.1.1':
|
||||||
resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
|
resolution: {integrity: sha512-3WJ1GKjU7NzZb6RTbwLB59v9cTIlzjbiFLDB0z4376TkDqoNYilJaC37IomCr/aXwuU8QKkrYoHrgpSq5ffJ4Q==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@biomejs/cli-win32-arm64@1.9.4':
|
'@biomejs/cli-win32-arm64@2.1.1':
|
||||||
resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
|
resolution: {integrity: sha512-vEHK0v0oW+E6RUWLoxb2isI3rZo57OX9ZNyyGH701fZPj6Il0Rn1f5DMNyCmyflMwTnIQstEbs7n2BxYSqQx4Q==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@biomejs/cli-win32-x64@1.9.4':
|
'@biomejs/cli-win32-x64@2.1.1':
|
||||||
resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==}
|
resolution: {integrity: sha512-i2PKdn70kY++KEF/zkQFvQfX1e8SkA8hq4BgC+yE9dZqyLzB/XStY2MvwI3qswlRgnGpgncgqe0QYKVS1blksg==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@clack/core@0.5.0':
|
||||||
|
resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==}
|
||||||
|
|
||||||
|
'@clack/prompts@0.11.0':
|
||||||
|
resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==}
|
||||||
|
|
||||||
'@codemirror/language@6.11.1':
|
'@codemirror/language@6.11.1':
|
||||||
resolution: {integrity: sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==}
|
resolution: {integrity: sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==}
|
||||||
|
|
||||||
@ -3211,6 +3217,9 @@ packages:
|
|||||||
'@vitest/expect@3.2.3':
|
'@vitest/expect@3.2.3':
|
||||||
resolution: {integrity: sha512-W2RH2TPWVHA1o7UmaFKISPvdicFJH+mjykctJFoAkUw+SPTJTGjUNdKscFBrqM7IPnCVu6zihtKYa7TkZS1dkQ==}
|
resolution: {integrity: sha512-W2RH2TPWVHA1o7UmaFKISPvdicFJH+mjykctJFoAkUw+SPTJTGjUNdKscFBrqM7IPnCVu6zihtKYa7TkZS1dkQ==}
|
||||||
|
|
||||||
|
'@vitest/expect@3.2.4':
|
||||||
|
resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
|
||||||
|
|
||||||
'@vitest/mocker@3.2.3':
|
'@vitest/mocker@3.2.3':
|
||||||
resolution: {integrity: sha512-cP6fIun+Zx8he4rbWvi+Oya6goKQDZK+Yq4hhlggwQBbrlOQ4qtZ+G4nxB6ZnzI9lyIb+JnvyiJnPC2AGbKSPA==}
|
resolution: {integrity: sha512-cP6fIun+Zx8he4rbWvi+Oya6goKQDZK+Yq4hhlggwQBbrlOQ4qtZ+G4nxB6ZnzI9lyIb+JnvyiJnPC2AGbKSPA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -3222,21 +3231,47 @@ packages:
|
|||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@vitest/mocker@3.2.4':
|
||||||
|
resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
|
||||||
|
peerDependencies:
|
||||||
|
msw: ^2.4.9
|
||||||
|
vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
msw:
|
||||||
|
optional: true
|
||||||
|
vite:
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@vitest/pretty-format@3.2.3':
|
'@vitest/pretty-format@3.2.3':
|
||||||
resolution: {integrity: sha512-yFglXGkr9hW/yEXngO+IKMhP0jxyFw2/qys/CK4fFUZnSltD+MU7dVYGrH8rvPcK/O6feXQA+EU33gjaBBbAng==}
|
resolution: {integrity: sha512-yFglXGkr9hW/yEXngO+IKMhP0jxyFw2/qys/CK4fFUZnSltD+MU7dVYGrH8rvPcK/O6feXQA+EU33gjaBBbAng==}
|
||||||
|
|
||||||
|
'@vitest/pretty-format@3.2.4':
|
||||||
|
resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
|
||||||
|
|
||||||
'@vitest/runner@3.2.3':
|
'@vitest/runner@3.2.3':
|
||||||
resolution: {integrity: sha512-83HWYisT3IpMaU9LN+VN+/nLHVBCSIUKJzGxC5RWUOsK1h3USg7ojL+UXQR3b4o4UBIWCYdD2fxuzM7PQQ1u8w==}
|
resolution: {integrity: sha512-83HWYisT3IpMaU9LN+VN+/nLHVBCSIUKJzGxC5RWUOsK1h3USg7ojL+UXQR3b4o4UBIWCYdD2fxuzM7PQQ1u8w==}
|
||||||
|
|
||||||
|
'@vitest/runner@3.2.4':
|
||||||
|
resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
|
||||||
|
|
||||||
'@vitest/snapshot@3.2.3':
|
'@vitest/snapshot@3.2.3':
|
||||||
resolution: {integrity: sha512-9gIVWx2+tysDqUmmM1L0hwadyumqssOL1r8KJipwLx5JVYyxvVRfxvMq7DaWbZZsCqZnu/dZedaZQh4iYTtneA==}
|
resolution: {integrity: sha512-9gIVWx2+tysDqUmmM1L0hwadyumqssOL1r8KJipwLx5JVYyxvVRfxvMq7DaWbZZsCqZnu/dZedaZQh4iYTtneA==}
|
||||||
|
|
||||||
|
'@vitest/snapshot@3.2.4':
|
||||||
|
resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
|
||||||
|
|
||||||
'@vitest/spy@3.2.3':
|
'@vitest/spy@3.2.3':
|
||||||
resolution: {integrity: sha512-JHu9Wl+7bf6FEejTCREy+DmgWe+rQKbK+y32C/k5f4TBIAlijhJbRBIRIOCEpVevgRsCQR2iHRUH2/qKVM/plw==}
|
resolution: {integrity: sha512-JHu9Wl+7bf6FEejTCREy+DmgWe+rQKbK+y32C/k5f4TBIAlijhJbRBIRIOCEpVevgRsCQR2iHRUH2/qKVM/plw==}
|
||||||
|
|
||||||
|
'@vitest/spy@3.2.4':
|
||||||
|
resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
|
||||||
|
|
||||||
'@vitest/utils@3.2.3':
|
'@vitest/utils@3.2.3':
|
||||||
resolution: {integrity: sha512-4zFBCU5Pf+4Z6v+rwnZ1HU1yzOKKvDkMXZrymE2PBlbjKJRlrOxbvpfPSvJTGRIwGoahaOGvp+kbCoxifhzJ1Q==}
|
resolution: {integrity: sha512-4zFBCU5Pf+4Z6v+rwnZ1HU1yzOKKvDkMXZrymE2PBlbjKJRlrOxbvpfPSvJTGRIwGoahaOGvp+kbCoxifhzJ1Q==}
|
||||||
|
|
||||||
|
'@vitest/utils@3.2.4':
|
||||||
|
resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
|
||||||
|
|
||||||
'@webassemblyjs/ast@1.14.1':
|
'@webassemblyjs/ast@1.14.1':
|
||||||
resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==}
|
resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==}
|
||||||
|
|
||||||
@ -4876,6 +4911,9 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
jsonc-parser@3.3.1:
|
||||||
|
resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==}
|
||||||
|
|
||||||
jsonfile@2.4.0:
|
jsonfile@2.4.0:
|
||||||
resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==}
|
resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==}
|
||||||
|
|
||||||
@ -5002,6 +5040,9 @@ packages:
|
|||||||
loupe@3.1.3:
|
loupe@3.1.3:
|
||||||
resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
|
resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
|
||||||
|
|
||||||
|
loupe@3.1.4:
|
||||||
|
resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==}
|
||||||
|
|
||||||
lower-case-first@2.0.2:
|
lower-case-first@2.0.2:
|
||||||
resolution: {integrity: sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==}
|
resolution: {integrity: sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==}
|
||||||
|
|
||||||
@ -5952,6 +5993,9 @@ packages:
|
|||||||
simple-swizzle@0.2.2:
|
simple-swizzle@0.2.2:
|
||||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||||
|
|
||||||
|
sisteransi@1.0.5:
|
||||||
|
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||||
|
|
||||||
slash@3.0.0:
|
slash@3.0.0:
|
||||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -6260,6 +6304,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==}
|
resolution: {integrity: sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
|
|
||||||
|
tinypool@1.1.1:
|
||||||
|
resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
|
||||||
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
|
|
||||||
tinyrainbow@2.0.0:
|
tinyrainbow@2.0.0:
|
||||||
resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
|
resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -6384,8 +6432,8 @@ packages:
|
|||||||
uc.micro@2.1.0:
|
uc.micro@2.1.0:
|
||||||
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
|
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
|
||||||
|
|
||||||
ultracite@4.2.13:
|
ultracite@5.0.32:
|
||||||
resolution: {integrity: sha512-j49R1z3xXIPhdvU19x0z0Z4hNewJYn4F1h42ULeaCOylBuxwGVE401piPxe3aVapwue7+Ec3J6wnL/+mW4zwww==}
|
resolution: {integrity: sha512-JjVNswL1mkIaOkPVh1nuEGnbEaCa94+ftqJ9hpRX2Y+jt72pcv32JeWg3Dqhkz/e3l449f7KAzMHO4x6IbxFZQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
unbox-primitive@1.1.0:
|
unbox-primitive@1.1.0:
|
||||||
@ -6492,6 +6540,11 @@ packages:
|
|||||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
vite-node@3.2.4:
|
||||||
|
resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
|
||||||
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
vite@5.4.11:
|
vite@5.4.11:
|
||||||
resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==}
|
resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
@ -6551,6 +6604,34 @@ packages:
|
|||||||
jsdom:
|
jsdom:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
vitest@3.2.4:
|
||||||
|
resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
|
||||||
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@edge-runtime/vm': '*'
|
||||||
|
'@types/debug': ^4.1.12
|
||||||
|
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
|
||||||
|
'@vitest/browser': 3.2.4
|
||||||
|
'@vitest/ui': 3.2.4
|
||||||
|
happy-dom: '*'
|
||||||
|
jsdom: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@edge-runtime/vm':
|
||||||
|
optional: true
|
||||||
|
'@types/debug':
|
||||||
|
optional: true
|
||||||
|
'@types/node':
|
||||||
|
optional: true
|
||||||
|
'@vitest/browser':
|
||||||
|
optional: true
|
||||||
|
'@vitest/ui':
|
||||||
|
optional: true
|
||||||
|
happy-dom:
|
||||||
|
optional: true
|
||||||
|
jsdom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
vscode-languageserver-types@3.17.5:
|
vscode-languageserver-types@3.17.5:
|
||||||
resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==}
|
resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==}
|
||||||
|
|
||||||
@ -7133,41 +7214,52 @@ snapshots:
|
|||||||
'@babel/helper-string-parser': 7.27.1
|
'@babel/helper-string-parser': 7.27.1
|
||||||
'@babel/helper-validator-identifier': 7.27.1
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
|
|
||||||
'@biomejs/biome@1.9.4':
|
'@biomejs/biome@2.1.1':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@biomejs/cli-darwin-arm64': 1.9.4
|
'@biomejs/cli-darwin-arm64': 2.1.1
|
||||||
'@biomejs/cli-darwin-x64': 1.9.4
|
'@biomejs/cli-darwin-x64': 2.1.1
|
||||||
'@biomejs/cli-linux-arm64': 1.9.4
|
'@biomejs/cli-linux-arm64': 2.1.1
|
||||||
'@biomejs/cli-linux-arm64-musl': 1.9.4
|
'@biomejs/cli-linux-arm64-musl': 2.1.1
|
||||||
'@biomejs/cli-linux-x64': 1.9.4
|
'@biomejs/cli-linux-x64': 2.1.1
|
||||||
'@biomejs/cli-linux-x64-musl': 1.9.4
|
'@biomejs/cli-linux-x64-musl': 2.1.1
|
||||||
'@biomejs/cli-win32-arm64': 1.9.4
|
'@biomejs/cli-win32-arm64': 2.1.1
|
||||||
'@biomejs/cli-win32-x64': 1.9.4
|
'@biomejs/cli-win32-x64': 2.1.1
|
||||||
|
|
||||||
'@biomejs/cli-darwin-arm64@1.9.4':
|
'@biomejs/cli-darwin-arm64@2.1.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-darwin-x64@1.9.4':
|
'@biomejs/cli-darwin-x64@2.1.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-linux-arm64-musl@1.9.4':
|
'@biomejs/cli-linux-arm64-musl@2.1.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-linux-arm64@1.9.4':
|
'@biomejs/cli-linux-arm64@2.1.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64-musl@1.9.4':
|
'@biomejs/cli-linux-x64-musl@2.1.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64@1.9.4':
|
'@biomejs/cli-linux-x64@2.1.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-win32-arm64@1.9.4':
|
'@biomejs/cli-win32-arm64@2.1.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@biomejs/cli-win32-x64@1.9.4':
|
'@biomejs/cli-win32-x64@2.1.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@clack/core@0.5.0':
|
||||||
|
dependencies:
|
||||||
|
picocolors: 1.1.1
|
||||||
|
sisteransi: 1.0.5
|
||||||
|
|
||||||
|
'@clack/prompts@0.11.0':
|
||||||
|
dependencies:
|
||||||
|
'@clack/core': 0.5.0
|
||||||
|
picocolors: 1.1.1
|
||||||
|
sisteransi: 1.0.5
|
||||||
|
|
||||||
'@codemirror/language@6.11.1':
|
'@codemirror/language@6.11.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@codemirror/state': 6.5.2
|
'@codemirror/state': 6.5.2
|
||||||
@ -9898,6 +9990,14 @@ snapshots:
|
|||||||
chai: 5.2.0
|
chai: 5.2.0
|
||||||
tinyrainbow: 2.0.0
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
|
'@vitest/expect@3.2.4':
|
||||||
|
dependencies:
|
||||||
|
'@types/chai': 5.2.2
|
||||||
|
'@vitest/spy': 3.2.4
|
||||||
|
'@vitest/utils': 3.2.4
|
||||||
|
chai: 5.2.0
|
||||||
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
'@vitest/mocker@3.2.3(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1))':
|
'@vitest/mocker@3.2.3(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 3.2.3
|
'@vitest/spy': 3.2.3
|
||||||
@ -9906,32 +10006,66 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
|
vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
|
||||||
|
|
||||||
|
'@vitest/mocker@3.2.4(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1))':
|
||||||
|
dependencies:
|
||||||
|
'@vitest/spy': 3.2.4
|
||||||
|
estree-walker: 3.0.3
|
||||||
|
magic-string: 0.30.17
|
||||||
|
optionalDependencies:
|
||||||
|
vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
|
||||||
|
|
||||||
'@vitest/pretty-format@3.2.3':
|
'@vitest/pretty-format@3.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
tinyrainbow: 2.0.0
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
|
'@vitest/pretty-format@3.2.4':
|
||||||
|
dependencies:
|
||||||
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
'@vitest/runner@3.2.3':
|
'@vitest/runner@3.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/utils': 3.2.3
|
'@vitest/utils': 3.2.3
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
strip-literal: 3.0.0
|
strip-literal: 3.0.0
|
||||||
|
|
||||||
|
'@vitest/runner@3.2.4':
|
||||||
|
dependencies:
|
||||||
|
'@vitest/utils': 3.2.4
|
||||||
|
pathe: 2.0.3
|
||||||
|
strip-literal: 3.0.0
|
||||||
|
|
||||||
'@vitest/snapshot@3.2.3':
|
'@vitest/snapshot@3.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/pretty-format': 3.2.3
|
'@vitest/pretty-format': 3.2.3
|
||||||
magic-string: 0.30.17
|
magic-string: 0.30.17
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
|
|
||||||
|
'@vitest/snapshot@3.2.4':
|
||||||
|
dependencies:
|
||||||
|
'@vitest/pretty-format': 3.2.4
|
||||||
|
magic-string: 0.30.17
|
||||||
|
pathe: 2.0.3
|
||||||
|
|
||||||
'@vitest/spy@3.2.3':
|
'@vitest/spy@3.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
tinyspy: 4.0.3
|
tinyspy: 4.0.3
|
||||||
|
|
||||||
|
'@vitest/spy@3.2.4':
|
||||||
|
dependencies:
|
||||||
|
tinyspy: 4.0.3
|
||||||
|
|
||||||
'@vitest/utils@3.2.3':
|
'@vitest/utils@3.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/pretty-format': 3.2.3
|
'@vitest/pretty-format': 3.2.3
|
||||||
loupe: 3.1.3
|
loupe: 3.1.3
|
||||||
tinyrainbow: 2.0.0
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
|
'@vitest/utils@3.2.4':
|
||||||
|
dependencies:
|
||||||
|
'@vitest/pretty-format': 3.2.4
|
||||||
|
loupe: 3.1.4
|
||||||
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
'@webassemblyjs/ast@1.14.1':
|
'@webassemblyjs/ast@1.14.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@webassemblyjs/helper-numbers': 1.13.2
|
'@webassemblyjs/helper-numbers': 1.13.2
|
||||||
@ -11790,6 +11924,8 @@ snapshots:
|
|||||||
|
|
||||||
json5@2.2.3: {}
|
json5@2.2.3: {}
|
||||||
|
|
||||||
|
jsonc-parser@3.3.1: {}
|
||||||
|
|
||||||
jsonfile@2.4.0:
|
jsonfile@2.4.0:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
@ -11907,6 +12043,8 @@ snapshots:
|
|||||||
|
|
||||||
loupe@3.1.3: {}
|
loupe@3.1.3: {}
|
||||||
|
|
||||||
|
loupe@3.1.4: {}
|
||||||
|
|
||||||
lower-case-first@2.0.2:
|
lower-case-first@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
@ -12943,6 +13081,8 @@ snapshots:
|
|||||||
is-arrayish: 0.3.2
|
is-arrayish: 0.3.2
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
sisteransi@1.0.5: {}
|
||||||
|
|
||||||
slash@3.0.0: {}
|
slash@3.0.0: {}
|
||||||
|
|
||||||
slice-ansi@3.0.0:
|
slice-ansi@3.0.0:
|
||||||
@ -13264,6 +13404,8 @@ snapshots:
|
|||||||
|
|
||||||
tinypool@1.1.0: {}
|
tinypool@1.1.0: {}
|
||||||
|
|
||||||
|
tinypool@1.1.1: {}
|
||||||
|
|
||||||
tinyrainbow@2.0.0: {}
|
tinyrainbow@2.0.0: {}
|
||||||
|
|
||||||
tinyspy@4.0.3: {}
|
tinyspy@4.0.3: {}
|
||||||
@ -13390,9 +13532,30 @@ snapshots:
|
|||||||
|
|
||||||
uc.micro@2.1.0: {}
|
uc.micro@2.1.0: {}
|
||||||
|
|
||||||
ultracite@4.2.13:
|
ultracite@5.0.32(@types/node@24.0.10)(jsdom@25.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@clack/prompts': 0.11.0
|
||||||
commander: 14.0.0
|
commander: 14.0.0
|
||||||
|
deepmerge: 4.3.1
|
||||||
|
jsonc-parser: 3.3.1
|
||||||
|
vitest: 3.2.4(@types/node@24.0.10)(jsdom@25.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@edge-runtime/vm'
|
||||||
|
- '@types/debug'
|
||||||
|
- '@types/node'
|
||||||
|
- '@vitest/browser'
|
||||||
|
- '@vitest/ui'
|
||||||
|
- happy-dom
|
||||||
|
- jsdom
|
||||||
|
- less
|
||||||
|
- lightningcss
|
||||||
|
- msw
|
||||||
|
- sass
|
||||||
|
- sass-embedded
|
||||||
|
- stylus
|
||||||
|
- sugarss
|
||||||
|
- supports-color
|
||||||
|
- terser
|
||||||
|
|
||||||
unbox-primitive@1.1.0:
|
unbox-primitive@1.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -13527,6 +13690,24 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- terser
|
- terser
|
||||||
|
|
||||||
|
vite-node@3.2.4(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1):
|
||||||
|
dependencies:
|
||||||
|
cac: 6.7.14
|
||||||
|
debug: 4.4.1
|
||||||
|
es-module-lexer: 1.7.0
|
||||||
|
pathe: 2.0.3
|
||||||
|
vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/node'
|
||||||
|
- less
|
||||||
|
- lightningcss
|
||||||
|
- sass
|
||||||
|
- sass-embedded
|
||||||
|
- stylus
|
||||||
|
- sugarss
|
||||||
|
- supports-color
|
||||||
|
- terser
|
||||||
|
|
||||||
vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1):
|
vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.21.5
|
esbuild: 0.21.5
|
||||||
@ -13578,6 +13759,45 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- terser
|
- terser
|
||||||
|
|
||||||
|
vitest@3.2.4(@types/node@24.0.10)(jsdom@25.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1):
|
||||||
|
dependencies:
|
||||||
|
'@types/chai': 5.2.2
|
||||||
|
'@vitest/expect': 3.2.4
|
||||||
|
'@vitest/mocker': 3.2.4(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1))
|
||||||
|
'@vitest/pretty-format': 3.2.4
|
||||||
|
'@vitest/runner': 3.2.4
|
||||||
|
'@vitest/snapshot': 3.2.4
|
||||||
|
'@vitest/spy': 3.2.4
|
||||||
|
'@vitest/utils': 3.2.4
|
||||||
|
chai: 5.2.0
|
||||||
|
debug: 4.4.1
|
||||||
|
expect-type: 1.2.1
|
||||||
|
magic-string: 0.30.17
|
||||||
|
pathe: 2.0.3
|
||||||
|
picomatch: 4.0.2
|
||||||
|
std-env: 3.9.0
|
||||||
|
tinybench: 2.9.0
|
||||||
|
tinyexec: 0.3.2
|
||||||
|
tinyglobby: 0.2.14
|
||||||
|
tinypool: 1.1.1
|
||||||
|
tinyrainbow: 2.0.0
|
||||||
|
vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
|
||||||
|
vite-node: 3.2.4(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
|
||||||
|
why-is-node-running: 2.3.0
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/node': 24.0.10
|
||||||
|
jsdom: 25.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- less
|
||||||
|
- lightningcss
|
||||||
|
- msw
|
||||||
|
- sass
|
||||||
|
- sass-embedded
|
||||||
|
- stylus
|
||||||
|
- sugarss
|
||||||
|
- supports-color
|
||||||
|
- terser
|
||||||
|
|
||||||
vscode-languageserver-types@3.17.5: {}
|
vscode-languageserver-types@3.17.5: {}
|
||||||
|
|
||||||
w3c-keyname@2.2.8: {}
|
w3c-keyname@2.2.8: {}
|
||||||
|
Loading…
Reference in New Issue
Block a user