Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2bfee1f31 | |||
| 32fd181b52 | |||
| 5816dd5198 | |||
| 92665293ec |
@@ -1,6 +1,15 @@
|
|||||||
<a name="readme-top"></a>
|
<a name="readme-top"></a>
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.5.2](https://github.com/perfect-panel/ppanel-web/compare/v1.5.1...v1.5.2) (2025-09-29)
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
* Add step attribute to datetime-local inputs for precise time selection in forms ([32fd181](https://github.com/perfect-panel/ppanel-web/commit/32fd181))
|
||||||
|
* Rename 'hysteria2' to 'hysteria' across protocol definitions and schemas for consistency ([5816dd5](https://github.com/perfect-panel/ppanel-web/commit/5816dd5))
|
||||||
|
* Update protocol options in ServerConfig for accuracy and consistency ([9266529](https://github.com/perfect-panel/ppanel-web/commit/9266529))
|
||||||
|
|
||||||
## [1.5.1](https://github.com/perfect-panel/ppanel-web/compare/v1.5.0...v1.5.1) (2025-09-28)
|
## [1.5.1](https://github.com/perfect-panel/ppanel-web/compare/v1.5.0...v1.5.1) (2025-09-28)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -225,6 +225,7 @@ export default function AdsForm<T extends Record<string, any>>({
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<EnhancedInput
|
<EnhancedInput
|
||||||
type='datetime-local'
|
type='datetime-local'
|
||||||
|
step='1'
|
||||||
placeholder={t('form.enterStartTime')}
|
placeholder={t('form.enterStartTime')}
|
||||||
value={field.value ? new Date(field.value).toISOString().slice(0, 16) : ''}
|
value={field.value ? new Date(field.value).toISOString().slice(0, 16) : ''}
|
||||||
min={Number(new Date().toISOString().slice(0, 16))}
|
min={Number(new Date().toISOString().slice(0, 16))}
|
||||||
@@ -253,6 +254,7 @@ export default function AdsForm<T extends Record<string, any>>({
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<EnhancedInput
|
<EnhancedInput
|
||||||
type='datetime-local'
|
type='datetime-local'
|
||||||
|
step='1'
|
||||||
placeholder={t('form.enterEndTime')}
|
placeholder={t('form.enterEndTime')}
|
||||||
value={
|
value={
|
||||||
field.value ? new Date(field.value).toISOString().slice(0, 16) : ''
|
field.value ? new Date(field.value).toISOString().slice(0, 16) : ''
|
||||||
|
|||||||
@@ -366,6 +366,7 @@ export default function EmailBroadcastForm() {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<EnhancedInput
|
<EnhancedInput
|
||||||
type='datetime-local'
|
type='datetime-local'
|
||||||
|
step='1'
|
||||||
disabled={form.watch('scope') === 5} // ScopeSkip
|
disabled={form.watch('scope') === 5} // ScopeSkip
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
@@ -384,6 +385,7 @@ export default function EmailBroadcastForm() {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<EnhancedInput
|
<EnhancedInput
|
||||||
type='datetime-local'
|
type='datetime-local'
|
||||||
|
step='1'
|
||||||
disabled={form.watch('scope') === 5} // ScopeSkip
|
disabled={form.watch('scope') === 5} // ScopeSkip
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
@@ -425,6 +427,7 @@ export default function EmailBroadcastForm() {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<EnhancedInput
|
<EnhancedInput
|
||||||
type='datetime-local'
|
type='datetime-local'
|
||||||
|
step='1'
|
||||||
placeholder={t('leaveEmptyForImmediateSend')}
|
placeholder={t('leaveEmptyForImmediateSend')}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ export default function QuotaBroadcastForm() {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<EnhancedInput
|
<EnhancedInput
|
||||||
type='datetime-local'
|
type='datetime-local'
|
||||||
|
step='1'
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
/>
|
/>
|
||||||
@@ -286,6 +287,7 @@ export default function QuotaBroadcastForm() {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<EnhancedInput
|
<EnhancedInput
|
||||||
type='datetime-local'
|
type='datetime-local'
|
||||||
|
step='1'
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -36,9 +36,13 @@ export type ProtocolName =
|
|||||||
| 'vmess'
|
| 'vmess'
|
||||||
| 'vless'
|
| 'vless'
|
||||||
| 'trojan'
|
| 'trojan'
|
||||||
| 'hysteria2'
|
| 'hysteria'
|
||||||
| 'tuic'
|
| 'tuic'
|
||||||
| 'anytls';
|
| 'anytls'
|
||||||
|
| 'naive'
|
||||||
|
| 'http'
|
||||||
|
| 'socks'
|
||||||
|
| 'mieru';
|
||||||
|
|
||||||
const buildSchema = (t: ReturnType<typeof useTranslations>) =>
|
const buildSchema = (t: ReturnType<typeof useTranslations>) =>
|
||||||
z.object({
|
z.object({
|
||||||
|
|||||||
@@ -79,8 +79,18 @@ export default function DynamicMultiplier() {
|
|||||||
<div className='space-y-4 pt-4'>
|
<div className='space-y-4 pt-4'>
|
||||||
<ArrayInput<API.TimePeriod>
|
<ArrayInput<API.TimePeriod>
|
||||||
fields={[
|
fields={[
|
||||||
{ name: 'start_time', prefix: t('server_config.fields.start_time'), type: 'time' },
|
{
|
||||||
{ name: 'end_time', prefix: t('server_config.fields.end_time'), type: 'time' },
|
name: 'start_time',
|
||||||
|
prefix: t('server_config.fields.start_time'),
|
||||||
|
type: 'time',
|
||||||
|
step: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'end_time',
|
||||||
|
prefix: t('server_config.fields.end_time'),
|
||||||
|
type: 'time',
|
||||||
|
step: '1',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'multiplier',
|
name: 'multiplier',
|
||||||
prefix: t('server_config.fields.multiplier'),
|
prefix: t('server_config.fields.multiplier'),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export const protocols = [
|
|||||||
'vmess',
|
'vmess',
|
||||||
'vless',
|
'vless',
|
||||||
'trojan',
|
'trojan',
|
||||||
'hysteria2',
|
'hysteria',
|
||||||
'tuic',
|
'tuic',
|
||||||
'anytls',
|
'anytls',
|
||||||
'socks',
|
'socks',
|
||||||
@@ -64,7 +64,7 @@ export const SECURITY = {
|
|||||||
vmess: ['none', 'tls'] as const,
|
vmess: ['none', 'tls'] as const,
|
||||||
vless: ['none', 'tls', 'reality'] as const,
|
vless: ['none', 'tls', 'reality'] as const,
|
||||||
trojan: ['tls'] as const,
|
trojan: ['tls'] as const,
|
||||||
hysteria2: ['tls'] as const,
|
hysteria: ['tls'] as const,
|
||||||
tuic: ['tls'] as const,
|
tuic: ['tls'] as const,
|
||||||
anytls: ['tls'] as const,
|
anytls: ['tls'] as const,
|
||||||
naive: ['none', 'tls'] as const,
|
naive: ['none', 'tls'] as const,
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ export function getProtocolDefaultConfig(proto: ProtocolType) {
|
|||||||
cert_dns_env: null,
|
cert_dns_env: null,
|
||||||
ratio: 1,
|
ratio: 1,
|
||||||
} as any;
|
} as any;
|
||||||
case 'hysteria2':
|
case 'hysteria':
|
||||||
return {
|
return {
|
||||||
type: 'hysteria2',
|
type: 'hysteria',
|
||||||
enable: false,
|
enable: false,
|
||||||
port: null,
|
port: null,
|
||||||
hop_ports: null,
|
hop_ports: null,
|
||||||
|
|||||||
@@ -603,7 +603,7 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
|
|||||||
condition: (p) => p.security === 'tls' && p.cert_mode === 'dns',
|
condition: (p) => p.security === 'tls' && p.cert_mode === 'dns',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
hysteria2: [
|
hysteria: [
|
||||||
{
|
{
|
||||||
name: 'ratio',
|
name: 'ratio',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
|||||||
@@ -104,16 +104,16 @@ const trojan = z.object({
|
|||||||
cert_dns_env: nullableString,
|
cert_dns_env: nullableString,
|
||||||
});
|
});
|
||||||
|
|
||||||
const hysteria2 = z.object({
|
const hysteria = z.object({
|
||||||
ratio: nullableRatio,
|
ratio: nullableRatio,
|
||||||
type: z.literal('hysteria2'),
|
type: z.literal('hysteria'),
|
||||||
enable: nullableBool,
|
enable: nullableBool,
|
||||||
hop_ports: nullableString,
|
hop_ports: nullableString,
|
||||||
hop_interval: z.number().nullish(),
|
hop_interval: z.number().nullish(),
|
||||||
obfs_password: nullableString,
|
obfs_password: nullableString,
|
||||||
obfs: z.enum(['none', 'salamander'] as const).nullish(),
|
obfs: z.enum(['none', 'salamander'] as const).nullish(),
|
||||||
port: nullablePort,
|
port: nullablePort,
|
||||||
security: z.enum(SECURITY.hysteria2).nullish(),
|
security: z.enum(SECURITY.hysteria).nullish(),
|
||||||
sni: nullableString,
|
sni: nullableString,
|
||||||
allow_insecure: nullableBool,
|
allow_insecure: nullableBool,
|
||||||
fingerprint: nullableString,
|
fingerprint: nullableString,
|
||||||
@@ -207,7 +207,7 @@ export const protocolApiScheme = z.discriminatedUnion('type', [
|
|||||||
vmess,
|
vmess,
|
||||||
vless,
|
vless,
|
||||||
trojan,
|
trojan,
|
||||||
hysteria2,
|
hysteria,
|
||||||
tuic,
|
tuic,
|
||||||
anytls,
|
anytls,
|
||||||
socks,
|
socks,
|
||||||
|
|||||||
@@ -53,23 +53,6 @@ const dnsConfigSchema = z.object({
|
|||||||
const outboundConfigSchema = z.object({
|
const outboundConfigSchema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
protocol: z.string(),
|
protocol: z.string(),
|
||||||
// z.enum([
|
|
||||||
// 'http',
|
|
||||||
// 'https',
|
|
||||||
// 'socks5',
|
|
||||||
// 'shadowsocks',
|
|
||||||
// 'vmess',
|
|
||||||
// 'vless',
|
|
||||||
// 'trojan',
|
|
||||||
// 'hysteria2',
|
|
||||||
// 'tuic',
|
|
||||||
// 'naive',
|
|
||||||
// 'brook',
|
|
||||||
// 'snell',
|
|
||||||
// 'wireguard',
|
|
||||||
// 'direct',
|
|
||||||
// 'reject',
|
|
||||||
// ]),
|
|
||||||
address: z.string(),
|
address: z.string(),
|
||||||
port: z.number(),
|
port: z.number(),
|
||||||
password: z.string().optional(),
|
password: z.string().optional(),
|
||||||
@@ -401,18 +384,18 @@ export default function ServerConfig() {
|
|||||||
),
|
),
|
||||||
options: [
|
options: [
|
||||||
{ label: 'HTTP', value: 'http' },
|
{ label: 'HTTP', value: 'http' },
|
||||||
{ label: 'HTTPS', value: 'https' },
|
{ label: 'SOCKS', value: 'socks' },
|
||||||
{ label: 'SOCKS5', value: 'socks5' },
|
|
||||||
{ label: 'Shadowsocks', value: 'shadowsocks' },
|
{ label: 'Shadowsocks', value: 'shadowsocks' },
|
||||||
|
{ label: 'Brook', value: 'brook' },
|
||||||
|
{ label: 'Snell', value: 'snell' },
|
||||||
{ label: 'VMess', value: 'vmess' },
|
{ label: 'VMess', value: 'vmess' },
|
||||||
{ label: 'VLESS', value: 'vless' },
|
{ label: 'VLESS', value: 'vless' },
|
||||||
{ label: 'Trojan', value: 'trojan' },
|
{ label: 'Trojan', value: 'trojan' },
|
||||||
{ label: 'Hysteria2', value: 'hysteria2' },
|
|
||||||
{ label: 'TUIC', value: 'tuic' },
|
|
||||||
{ label: 'NaiveProxy', value: 'naive' },
|
|
||||||
{ label: 'Brook', value: 'brook' },
|
|
||||||
{ label: 'Snell', value: 'snell' },
|
|
||||||
{ label: 'WireGuard', value: 'wireguard' },
|
{ label: 'WireGuard', value: 'wireguard' },
|
||||||
|
{ label: 'Hysteria', value: 'hysteria' },
|
||||||
|
{ label: 'TUIC', value: 'tuic' },
|
||||||
|
{ label: 'AnyTLS', value: 'anytls' },
|
||||||
|
{ label: 'Naive', value: 'naive' },
|
||||||
{ label: 'Direct', value: 'direct' },
|
{ label: 'Direct', value: 'direct' },
|
||||||
{ label: 'Reject', value: 'reject' },
|
{ label: 'Reject', value: 'reject' },
|
||||||
],
|
],
|
||||||
|
|||||||
+1
-1
@@ -1272,7 +1272,7 @@ declare namespace API {
|
|||||||
has_migrate: boolean;
|
has_migrate: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Hysteria2 = {
|
type Hysteria = {
|
||||||
port: number;
|
port: number;
|
||||||
hop_ports: string;
|
hop_ports: string;
|
||||||
hop_interval: number;
|
hop_interval: number;
|
||||||
|
|||||||
+1
-1
@@ -324,7 +324,7 @@ declare namespace API {
|
|||||||
state: string;
|
state: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Hysteria2 = {
|
type Hysteria = {
|
||||||
port: number;
|
port: number;
|
||||||
hop_ports: string;
|
hop_ports: string;
|
||||||
hop_interval: number;
|
hop_interval: number;
|
||||||
|
|||||||
+1
-1
@@ -324,7 +324,7 @@ declare namespace API {
|
|||||||
state: string;
|
state: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Hysteria2 = {
|
type Hysteria = {
|
||||||
port: number;
|
port: number;
|
||||||
hop_ports: string;
|
hop_ports: string;
|
||||||
hop_interval: number;
|
hop_interval: number;
|
||||||
|
|||||||
Vendored
+1
-1
@@ -343,7 +343,7 @@ declare namespace API {
|
|||||||
list: Ticket[];
|
list: Ticket[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type Hysteria2 = {
|
type Hysteria = {
|
||||||
port: number;
|
port: number;
|
||||||
hop_ports: string;
|
hop_ports: string;
|
||||||
hop_interval: number;
|
hop_interval: number;
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ppanel-web",
|
"name": "ppanel-web",
|
||||||
"version": "1.5.1",
|
"version": "1.5.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/perfect-panel/ppanel-web",
|
"homepage": "https://github.com/perfect-panel/ppanel-web",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|||||||
Reference in New Issue
Block a user