🐛 fix(api): Update subscription_protocol to subscribe_type for consistency across services
This commit is contained in:
parent
9d8b814212
commit
b6da51b618
@ -42,7 +42,7 @@ import { z } from 'zod';
|
|||||||
const platforms = ['windows', 'macos', 'linux', 'android', 'ios', 'harmony'];
|
const platforms = ['windows', 'macos', 'linux', 'android', 'ios', 'harmony'];
|
||||||
|
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
subscription_protocol: 'Clash',
|
subscribe_type: 'Clash',
|
||||||
name: '',
|
name: '',
|
||||||
icon: '',
|
icon: '',
|
||||||
url: '',
|
url: '',
|
||||||
@ -58,7 +58,7 @@ const versionSchema = z.object({
|
|||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
icon: z.string(),
|
icon: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
subscription_protocol: z.string(),
|
subscribe_type: z.string(),
|
||||||
platform: z.object({
|
platform: z.object({
|
||||||
windows: z.array(versionSchema).optional(),
|
windows: z.array(versionSchema).optional(),
|
||||||
macos: z.array(versionSchema).optional(),
|
macos: z.array(versionSchema).optional(),
|
||||||
@ -172,7 +172,7 @@ export default function SubscribeAppForm<
|
|||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name='subscription_protocol'
|
name='subscribe_type'
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('subscriptionProtocol')}</FormLabel>
|
<FormLabel>{t('subscriptionProtocol')}</FormLabel>
|
||||||
|
|||||||
@ -76,9 +76,9 @@ export default function SubscribeApp() {
|
|||||||
header: t('appName'),
|
header: t('appName'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'subscription_protocol',
|
accessorKey: 'subscribe_type',
|
||||||
header: t('subscriptionProtocol'),
|
header: t('subscriptionProtocol'),
|
||||||
cell: ({ row }) => row.getValue('subscription_protocol'),
|
cell: ({ row }) => row.getValue('subscribe_type'),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
actions={{
|
actions={{
|
||||||
|
|||||||
2
apps/admin/services/admin/typings.d.ts
vendored
2
apps/admin/services/admin/typings.d.ts
vendored
@ -50,7 +50,7 @@ declare namespace API {
|
|||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
description: string;
|
description: string;
|
||||||
subscription_protocol: string;
|
subscribe_type: string;
|
||||||
platform: ApplicationPlatform;
|
platform: ApplicationPlatform;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
2
apps/admin/services/common/typings.d.ts
vendored
2
apps/admin/services/common/typings.d.ts
vendored
@ -42,7 +42,7 @@ declare namespace API {
|
|||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
description: string;
|
description: string;
|
||||||
subscription_protocol: string;
|
subscribe_type: string;
|
||||||
platform: ApplicationPlatform;
|
platform: ApplicationPlatform;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,15 @@ import CopyToClipboard from 'react-copy-to-clipboard';
|
|||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import Subscribe from '../subscribe/page';
|
import Subscribe from '../subscribe/page';
|
||||||
|
|
||||||
|
const platforms: (keyof API.ApplicationPlatform)[] = [
|
||||||
|
'windows',
|
||||||
|
'mac',
|
||||||
|
'linux',
|
||||||
|
'ios',
|
||||||
|
'android',
|
||||||
|
'harmony',
|
||||||
|
];
|
||||||
|
|
||||||
export default function Content() {
|
export default function Content() {
|
||||||
const t = useTranslations('dashboard');
|
const t = useTranslations('dashboard');
|
||||||
const { getUserSubscribe, getAppSubLink } = useGlobalStore();
|
const { getUserSubscribe, getAppSubLink } = useGlobalStore();
|
||||||
@ -56,14 +65,14 @@ export default function Content() {
|
|||||||
return data.data?.list || [];
|
return data.data?.list || [];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { data: application } = useQuery({
|
const { data: applications } = useQuery({
|
||||||
queryKey: ['queryApplicationConfig'],
|
queryKey: ['queryApplicationConfig'],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await queryApplicationConfig();
|
const { data } = await queryApplicationConfig();
|
||||||
return data.data as API.ApplicationResponse;
|
return data.data?.applications || [];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const [platform, setPlatform] = useState<keyof API.ApplicationResponse>(getPlatform());
|
const [platform, setPlatform] = useState<keyof API.ApplicationPlatform>(getPlatform());
|
||||||
|
|
||||||
const { data } = useQuery({
|
const { data } = useQuery({
|
||||||
queryKey: ['getStat'],
|
queryKey: ['getStat'],
|
||||||
@ -87,16 +96,27 @@ export default function Content() {
|
|||||||
<div className='flex flex-wrap justify-between gap-4'>
|
<div className='flex flex-wrap justify-between gap-4'>
|
||||||
<Tabs
|
<Tabs
|
||||||
value={platform}
|
value={platform}
|
||||||
onValueChange={(value) => setPlatform(value as keyof API.ApplicationResponse)}
|
onValueChange={(value) => setPlatform(value as keyof API.ApplicationPlatform)}
|
||||||
className='w-full max-w-full md:w-auto'
|
className='w-full max-w-full md:w-auto'
|
||||||
>
|
>
|
||||||
<TabsList className='flex *:flex-auto'>
|
<TabsList className='flex *:flex-auto'>
|
||||||
{application &&
|
{platforms.map((item) => (
|
||||||
Object.keys(application)?.map((item) => (
|
<TabsTrigger value={item} key={item} className='px-1 lg:px-3'>
|
||||||
<TabsTrigger value={item} key={item} className='px-1 uppercase lg:px-3'>
|
<Icon
|
||||||
{item}
|
icon={`${
|
||||||
</TabsTrigger>
|
{
|
||||||
))}
|
windows: 'simple-icons:windows',
|
||||||
|
mac: 'simple-icons:apple',
|
||||||
|
linux: 'simple-icons:linux',
|
||||||
|
ios: 'simple-icons:ios',
|
||||||
|
android: 'simple-icons:android',
|
||||||
|
harmony: 'simple-icons:harmonyos',
|
||||||
|
}[item]
|
||||||
|
}`}
|
||||||
|
className='size-6'
|
||||||
|
/>
|
||||||
|
</TabsTrigger>
|
||||||
|
))}
|
||||||
</TabsList>
|
</TabsList>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{data?.protocol && data?.protocol.length > 1 && (
|
{data?.protocol && data?.protocol.length > 1 && (
|
||||||
@ -215,54 +235,69 @@ export default function Content() {
|
|||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
<AccordionContent>
|
<AccordionContent>
|
||||||
<div className='grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6'>
|
<div className='grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6'>
|
||||||
{application?.[platform]?.map((app) => (
|
{applications
|
||||||
<div
|
?.filter((application) => {
|
||||||
key={app.name}
|
const platformApps = application.platform?.[platform];
|
||||||
className='text-muted-foreground flex size-full flex-col items-center justify-between gap-2 text-xs'
|
return platformApps && platformApps.length > 0;
|
||||||
>
|
})
|
||||||
<span>{app.name}</span>
|
.map((application) => {
|
||||||
{app.icon && (
|
const platformApps = application.platform?.[platform];
|
||||||
<Image
|
const app =
|
||||||
src={app.icon}
|
platformApps?.find((item) => item.is_default) || platformApps?.[0];
|
||||||
alt={app.name}
|
if (!app) return null;
|
||||||
width={64}
|
const handleCopy = (text: string, result: boolean) => {
|
||||||
height={64}
|
const href = getAppSubLink(application.subscribe_type, url);
|
||||||
className='p-1'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<div className='flex'>
|
|
||||||
<Button
|
|
||||||
size='sm'
|
|
||||||
variant='secondary'
|
|
||||||
className='rounded-r-none px-1.5'
|
|
||||||
asChild
|
|
||||||
>
|
|
||||||
<Link href={app.url}>{t('download')}</Link>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<CopyToClipboard
|
if (isBrowser() && href) {
|
||||||
text={url}
|
window.location.href = href;
|
||||||
onCopy={(text, result) => {
|
return;
|
||||||
const href = getAppSubLink(app.subscribe_type, url);
|
}
|
||||||
if (isBrowser() && href) {
|
|
||||||
window.location.href = href;
|
if (result) {
|
||||||
} else if (result) {
|
toast.success(
|
||||||
toast.success(
|
<>
|
||||||
<>
|
<p>{t('copySuccess')}</p>
|
||||||
<p>{t('copySuccess')}</p>
|
<p>{t('manualImportMessage')}</p>
|
||||||
<p>{t('manualImportMessage')}</p>
|
</>,
|
||||||
</>,
|
);
|
||||||
);
|
}
|
||||||
}
|
};
|
||||||
}}
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={application.name}
|
||||||
|
className='text-muted-foreground flex size-full flex-col items-center justify-between gap-2 text-xs'
|
||||||
>
|
>
|
||||||
<Button size='sm' className='rounded-l-none p-2'>
|
<span>{application.name}</span>
|
||||||
{t('import')}
|
|
||||||
</Button>
|
{application.icon && (
|
||||||
</CopyToClipboard>
|
<Image
|
||||||
</div>
|
src={application.icon}
|
||||||
</div>
|
alt={application.name}
|
||||||
))}
|
width={64}
|
||||||
|
height={64}
|
||||||
|
className='p-1'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className='flex'>
|
||||||
|
<Button
|
||||||
|
size='sm'
|
||||||
|
variant='secondary'
|
||||||
|
className='rounded-r-none px-1.5'
|
||||||
|
asChild
|
||||||
|
>
|
||||||
|
<Link href={app.url}>{t('download')}</Link>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<CopyToClipboard text={url} onCopy={handleCopy}>
|
||||||
|
<Button size='sm' className='rounded-l-none p-2'>
|
||||||
|
{t('import')}
|
||||||
|
</Button>
|
||||||
|
</CopyToClipboard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
<div className='text-muted-foreground hidden size-full flex-col items-center justify-between gap-2 text-sm lg:flex'>
|
<div className='text-muted-foreground hidden size-full flex-col items-center justify-between gap-2 text-sm lg:flex'>
|
||||||
<span>{t('qrCode')}</span>
|
<span>{t('qrCode')}</span>
|
||||||
<QRCodeCanvas
|
<QRCodeCanvas
|
||||||
|
|||||||
2
apps/user/services/common/typings.d.ts
vendored
2
apps/user/services/common/typings.d.ts
vendored
@ -42,7 +42,7 @@ declare namespace API {
|
|||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
description: string;
|
description: string;
|
||||||
subscription_protocol: string;
|
subscribe_type: string;
|
||||||
platform: ApplicationPlatform;
|
platform: ApplicationPlatform;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
2
apps/user/services/user/typings.d.ts
vendored
2
apps/user/services/user/typings.d.ts
vendored
@ -42,7 +42,7 @@ declare namespace API {
|
|||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
description: string;
|
description: string;
|
||||||
subscription_protocol: string;
|
subscribe_type: string;
|
||||||
platform: ApplicationPlatform;
|
platform: ApplicationPlatform;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export function Logout() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPlatform(): 'windows' | 'mac' | 'linux' | 'android' | 'ios' {
|
export function getPlatform(): 'windows' | 'mac' | 'linux' | 'android' | 'ios' | 'harmony' {
|
||||||
const parser = new UAParser();
|
const parser = new UAParser();
|
||||||
const os = parser.getOS();
|
const os = parser.getOS();
|
||||||
const osName = os.name?.toLowerCase() || '';
|
const osName = os.name?.toLowerCase() || '';
|
||||||
@ -70,6 +70,7 @@ export function getPlatform(): 'windows' | 'mac' | 'linux' | 'android' | 'ios' {
|
|||||||
return 'linux';
|
return 'linux';
|
||||||
if (osName.includes('android')) return 'android';
|
if (osName.includes('android')) return 'android';
|
||||||
if (osName.includes('ios')) return 'ios';
|
if (osName.includes('ios')) return 'ios';
|
||||||
|
if (osName.includes('harmony')) return 'harmony';
|
||||||
|
|
||||||
return 'windows';
|
return 'windows';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
"@hookform/resolvers": "^3.10.0",
|
"@hookform/resolvers": "^3.10.0",
|
||||||
"@iconify-json/flagpack": "^1.2.2",
|
"@iconify-json/flagpack": "^1.2.2",
|
||||||
"@iconify-json/mdi": "^1.2.2",
|
"@iconify-json/mdi": "^1.2.2",
|
||||||
|
"@iconify-json/simple-icons": "^1.2.20",
|
||||||
"@iconify-json/uil": "^1.2.3",
|
"@iconify-json/uil": "^1.2.3",
|
||||||
"@iconify/react": "^5.2.0",
|
"@iconify/react": "^5.2.0",
|
||||||
"@monaco-editor/react": "^4.6.0",
|
"@monaco-editor/react": "^4.6.0",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Button } from '@workspace/ui/components/button';
|
import { Button } from '@workspace/ui/components/button';
|
||||||
import { Label } from '@workspace/ui/components/label.js';
|
import { Label } from '@workspace/ui/components/label';
|
||||||
import { Switch } from '@workspace/ui/components/switch';
|
import { Switch } from '@workspace/ui/components/switch';
|
||||||
import { Combobox } from '@workspace/ui/custom-components/combobox';
|
import { Combobox } from '@workspace/ui/custom-components/combobox';
|
||||||
import { EnhancedInput, EnhancedInputProps } from '@workspace/ui/custom-components/enhanced-input';
|
import { EnhancedInput, EnhancedInputProps } from '@workspace/ui/custom-components/enhanced-input';
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { icons as FlagPack } from '@iconify-json/flagpack';
|
import { icons as FlagPack } from '@iconify-json/flagpack';
|
||||||
import { icons as Mdi } from '@iconify-json/mdi';
|
import { icons as Mdi } from '@iconify-json/mdi';
|
||||||
|
import { icons as Simple } from '@iconify-json/simple-icons';
|
||||||
import { icons as Uil } from '@iconify-json/uil';
|
import { icons as Uil } from '@iconify-json/uil';
|
||||||
|
|
||||||
import { addCollection, Icon as Iconify, IconProps } from '@iconify/react';
|
import { addCollection, Icon as Iconify, IconProps } from '@iconify/react';
|
||||||
@ -9,6 +10,7 @@ import { addCollection, Icon as Iconify, IconProps } from '@iconify/react';
|
|||||||
addCollection(FlagPack);
|
addCollection(FlagPack);
|
||||||
addCollection(Mdi);
|
addCollection(Mdi);
|
||||||
addCollection(Uil);
|
addCollection(Uil);
|
||||||
|
addCollection(Simple);
|
||||||
|
|
||||||
export function Icon(props: IconProps) {
|
export function Icon(props: IconProps) {
|
||||||
return <Iconify {...props} />;
|
return <Iconify {...props} />;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user