Compare commits

..

7 Commits

Author SHA1 Message Date
semantic-release-bot 8f772c2364 🔖 chore(release): v1.1.1 [skip ci]
## [1.1.1](https://github.com/perfect-panel/ppanel-web/compare/v1.1.0...v1.1.1) (2025-07-20)

### 🐛 Bug Fixes

* **node-table**: Update translations for headers and no data display ([eec0b12](https://github.com/perfect-panel/ppanel-web/commit/eec0b12))
* **rules**: Change rule type from 'auto' to 'default' and update ([3e290d7](https://github.com/perfect-panel/ppanel-web/commit/3e290d7))
* **rules**: Update rule settings ([3304a55](https://github.com/perfect-panel/ppanel-web/commit/3304a55))
* **subscribe-form**: Optimize discount calculation logic and debounce updates ([166e48f](https://github.com/perfect-panel/ppanel-web/commit/166e48f))
* **tutorial**: Comment out unused getVersion function and simplify getVersionPath ([7cdc6bd](https://github.com/perfect-panel/ppanel-web/commit/7cdc6bd))
* **tutorial**: Return latest version in case of fetch error ([1fb305e](https://github.com/perfect-panel/ppanel-web/commit/1fb305e))
2025-07-20 10:24:58 +00:00
web 166e48f442 🐛 fix(subscribe-form): Optimize discount calculation logic and debounce updates 2025-07-20 03:20:59 -07:00
web eec0b12154 🐛 fix(node-table): Update translations for headers and no data display 2025-07-20 03:00:59 -07:00
web 3e290d7cb5 🐛 fix(rules): Change rule type from 'auto' to 'default' and update 2025-07-17 03:30:12 -07:00
web 3304a55fd4 🐛 fix(rules): Update rule settings 2025-07-16 09:16:33 -07:00
web 7cdc6bdd8f 🐛 fix(tutorial): Comment out unused getVersion function and simplify getVersionPath 2025-07-11 02:58:37 -07:00
web 1fb305e7a1 🐛 fix(tutorial): Return latest version in case of fetch error 2025-07-11 01:56:42 -07:00
39 changed files with 327 additions and 198 deletions
+17 -2
View File
@@ -1,12 +1,27 @@
<a name="readme-top"></a>
# Changelog
## [1.1.1](https://github.com/perfect-panel/ppanel-web/compare/v1.1.0...v1.1.1) (2025-07-20)
### 🐛 Bug Fixes
* **node-table**: Update translations for headers and no data display ([eec0b12](https://github.com/perfect-panel/ppanel-web/commit/eec0b12))
* **rules**: Change rule type from 'auto' to 'default' and update ([3e290d7](https://github.com/perfect-panel/ppanel-web/commit/3e290d7))
* **rules**: Update rule settings ([3304a55](https://github.com/perfect-panel/ppanel-web/commit/3304a55))
* **subscribe-form**: Optimize discount calculation logic and debounce updates ([166e48f](https://github.com/perfect-panel/ppanel-web/commit/166e48f))
* **tutorial**: Comment out unused getVersion function and simplify getVersionPath ([7cdc6bd](https://github.com/perfect-panel/ppanel-web/commit/7cdc6bd))
* **tutorial**: Return latest version in case of fetch error ([1fb305e](https://github.com/perfect-panel/ppanel-web/commit/1fb305e))
<a name="readme-top"></a>
# Changelog
# [1.1.0](https://github.com/perfect-panel/ppanel-web/compare/v1.0.2...v1.1.0) (2025-07-06)
### ✨ Features
* **view**: Add AnyTLS protocol support and enhance node configuration options ([bcfb10a](https://github.com/perfect-panel/ppanel-web/commit/bcfb10a))
- **view**: Add AnyTLS protocol support and enhance node configuration options ([bcfb10a](https://github.com/perfect-panel/ppanel-web/commit/bcfb10a))
<a name="readme-top"></a>
@@ -88,12 +88,32 @@ export default function ImportYamlRules({ onImportSuccess }: ImportYamlRulesProp
if (!groups[policyGroup]) {
groups[policyGroup] = [];
}
// 不插入 MATCH 规则,只用于标识默认规则组
if (!rule.trim().startsWith('MATCH,')) {
groups[policyGroup].push(cleanRule);
}
}
return groups;
};
const checkIfDefaultRule = (originalRules: string[], groupName: string): boolean => {
return originalRules.some((rule) => {
const trimmedRule = rule.trim();
if (!trimmedRule.startsWith('MATCH,')) return false;
// 检查 MATCH 规则是否属于当前组
const parts = trimmedRule.split(',');
if (parts.length >= 3) {
const ruleGroup = parts[2]?.trim();
return ruleGroup === groupName;
}
return groupName === 'default';
});
};
const handleImport = async () => {
if (!yamlContent) {
toast.error(t('pleaseUploadFile'));
@@ -130,12 +150,17 @@ export default function ImportYamlRules({ onImportSuccess }: ImportYamlRulesProp
for (let i = 0; i < groups.length; i++) {
const group = groups[i];
if (!group?.name || !group?.rules.length) continue;
const isDefault = checkIfDefaultRule(allRules, group.name);
await createRuleGroup({
name: group.name,
rules: group?.rules.join('\n'),
enable: false,
tags: [],
icon: '',
type: 'default',
default: isDefault,
});
setImportProgress(i + 1);
}
+47 -15
View File
@@ -50,6 +50,8 @@ export default function Page() {
enable: false,
tags: values.tags || [],
icon: values.icon || '',
type: values.type || 'default',
default: false,
});
toast.success(t('createSuccess'));
ref.current?.refresh();
@@ -100,27 +102,55 @@ export default function Page() {
},
},
{
accessorKey: 'icon',
header: t('appIcon'),
cell: ({ row }) =>
row.getValue('icon') ? (
<Image
src={row.getValue('icon')}
alt={row.getValue('name')}
className='h-8 w-8 rounded-md'
width={32}
height={32}
accessorKey: 'default',
header: t('defaultRule'),
cell: ({ row }) => (
<Switch
defaultChecked={row.original.default}
onCheckedChange={async (checked) => {
await updateRuleGroup({
...row.original,
default: checked,
} as API.UpdateRuleGroupRequest);
ref.current?.refresh();
}}
/>
) : (
<div className='bg-muted flex h-8 w-8 items-center justify-center rounded-md'>
{row.original.name?.slice(0, 2)}
</div>
),
},
{
accessorKey: 'type',
header: t('type'),
cell: ({ row }) => {
const type = row.original.type || 'default';
if (type === 'default') {
return <Badge variant='default'>{t('default')}</Badge>;
}
if (type === 'reject') {
return <Badge variant='destructive'>{t('reject')}</Badge>;
}
if (type === 'direct') {
return <Badge variant='secondary'>{t('direct')}</Badge>;
}
return <Badge variant='default'>{t('default')}</Badge>;
},
},
{
accessorKey: 'name',
header: t('name'),
cell: ({ row }) => (
<div className='flex items-center gap-2'>
{row.original.icon && (
<Image
src={row.original.icon}
alt={row.original.name}
className='h-6 w-6 rounded-md'
width={24}
height={24}
/>
)}
<span>{row.original.name}</span>
</div>
),
},
{
accessorKey: 'tags',
@@ -163,6 +193,8 @@ export default function Page() {
rules: values.rules,
enable: row.enable,
icon: values.icon,
type: values.type,
default: row.default,
});
toast.success(t('updateSuccess'));
ref.current?.refresh();
@@ -13,6 +13,13 @@ import {
FormMessage,
} from '@workspace/ui/components/form';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@workspace/ui/components/select';
import {
Sheet,
SheetContent,
@@ -36,6 +43,7 @@ const formSchema = z.object({
tags: z.array(z.string()).default([]),
rules: z.string().default(''),
icon: z.string().default(''),
type: z.string().default('default'),
});
interface RuleFormProps<T> {
@@ -147,6 +155,33 @@ export default function RuleForm<T extends Record<string, any>>({
</FormItem>
)}
/>
<FormField
control={form.control}
name='type'
render={({ field }) => (
<FormItem>
<FormLabel>{t('type')}</FormLabel>
<FormControl>
<Select
value={field.value}
onValueChange={(value) => {
form.setValue(field.name, value);
}}
>
<SelectTrigger>
<SelectValue placeholder={t('selectType')} />
</SelectTrigger>
<SelectContent>
<SelectItem value='default'>{t('default')}</SelectItem>
<SelectItem value='reject'>{t('reject')}</SelectItem>
<SelectItem value='direct'>{t('direct')}</SelectItem>
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='tags'
@@ -73,7 +73,7 @@ export default function NodeTable() {
columns={[
{
accessorKey: 'id',
header: 'ID',
header: t('id'),
cell: ({ row }) => (
<TooltipProvider>
<Tooltip>
@@ -160,7 +160,7 @@ export default function NodeTable() {
header: t('nodeGroup'),
cell: ({ row }) => {
const name = groups?.find((group) => group.id === row.getValue('group_id'))?.name;
return name ? <Badge variant='outline'>{name}</Badge> : '--';
return name ? <Badge variant='outline'>{name}</Badge> : t('noData');
},
},
{
@@ -177,7 +177,7 @@ export default function NodeTable() {
))}
</div>
) : (
'--'
t('noData')
);
},
},
@@ -273,17 +273,17 @@ export default function NodeTable() {
<ConfirmButton
key='delete'
trigger={<Button variant='destructive'>{t('delete')}</Button>}
title={t('group.confirmDelete')}
description={t('group.deleteWarning')}
title={t('confirmDelete')}
description={t('deleteWarning')}
onConfirm={async () => {
await batchDeleteNode({
ids: rows.map((item) => item.id),
});
toast.success(t('group.deleteSuccess'));
toast.success(t('deleteSuccess'));
ref.current?.refresh();
}}
cancelText={t('group.cancel')}
confirmText={t('group.confirm')}
cancelText={t('cancel')}
confirmText={t('confirm')}
/>,
];
},
@@ -42,7 +42,7 @@ import { evaluateWithPrecision, unitConversion } from '@workspace/ui/utils';
import { CreditCard, Server, Settings } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { assign, shake } from 'radash';
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import { z } from 'zod';
@@ -81,6 +81,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
}: Readonly<SubscribeFormProps<T>>) {
const t = useTranslations('subscribe');
const [open, setOpen] = useState(false);
const updateTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const formSchema = z.object({
name: z.string(),
@@ -118,12 +119,111 @@ export default function SubscribeForm<T extends Record<string, any>>({
),
});
const debouncedCalculateDiscount = useCallback(
(values: any[], fieldName: string, lastChangedField?: string, changedIndex?: number) => {
if (updateTimeoutRef.current) {
clearTimeout(updateTimeoutRef.current);
}
updateTimeoutRef.current = setTimeout(() => {
const { unit_price } = form.getValues();
if (!unit_price || !values?.length) return;
let hasChanges = false;
const calculatedValues = values.map((item: any, index: number) => {
const result = { ...item };
if (changedIndex !== undefined && index !== changedIndex) {
return result;
}
const quantity = Number(item.quantity) || 0;
const discount = Number(item.discount) || 0;
const price = Number(item.price) || 0;
switch (lastChangedField) {
case 'quantity':
case 'discount':
if (quantity > 0 && discount > 0) {
const newPrice = evaluateWithPrecision(
`${unit_price} * ${quantity} * ${discount} / 100`,
);
if (Math.abs(newPrice - price) > 0.01) {
result.price = newPrice;
hasChanges = true;
}
}
break;
case 'price':
if (quantity > 0 && price > 0) {
const newDiscount = evaluateWithPrecision(
`${price} / ${quantity} / ${unit_price} * 100`,
);
if (Math.abs(newDiscount - discount) > 0.01) {
result.discount = Math.min(100, Math.max(0, newDiscount));
hasChanges = true;
}
} else if (discount > 0 && price > 0) {
const newQuantity = evaluateWithPrecision(
`${price} / ${unit_price} / ${discount} * 100`,
);
if (Math.abs(newQuantity - quantity) > 0.01 && newQuantity > 0) {
result.quantity = Math.max(1, Math.round(newQuantity));
hasChanges = true;
}
}
break;
default:
if (quantity > 0 && discount > 0 && price === 0) {
result.price = evaluateWithPrecision(
`${unit_price} * ${quantity} * ${discount} / 100`,
);
hasChanges = true;
} else if (quantity > 0 && price > 0 && discount === 0) {
const newDiscount = evaluateWithPrecision(
`${price} / ${quantity} / ${unit_price} * 100`,
);
result.discount = Math.min(100, Math.max(0, newDiscount));
hasChanges = true;
} else if (discount > 0 && price > 0 && quantity === 0) {
const newQuantity = evaluateWithPrecision(
`${price} / ${unit_price} / ${discount} * 100`,
);
if (newQuantity > 0) {
result.quantity = Math.max(1, Math.round(newQuantity));
hasChanges = true;
}
}
break;
}
return result;
});
if (hasChanges) {
form.setValue(fieldName, calculatedValues, { shouldDirty: true });
}
}, 300);
},
[form],
);
useEffect(() => {
form?.reset(
assign(defaultValues, shake(initialValues, (value) => value === null) as Record<string, any>),
);
}, [form, initialValues]);
useEffect(() => {
return () => {
if (updateTimeoutRef.current) {
clearTimeout(updateTimeoutRef.current);
}
};
}, []);
async function handleSubmit(data: { [x: string]: any }) {
const bool = await onSubmit(data as T);
if (bool) setOpen(false);
@@ -158,31 +258,6 @@ export default function SubscribeForm<T extends Record<string, any>>({
const unit_time = form.watch('unit_time');
const unit_price = form.watch('unit_price');
const discounts = form.watch('discount');
useEffect(() => {
if (!discounts?.length || !unit_price) return;
const calculatedValues = discounts.map((item: any) => {
const result = { ...item };
if (item.quantity && item.discount) {
result.price = evaluateWithPrecision(
`${unit_price || 0} * ${item.quantity} * ${item.discount} / 100`,
);
} else if (item.quantity && item.price && !item.discount) {
result.discount = evaluateWithPrecision(
`${item.price} / ${item.quantity} / ${unit_price} * 100`,
);
}
return result;
});
if (JSON.stringify(calculatedValues) !== JSON.stringify(discounts)) {
form.setValue('discount', calculatedValues);
}
}, [unit_price, discounts, form]);
return (
<Sheet open={open} onOpenChange={setOpen}>
@@ -581,8 +656,9 @@ export default function SubscribeForm<T extends Record<string, any>>({
{
name: 'discount',
type: 'number',
min: 1,
min: 0.01,
max: 100,
step: 0.01,
placeholder: t('form.discountPercent'),
suffix: '%',
},
@@ -590,51 +666,53 @@ export default function SubscribeForm<T extends Record<string, any>>({
name: 'price',
placeholder: t('form.discount_price'),
type: 'number',
min: 0,
step: 0.01,
formatInput: (value) => unitConversion('centsToDollars', value),
formatOutput: (value) => unitConversion('dollarsToCents', value),
},
]}
value={field.value}
onChange={(newValues) => {
onChange={(
newValues: (API.SubscribeDiscount & { price?: number })[],
) => {
const oldValues = field.value || [];
const { unit_price } = form.getValues();
let lastChangedField: string | undefined;
let changedIndex: number | undefined;
const calculatedValues = newValues.map((newItem, index) => {
const oldItem = oldValues[index] || {};
const result = { ...newItem };
const quantityChanged = newItem.quantity !== oldItem.quantity;
const discountChanged = newItem.discount !== oldItem.discount;
const priceChanged = newItem.price !== oldItem.price;
if (
(quantityChanged || discountChanged) &&
!priceChanged &&
newItem.quantity &&
newItem.discount
for (
let i = 0;
i < Math.max(newValues.length, oldValues.length);
i++
) {
result.price = evaluateWithPrecision(
`${unit_price || 0} * ${newItem.quantity} * ${newItem.discount} / 100`,
const newItem = newValues[i] || {};
const oldItem = oldValues[i] || {};
if ((newItem as any).quantity !== (oldItem as any).quantity) {
lastChangedField = 'quantity';
changedIndex = i;
break;
}
if ((newItem as any).discount !== (oldItem as any).discount) {
lastChangedField = 'discount';
changedIndex = i;
break;
}
if ((newItem as any).price !== (oldItem as any).price) {
lastChangedField = 'price';
changedIndex = i;
break;
}
}
form.setValue(field.name, newValues, { shouldDirty: true });
if (newValues?.length > 0) {
debouncedCalculateDiscount(
newValues,
field.name,
lastChangedField,
changedIndex,
);
}
if (
priceChanged &&
!discountChanged &&
newItem.price &&
newItem.quantity &&
unit_price
) {
result.discount = evaluateWithPrecision(
`${newItem.price} / ${newItem.quantity} / ${unit_price} * 100`,
);
}
return result;
});
form.setValue(field.name, calculatedValues);
}}
/>
</FormControl>
-4
View File
@@ -11,7 +11,6 @@
"delete": "Smazat",
"deleteSuccess": "Pravidlo bylo úspěšně smazáno",
"deleteWarning": "Opravdu chcete smazat toto pravidlo? Tato akce není vratná.",
"description": "Popis pravidla",
"downloadTemplate": "Stáhnout šablonu",
"edit": "Upravit",
"editRule": "Upravit pravidlo",
@@ -22,7 +21,6 @@
"import": "Importovat",
"importFailed": "Import se nezdařil",
"importSuccess": "Import byl úspěšný",
"importYaml": "Importovat YAML",
"importYamlDescription": "Importujte pravidla ze souboru YAML, systém automaticky vytvoří skupiny pravidel na základě názvů skupin politiky",
"importYamlRules": "Importovat YAML pravidla",
"importing": "Importuji...",
@@ -31,11 +29,9 @@
"noValidRules": "Nebyly nalezeny žádné platné pravidla",
"pleaseUploadFile": "Prosím, nahrajte soubor YAML",
"preview": "Náhled",
"rules": "Obsah pravidla",
"rulesFormat": "Formát pravidla: typ pravidla, obsah shody, [politika], kde politika je volitelná.\nPokud politika není specifikována, bude automaticky použito aktuální jméno skupiny pravidel. Příklady:",
"rulesLabel": "Obsah pravidla",
"searchRule": "Hledat název pravidla",
"selectFile": "Vybrat soubor",
"selectTags": "Vybrat značky uzlu",
"tags": "Značky uzlu",
"tagsLabel": "Značky uzlu",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Löschen",
"deleteSuccess": "Regel erfolgreich gelöscht",
"deleteWarning": "Sind Sie sicher, dass Sie diese Regel löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.",
"description": "Regelbeschreibung",
"downloadTemplate": "Vorlage herunterladen",
"edit": "Bearbeiten",
"editRule": "Regel bearbeiten",
@@ -22,7 +21,6 @@
"import": "Importieren",
"importFailed": "Import fehlgeschlagen",
"importSuccess": "Import erfolgreich",
"importYaml": "YAML importieren",
"importYamlDescription": "Regeln aus einer YAML-Datei importieren, das System erstellt automatisch Regelgruppen basierend auf den Namen der Richtliniengruppen",
"importYamlRules": "YAML-Regeln importieren",
"importing": "Importiere...",
@@ -31,11 +29,9 @@
"noValidRules": "Keine gültigen Regeln gefunden",
"pleaseUploadFile": "Bitte laden Sie eine YAML-Datei hoch",
"preview": "Vorschau",
"rules": "Regelinhalt",
"rulesFormat": "Regelformat: Regeltyp, Übereinstimmungsinhalt, [Richtlinie], wobei die Richtlinie optional ist.\nWenn keine Richtlinie angegeben ist, wird automatisch der aktuelle Regelgruppenname verwendet. Beispiele:",
"rulesLabel": "Regelinhalt",
"searchRule": "Regelname suchen",
"selectFile": "Datei auswählen",
"selectTags": "Knoten-Tags auswählen",
"tags": "Knoten-Tags",
"tagsLabel": "Knoten-Tags",
+6 -4
View File
@@ -8,10 +8,12 @@
"createRule": "Add Rule",
"createSuccess": "Rule created successfully",
"createdAt": "Created At",
"default": "Default",
"defaultRule": "Default Rule",
"delete": "Delete",
"deleteSuccess": "Rule deleted successfully",
"deleteWarning": "Are you sure you want to delete this rule? This action cannot be undone.",
"description": "Rule Description",
"direct": "Direct",
"downloadTemplate": "Download Template",
"edit": "Edit",
"editRule": "Edit Rule",
@@ -22,7 +24,6 @@
"import": "Import",
"importFailed": "Import failed",
"importSuccess": "Import successful",
"importYaml": "Import YAML",
"importYamlDescription": "Import rules from YAML file, the system will automatically create rule groups based on policy group names",
"importYamlRules": "Import YAML Rules",
"importing": "Importing...",
@@ -31,13 +32,14 @@
"noValidRules": "No valid rules found",
"pleaseUploadFile": "Please upload a YAML file",
"preview": "Preview",
"rules": "Rule Content",
"reject": "Reject",
"rulesFormat": "Rule format: rule type,match content,[policy], where policy is optional.\nIf policy is not specified, the current rule group name will be used automatically. Examples:",
"rulesLabel": "Rule Content",
"searchRule": "Search rule name",
"selectFile": "Select File",
"selectTags": "Select node tags",
"selectType": "Select rule type",
"tags": "Node Tags",
"tagsLabel": "Node Tags",
"type": "Rule Type",
"updateSuccess": "Rule updated successfully"
}
+2
View File
@@ -63,6 +63,7 @@
"edit": "Edit",
"editNode": "Edit Node",
"enable": "Enable",
"id": "ID",
"form": {
"allowInsecure": "Allow Insecure",
"cancel": "Cancel",
@@ -141,6 +142,7 @@
"name": "Name",
"node": "Node",
"nodeGroup": "Node Group",
"noData": "--",
"normal": "Normal",
"onlineCount": "Online users",
"onlineUsers": "Online Users",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Eliminar",
"deleteSuccess": "Regla eliminada con éxito",
"deleteWarning": "¿Está seguro de que desea eliminar esta regla? Esta acción no se puede deshacer.",
"description": "Descripción de la Regla",
"downloadTemplate": "Descargar Plantilla",
"edit": "Editar",
"editRule": "Editar Regla",
@@ -22,7 +21,6 @@
"import": "Importar",
"importFailed": "Importación fallida",
"importSuccess": "Importación exitosa",
"importYaml": "Importar YAML",
"importYamlDescription": "Importar reglas desde un archivo YAML, el sistema creará automáticamente grupos de reglas basados en los nombres de los grupos de políticas",
"importYamlRules": "Importar Reglas YAML",
"importing": "Importando...",
@@ -31,11 +29,9 @@
"noValidRules": "No se encontraron reglas válidas",
"pleaseUploadFile": "Por favor, suba un archivo YAML",
"preview": "Vista Previa",
"rules": "Contenido de la Regla",
"rulesFormat": "Formato de regla: tipo de regla, contenido de coincidencia, [política], donde la política es opcional.\nSi no se especifica la política, se utilizará automáticamente el nombre del grupo de reglas actual. Ejemplos:",
"rulesLabel": "Contenido de la Regla",
"searchRule": "Buscar nombre de regla",
"selectFile": "Seleccionar Archivo",
"selectTags": "Seleccionar etiquetas de nodo",
"tags": "Etiquetas de Nodo",
"tagsLabel": "Etiquetas de Nodo",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Eliminar",
"deleteSuccess": "Regla eliminada con éxito",
"deleteWarning": "¿Está seguro de que desea eliminar esta regla? Esta acción no se puede deshacer.",
"description": "Descripción de la Regla",
"downloadTemplate": "Descargar Plantilla",
"edit": "Editar",
"editRule": "Editar Regla",
@@ -22,7 +21,6 @@
"import": "Importar",
"importFailed": "Importación fallida",
"importSuccess": "Importación exitosa",
"importYaml": "Importar YAML",
"importYamlDescription": "Importar reglas desde un archivo YAML, el sistema creará automáticamente grupos de reglas basados en los nombres de los grupos de políticas",
"importYamlRules": "Importar Reglas YAML",
"importing": "Importando...",
@@ -31,11 +29,9 @@
"noValidRules": "No se encontraron reglas válidas",
"pleaseUploadFile": "Por favor, suba un archivo YAML",
"preview": "Vista Previa",
"rules": "Contenido de la Regla",
"rulesFormat": "Formato de regla: tipo de regla, contenido de coincidencia, [política], donde la política es opcional.\nSi no se especifica la política, se utilizará automáticamente el nombre del grupo de reglas actual. Ejemplos:",
"rulesLabel": "Contenido de la Regla",
"searchRule": "Buscar nombre de regla",
"selectFile": "Seleccionar Archivo",
"selectTags": "Seleccionar etiquetas de nodo",
"tags": "Etiquetas de Nodo",
"tagsLabel": "Etiquetas de Nodo",
-4
View File
@@ -11,7 +11,6 @@
"delete": "حذف",
"deleteSuccess": "قانون با موفقیت حذف شد",
"deleteWarning": "آیا مطمئن هستید که می‌خواهید این قانون را حذف کنید؟ این عمل قابل بازگشت نیست.",
"description": "توضیحات قانون",
"downloadTemplate": "دانلود الگو",
"edit": "ویرایش",
"editRule": "ویرایش قانون",
@@ -22,7 +21,6 @@
"import": "وارد کردن",
"importFailed": "وارد کردن ناموفق بود",
"importSuccess": "وارد کردن با موفقیت انجام شد",
"importYaml": "وارد کردن YAML",
"importYamlDescription": "وارد کردن قوانین از فایل YAML، سیستم به طور خودکار گروه‌های قانونی را بر اساس نام‌های گروه سیاست ایجاد خواهد کرد",
"importYamlRules": "وارد کردن قوانین YAML",
"importing": "در حال وارد کردن...",
@@ -31,11 +29,9 @@
"noValidRules": "هیچ قانونی یافت نشد",
"pleaseUploadFile": "لطفاً یک فایل YAML بارگذاری کنید",
"preview": "پیش‌نمایش",
"rules": "محتوای قانون",
"rulesFormat": "فرمت قانون: نوع قانون، محتوای تطابق، [سیاست]، که سیاست اختیاری است.\nاگر سیاست مشخص نشود، نام گروه قانونی فعلی به طور خودکار استفاده خواهد شد. مثال‌ها:",
"rulesLabel": "محتوای قانون",
"searchRule": "جستجوی نام قانون",
"selectFile": "انتخاب فایل",
"selectTags": "انتخاب برچسب‌های گره",
"tags": "برچسب‌های گره",
"tagsLabel": "برچسب‌های گره",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Poista",
"deleteSuccess": "Sääntö poistettiin onnistuneesti",
"deleteWarning": "Oletko varma, että haluat poistaa tämän säännön? Tätä toimintoa ei voi peruuttaa.",
"description": "Säännön kuvaus",
"downloadTemplate": "Lataa malli",
"edit": "Muokkaa",
"editRule": "Muokkaa sääntöä",
@@ -22,7 +21,6 @@
"import": "Tuoda",
"importFailed": "Tuonti epäonnistui",
"importSuccess": "Tuonti onnistui",
"importYaml": "Tuo YAML",
"importYamlDescription": "Tuo sääntöjä YAML-tiedostosta, järjestelmä luo automaattisesti sääntöryhmiä politiikkaryhmän nimien perusteella",
"importYamlRules": "Tuo YAML-säännöt",
"importing": "Tuodaan...",
@@ -31,11 +29,9 @@
"noValidRules": "Ei voimassa olevia sääntöjä löytynyt",
"pleaseUploadFile": "Lataa YAML-tiedosto",
"preview": "Esikatselu",
"rules": "Säännön sisältö",
"rulesFormat": "Sääntömuoto: sääntötyyppi, vastaavuus, [politiikka], jossa politiikka on valinnainen.\nJos politiikkaa ei ole määritelty, nykyistä sääntöryhmän nimeä käytetään automaattisesti. Esimerkkejä:",
"rulesLabel": "Säännön sisältö",
"searchRule": "Etsi säännön nimeä",
"selectFile": "Valitse tiedosto",
"selectTags": "Valitse solmun tunnisteet",
"tags": "Solmun tunnisteet",
"tagsLabel": "Solmun tunnisteet",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Supprimer",
"deleteSuccess": "Règle supprimée avec succès",
"deleteWarning": "Êtes-vous sûr de vouloir supprimer cette règle ? Cette action ne peut pas être annulée.",
"description": "Description de la règle",
"downloadTemplate": "Télécharger le modèle",
"edit": "Modifier",
"editRule": "Modifier la règle",
@@ -22,7 +21,6 @@
"import": "Importer",
"importFailed": "Échec de l'importation",
"importSuccess": "Importation réussie",
"importYaml": "Importer YAML",
"importYamlDescription": "Importer des règles à partir d'un fichier YAML, le système créera automatiquement des groupes de règles en fonction des noms de groupes de politiques",
"importYamlRules": "Importer des règles YAML",
"importing": "Importation en cours...",
@@ -31,11 +29,9 @@
"noValidRules": "Aucune règle valide trouvée",
"pleaseUploadFile": "Veuillez télécharger un fichier YAML",
"preview": "Aperçu",
"rules": "Contenu de la règle",
"rulesFormat": "Format de la règle : type de règle, contenu de correspondance, [politique], où la politique est optionnelle.\nSi la politique n'est pas spécifiée, le nom du groupe de règles actuel sera utilisé automatiquement. Exemples :",
"rulesLabel": "Contenu de la règle",
"searchRule": "Rechercher le nom de la règle",
"selectFile": "Sélectionner un fichier",
"selectTags": "Sélectionner des balises de nœud",
"tags": "Balises de nœud",
"tagsLabel": "Balises de nœud",
-4
View File
@@ -11,7 +11,6 @@
"delete": "हटाएं",
"deleteSuccess": "नियम सफलतापूर्वक हटाया गया",
"deleteWarning": "क्या आप वाकई इस नियम को हटाना चाहते हैं? यह क्रिया पूर्ववत नहीं की जा सकती।",
"description": "नियम विवरण",
"downloadTemplate": "टेम्पलेट डाउनलोड करें",
"edit": "संपादित करें",
"editRule": "नियम संपादित करें",
@@ -22,7 +21,6 @@
"import": "आयात करें",
"importFailed": "आयात विफल",
"importSuccess": "आयात सफल",
"importYaml": "YAML आयात करें",
"importYamlDescription": "YAML फ़ाइल से नियम आयात करें, प्रणाली स्वचालित रूप से नीति समूह नामों के आधार पर नियम समूह बनाएगी",
"importYamlRules": "YAML नियम आयात करें",
"importing": "आयात कर रहा है...",
@@ -31,11 +29,9 @@
"noValidRules": "कोई मान्य नियम नहीं मिला",
"pleaseUploadFile": "कृपया एक YAML फ़ाइल अपलोड करें",
"preview": "पूर्वावलोकन",
"rules": "नियम सामग्री",
"rulesFormat": "नियम प्रारूप: नियम प्रकार, मिलान सामग्री, [नीति], जहाँ नीति वैकल्पिक है।\nयदि नीति निर्दिष्ट नहीं की गई है, तो वर्तमान नियम समूह का नाम स्वचालित रूप से उपयोग किया जाएगा। उदाहरण:",
"rulesLabel": "नियम सामग्री",
"searchRule": "नियम नाम खोजें",
"selectFile": "फ़ाइल चुनें",
"selectTags": "नोड टैग चुनें",
"tags": "नोड टैग",
"tagsLabel": "नोड टैग",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Törlés",
"deleteSuccess": "A szabály sikeresen törölve",
"deleteWarning": "Biztosan törölni szeretné ezt a szabályt? Ez a művelet nem vonható vissza.",
"description": "Szabály leírása",
"downloadTemplate": "Sablon letöltése",
"edit": "Szerkesztés",
"editRule": "Szabály szerkesztése",
@@ -22,7 +21,6 @@
"import": "Importálás",
"importFailed": "Importálás sikertelen",
"importSuccess": "Importálás sikeres",
"importYaml": "YAML importálása",
"importYamlDescription": "Szabályok importálása YAML fájlból, a rendszer automatikusan létrehozza a szabálycsoportokat a politikai csoportnevek alapján",
"importYamlRules": "YAML szabályok importálása",
"importing": "Importálás...",
@@ -31,11 +29,9 @@
"noValidRules": "Nincsenek érvényes szabályok",
"pleaseUploadFile": "Kérjük, töltsön fel egy YAML fájlt",
"preview": "Előnézet",
"rules": "Szabály tartalom",
"rulesFormat": "Szabály formátum: szabály típusa, egyezési tartalom, [politika], ahol a politika opcionális.\nHa a politika nincs megadva, az aktuális szabálycsoport neve automatikusan felhasználásra kerül. Példák:",
"rulesLabel": "Szabály tartalom",
"searchRule": "Szabály név keresése",
"selectFile": "Fájl kiválasztása",
"selectTags": "Válassza ki a csomópont címkéket",
"tags": "Csomópont címkék",
"tagsLabel": "Csomópont címkék",
+3 -4
View File
@@ -8,10 +8,10 @@
"createRule": "ルールを追加",
"createSuccess": "ルールが正常に作成されました",
"createdAt": "作成日時",
"defaultRule": "デフォルトルール",
"delete": "削除",
"deleteSuccess": "ルールが正常に削除されました",
"deleteWarning": "このルールを削除してもよろしいですか?この操作は元に戻せません。",
"description": "ルールの説明",
"downloadTemplate": "テンプレートをダウンロード",
"edit": "編集",
"editRule": "ルールを編集",
@@ -22,7 +22,6 @@
"import": "インポート",
"importFailed": "インポートに失敗しました",
"importSuccess": "インポートが成功しました",
"importYaml": "YAMLをインポート",
"importYamlDescription": "YAMLファイルからルールをインポートします。システムはポリシーグループ名に基づいてルールグループを自動的に作成します。",
"importYamlRules": "YAMLルールをインポート",
"importing": "インポート中...",
@@ -31,13 +30,13 @@
"noValidRules": "有効なルールが見つかりません",
"pleaseUploadFile": "YAMLファイルをアップロードしてください",
"preview": "プレビュー",
"rules": "ルールの内容",
"rulesFormat": "ルール形式: ルールタイプ, マッチ内容, [ポリシー](ポリシーはオプションです)。\nポリシーが指定されていない場合、現在のルールグループ名が自動的に使用されます。例:",
"rulesLabel": "ルールの内容",
"searchRule": "ルール名を検索",
"selectFile": "ファイルを選択",
"selectTags": "ノードタグを選択",
"selectType": "ルールタイプを選択",
"tags": "ノードタグ",
"tagsLabel": "ノードタグ",
"type": "ルールタイプ",
"updateSuccess": "ルールが正常に更新されました"
}
-4
View File
@@ -11,7 +11,6 @@
"delete": "삭제",
"deleteSuccess": "규칙이 성공적으로 삭제되었습니다",
"deleteWarning": "이 규칙을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.",
"description": "규칙 설명",
"downloadTemplate": "템플릿 다운로드",
"edit": "편집",
"editRule": "규칙 편집",
@@ -22,7 +21,6 @@
"import": "가져오기",
"importFailed": "가져오기에 실패했습니다",
"importSuccess": "가져오기가 성공적으로 완료되었습니다",
"importYaml": "YAML 가져오기",
"importYamlDescription": "YAML 파일에서 규칙을 가져오며, 시스템이 정책 그룹 이름에 따라 규칙 그룹을 자동으로 생성합니다",
"importYamlRules": "YAML 규칙 가져오기",
"importing": "가져오는 중...",
@@ -31,11 +29,9 @@
"noValidRules": "유효한 규칙이 없습니다",
"pleaseUploadFile": "YAML 파일을 업로드해 주세요",
"preview": "미리보기",
"rules": "규칙 내용",
"rulesFormat": "규칙 형식: 규칙 유형, 일치하는 내용, [정책], 여기서 정책은 선택 사항입니다.\n정책이 지정되지 않으면 현재 규칙 그룹 이름이 자동으로 사용됩니다. 예시:",
"rulesLabel": "규칙 내용",
"searchRule": "규칙 이름 검색",
"selectFile": "파일 선택",
"selectTags": "노드 태그 선택",
"tags": "노드 태그",
"tagsLabel": "노드 태그",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Slett",
"deleteSuccess": "Regel slettet med suksess",
"deleteWarning": "Er du sikker på at du vil slette denne regelen? Denne handlingen kan ikke angres.",
"description": "Regelbeskrivelse",
"downloadTemplate": "Last ned mal",
"edit": "Rediger",
"editRule": "Rediger regel",
@@ -22,7 +21,6 @@
"import": "Importer",
"importFailed": "Import mislyktes",
"importSuccess": "Import vellykket",
"importYaml": "Importer YAML",
"importYamlDescription": "Importer regler fra YAML-fil, systemet vil automatisk opprette regelgrupper basert på policygruppens navn",
"importYamlRules": "Importer YAML-regler",
"importing": "Importer...",
@@ -31,11 +29,9 @@
"noValidRules": "Ingen gyldige regler funnet",
"pleaseUploadFile": "Vennligst last opp en YAML-fil",
"preview": "Forhåndsvisning",
"rules": "Regelinnhold",
"rulesFormat": "Regelformat: regeltype, matchinnhold, [policy], der policy er valgfritt.\nHvis policy ikke er spesifisert, vil det nåværende regelgruppens navn bli brukt automatisk. Eksempler:",
"rulesLabel": "Regelinnhold",
"searchRule": "Søk etter regelnavn",
"selectFile": "Velg fil",
"selectTags": "Velg nodetagger",
"tags": "Nodetagger",
"tagsLabel": "Nodetagger",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Usuń",
"deleteSuccess": "Reguła została pomyślnie usunięta",
"deleteWarning": "Czy na pewno chcesz usunąć tę regułę? Ta akcja nie może być cofnięta.",
"description": "Opis Reguły",
"downloadTemplate": "Pobierz Szablon",
"edit": "Edytuj",
"editRule": "Edytuj Regułę",
@@ -22,7 +21,6 @@
"import": "Importuj",
"importFailed": "Import nie powiódł się",
"importSuccess": "Import zakończony sukcesem",
"importYaml": "Importuj YAML",
"importYamlDescription": "Importuj reguły z pliku YAML, system automatycznie utworzy grupy reguł na podstawie nazw grup polityk",
"importYamlRules": "Importuj Reguły YAML",
"importing": "Importowanie...",
@@ -31,11 +29,9 @@
"noValidRules": "Nie znaleziono prawidłowych reguł",
"pleaseUploadFile": "Proszę przesłać plik YAML",
"preview": "Podgląd",
"rules": "Treść Reguły",
"rulesFormat": "Format reguły: typ reguły, treść dopasowania, [polityka], gdzie polityka jest opcjonalna.\nJeśli polityka nie jest określona, aktualna nazwa grupy reguł zostanie użyta automatycznie. Przykłady:",
"rulesLabel": "Treść Reguły",
"searchRule": "Szukaj nazwy reguły",
"selectFile": "Wybierz Plik",
"selectTags": "Wybierz tagi węzła",
"tags": "Tagi Węzła",
"tagsLabel": "Tagi Węzła",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Excluir",
"deleteSuccess": "Regra excluída com sucesso",
"deleteWarning": "Você tem certeza de que deseja excluir esta regra? Esta ação não pode ser desfeita.",
"description": "Descrição da Regra",
"downloadTemplate": "Baixar Modelo",
"edit": "Editar",
"editRule": "Editar Regra",
@@ -22,7 +21,6 @@
"import": "Importar",
"importFailed": "Falha na importação",
"importSuccess": "Importação bem-sucedida",
"importYaml": "Importar YAML",
"importYamlDescription": "Importar regras de um arquivo YAML, o sistema criará automaticamente grupos de regras com base nos nomes dos grupos de políticas",
"importYamlRules": "Importar Regras YAML",
"importing": "Importando...",
@@ -31,11 +29,9 @@
"noValidRules": "Nenhuma regra válida encontrada",
"pleaseUploadFile": "Por favor, faça upload de um arquivo YAML",
"preview": "Pré-visualização",
"rules": "Conteúdo da Regra",
"rulesFormat": "Formato da regra: tipo de regra, conteúdo de correspondência, [política], onde a política é opcional.\nSe a política não for especificada, o nome do grupo de regras atual será usado automaticamente. Exemplos:",
"rulesLabel": "Conteúdo da Regra",
"searchRule": "Pesquisar nome da regra",
"selectFile": "Selecionar Arquivo",
"selectTags": "Selecionar tags de nó",
"tags": "Tags de Nó",
"tagsLabel": "Tags de Nó",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Șterge",
"deleteSuccess": "Regula a fost ștersă cu succes",
"deleteWarning": "Ești sigur că vrei să ștergi această regulă? Această acțiune nu poate fi anulată.",
"description": "Descrierea Regulii",
"downloadTemplate": "Descarcă Șablon",
"edit": "Editează",
"editRule": "Editează Regulă",
@@ -22,7 +21,6 @@
"import": "Importă",
"importFailed": "Importul a eșuat",
"importSuccess": "Importul a fost realizat cu succes",
"importYaml": "Importă YAML",
"importYamlDescription": "Importă reguli din fișier YAML, sistemul va crea automat grupuri de reguli pe baza numelui grupului de politici",
"importYamlRules": "Importă Reguli YAML",
"importing": "Se importă...",
@@ -31,11 +29,9 @@
"noValidRules": "Nu au fost găsite reguli valide",
"pleaseUploadFile": "Te rugăm să încarci un fișier YAML",
"preview": "Previzualizare",
"rules": "Conținutul Regulii",
"rulesFormat": "Formatul regulii: tip regulă, conținut de potrivire, [politică], unde politica este opțională.\nDacă politica nu este specificată, numele grupului de reguli curent va fi folosit automat. Exemple:",
"rulesLabel": "Conținutul Regulii",
"searchRule": "Caută numele regulii",
"selectFile": "Selectează Fișier",
"selectTags": "Selectează etichetele nodului",
"tags": "Etichete Nod",
"tagsLabel": "Etichete Nod",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Удалить",
"deleteSuccess": "Правило успешно удалено",
"deleteWarning": "Вы уверены, что хотите удалить это правило? Это действие нельзя отменить.",
"description": "Описание правила",
"downloadTemplate": "Скачать шаблон",
"edit": "Редактировать",
"editRule": "Редактировать правило",
@@ -22,7 +21,6 @@
"import": "Импортировать",
"importFailed": "Ошибка импорта",
"importSuccess": "Импорт успешен",
"importYaml": "Импортировать YAML",
"importYamlDescription": "Импорт правил из файла YAML, система автоматически создаст группы правил на основе имен групп политик",
"importYamlRules": "Импортировать правила YAML",
"importing": "Импортирую...",
@@ -31,11 +29,9 @@
"noValidRules": "Не найдено действительных правил",
"pleaseUploadFile": "Пожалуйста, загрузите файл YAML",
"preview": "Предварительный просмотр",
"rules": "Содержание правила",
"rulesFormat": "Формат правила: тип правила, содержание совпадения, [политика], где политика является необязательной.\nЕсли политика не указана, будет автоматически использовано текущее имя группы правил. Примеры:",
"rulesLabel": "Содержание правила",
"searchRule": "Поиск имени правила",
"selectFile": "Выбрать файл",
"selectTags": "Выбрать теги узлов",
"tags": "Теги узлов",
"tagsLabel": "Теги узлов",
-4
View File
@@ -11,7 +11,6 @@
"delete": "ลบ",
"deleteSuccess": "ลบกฎเรียบร้อยแล้ว",
"deleteWarning": "คุณแน่ใจหรือว่าต้องการลบกฎนี้? การกระทำนี้ไม่สามารถย้อนกลับได้.",
"description": "คำอธิบายกฎ",
"downloadTemplate": "ดาวน์โหลดเทมเพลต",
"edit": "แก้ไข",
"editRule": "แก้ไขกฎ",
@@ -22,7 +21,6 @@
"import": "นำเข้า",
"importFailed": "นำเข้าล้มเหลว",
"importSuccess": "นำเข้าสำเร็จ",
"importYaml": "นำเข้า YAML",
"importYamlDescription": "นำเข้ากฎจากไฟล์ YAML, ระบบจะสร้างกลุ่มกฎโดยอัตโนมัติตามชื่อกลุ่มนโยบาย",
"importYamlRules": "นำเข้ากฎ YAML",
"importing": "กำลังนำเข้า...",
@@ -31,11 +29,9 @@
"noValidRules": "ไม่พบกฎที่ถูกต้อง",
"pleaseUploadFile": "กรุณาอัปโหลดไฟล์ YAML",
"preview": "ตัวอย่าง",
"rules": "เนื้อหากฎ",
"rulesFormat": "รูปแบบกฎ: ประเภทกฎ, เนื้อหาที่ตรงกัน, [นโยบาย], โดยที่นโยบายเป็นทางเลือก.\nหากไม่ได้ระบุนโยบาย, ชื่อกลุ่มกฎปัจจุบันจะถูกใช้โดยอัตโนมัติ. ตัวอย่าง:",
"rulesLabel": "เนื้อหากฎ",
"searchRule": "ค้นหาชื่อกฎ",
"selectFile": "เลือกไฟล์",
"selectTags": "เลือกแท็กโหนด",
"tags": "แท็กโหนด",
"tagsLabel": "แท็กโหนด",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Sil",
"deleteSuccess": "Kural başarıyla silindi",
"deleteWarning": "Bu kuralı silmek istediğinize emin misiniz? Bu işlem geri alınamaz.",
"description": "Kural Açıklaması",
"downloadTemplate": "Şablonu İndir",
"edit": "Düzenle",
"editRule": "Kuralı Düzenle",
@@ -22,7 +21,6 @@
"import": "İçe Aktar",
"importFailed": "İçe aktarma başarısız oldu",
"importSuccess": "İçe aktarma başarılı",
"importYaml": "YAML İçe Aktar",
"importYamlDescription": "YAML dosyasından kuralları içe aktarın, sistem otomatik olarak politika grup adlarına göre kural grupları oluşturacaktır",
"importYamlRules": "YAML Kurallarını İçe Aktar",
"importing": "İçe aktarılıyor...",
@@ -31,11 +29,9 @@
"noValidRules": "Geçerli kural bulunamadı",
"pleaseUploadFile": "Lütfen bir YAML dosyası yükleyin",
"preview": "Önizleme",
"rules": "Kural İçeriği",
"rulesFormat": "Kural formatı: kural türü, eşleşme içeriği,[politika], burada politika isteğe bağlıdır.\nEğer politika belirtilmemişse, mevcut kural grup adı otomatik olarak kullanılacaktır. Örnekler:",
"rulesLabel": "Kural İçeriği",
"searchRule": "Kural adını ara",
"selectFile": "Dosya Seç",
"selectTags": "Düğüm etiketlerini seç",
"tags": "Düğüm Etiketleri",
"tagsLabel": "Düğüm Etiketleri",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Видалити",
"deleteSuccess": "Правило успішно видалено",
"deleteWarning": "Ви впевнені, що хочете видалити це правило? Цю дію не можна скасувати.",
"description": "Опис правила",
"downloadTemplate": "Завантажити шаблон",
"edit": "Редагувати",
"editRule": "Редагувати правило",
@@ -22,7 +21,6 @@
"import": "Імпортувати",
"importFailed": "Імпорт не вдався",
"importSuccess": "Імпорт успішний",
"importYaml": "Імпортувати YAML",
"importYamlDescription": "Імпортуйте правила з файлу YAML, система автоматично створить групи правил на основі назв груп політик",
"importYamlRules": "Імпортувати правила YAML",
"importing": "Імпортується...",
@@ -31,11 +29,9 @@
"noValidRules": "Не знайдено дійсних правил",
"pleaseUploadFile": "Будь ласка, завантажте файл YAML",
"preview": "Попередній перегляд",
"rules": "Вміст правила",
"rulesFormat": "Формат правила: тип правила, вміст збігу, [політика], де політика є необов'язковою.\nЯкщо політика не вказана, автоматично буде використано назву поточної групи правил. Приклади:",
"rulesLabel": "Вміст правила",
"searchRule": "Шукати назву правила",
"selectFile": "Вибрати файл",
"selectTags": "Вибрати теги вузлів",
"tags": "Теги вузлів",
"tagsLabel": "Теги вузлів",
-4
View File
@@ -11,7 +11,6 @@
"delete": "Xóa",
"deleteSuccess": "Quy tắc đã được xóa thành công",
"deleteWarning": "Bạn có chắc chắn muốn xóa quy tắc này không? Hành động này không thể hoàn tác.",
"description": "Mô tả Quy tắc",
"downloadTemplate": "Tải Mẫu",
"edit": "Chỉnh sửa",
"editRule": "Chỉnh sửa Quy tắc",
@@ -22,7 +21,6 @@
"import": "Nhập khẩu",
"importFailed": "Nhập khẩu không thành công",
"importSuccess": "Nhập khẩu thành công",
"importYaml": "Nhập YAML",
"importYamlDescription": "Nhập quy tắc từ tệp YAML, hệ thống sẽ tự động tạo nhóm quy tắc dựa trên tên nhóm chính sách",
"importYamlRules": "Nhập Quy tắc YAML",
"importing": "Đang nhập khẩu...",
@@ -31,11 +29,9 @@
"noValidRules": "Không tìm thấy quy tắc hợp lệ",
"pleaseUploadFile": "Vui lòng tải lên một tệp YAML",
"preview": "Xem trước",
"rules": "Nội dung Quy tắc",
"rulesFormat": "Định dạng quy tắc: loại quy tắc, nội dung khớp, [chính sách], trong đó chính sách là tùy chọn.\nNếu không chỉ định chính sách, tên nhóm quy tắc hiện tại sẽ được sử dụng tự động. Ví dụ:",
"rulesLabel": "Nội dung Quy tắc",
"searchRule": "Tìm kiếm tên quy tắc",
"selectFile": "Chọn Tệp",
"selectTags": "Chọn thẻ nút",
"tags": "Thẻ Nút",
"tagsLabel": "Thẻ Nút",
+6 -4
View File
@@ -8,10 +8,12 @@
"createRule": "添加规则",
"createSuccess": "创建规则成功",
"createdAt": "创建时间",
"default": "默认",
"defaultRule": "默认规则",
"delete": "删除",
"deleteSuccess": "删除规则成功",
"deleteWarning": "确定要删除所选规则吗?此操作不可恢复。",
"description": "规则描述",
"direct": "直连",
"downloadTemplate": "下载模板",
"edit": "编辑",
"editRule": "编辑规则",
@@ -22,7 +24,6 @@
"import": "导入",
"importFailed": "导入失败",
"importSuccess": "导入成功",
"importYaml": "导入YAML",
"importYamlDescription": "从YAML文件导入规则,系统将自动根据策略组名称分组创建规则",
"importYamlRules": "导入YAML规则",
"importing": "导入中...",
@@ -31,13 +32,14 @@
"noValidRules": "没有找到有效的规则",
"pleaseUploadFile": "请上传YAML文件",
"preview": "预览",
"rules": "规则内容",
"reject": "拒绝",
"rulesFormat": "规则格式说明:规则类型,匹配内容,[策略], 其中策略为可选项。\n不指定策略时,将自动使用当前规则组名称, 示例:",
"rulesLabel": "规则内容",
"searchRule": "搜索规则名称",
"selectFile": "选择文件",
"selectTags": "选择节点标签",
"selectType": "选择规则类型",
"tags": "节点标签",
"tagsLabel": "节点标签",
"type": "规则类型",
"updateSuccess": "更新规则成功"
}
+2
View File
@@ -63,6 +63,7 @@
"edit": "编辑",
"editNode": "编辑节点",
"enable": "启用",
"id": "ID",
"form": {
"allowInsecure": "允许不安全",
"cancel": "取消",
@@ -141,6 +142,7 @@
"name": "名称",
"node": "节点",
"nodeGroup": "节点组",
"noData": "--",
"normal": "正常",
"onlineCount": "在线人数",
"onlineUsers": "在线用户",
+3 -4
View File
@@ -8,10 +8,10 @@
"createRule": "新增規則",
"createSuccess": "規則創建成功",
"createdAt": "創建於",
"defaultRule": "默認規則",
"delete": "刪除",
"deleteSuccess": "規則刪除成功",
"deleteWarning": "您確定要刪除這條規則嗎?此操作無法撤銷。",
"description": "規則描述",
"downloadTemplate": "下載模板",
"edit": "編輯",
"editRule": "編輯規則",
@@ -22,7 +22,6 @@
"import": "導入",
"importFailed": "導入失敗",
"importSuccess": "導入成功",
"importYaml": "導入 YAML",
"importYamlDescription": "從 YAML 文件導入規則,系統將根據策略組名稱自動創建規則組",
"importYamlRules": "導入 YAML 規則",
"importing": "導入中...",
@@ -31,13 +30,13 @@
"noValidRules": "未找到有效的規則",
"pleaseUploadFile": "請上傳 YAML 文件",
"preview": "預覽",
"rules": "規則內容",
"rulesFormat": "規則格式:規則類型,匹配內容,[策略],其中策略是可選的。\n如果未指定策略,將自動使用當前規則組名稱。示例:",
"rulesLabel": "規則內容",
"searchRule": "搜索規則名稱",
"selectFile": "選擇文件",
"selectTags": "選擇節點標籤",
"selectType": "選擇規則類型",
"tags": "節點標籤",
"tagsLabel": "節點標籤",
"type": "規則類型",
"updateSuccess": "規則更新成功"
}
+1
View File
@@ -9968,3 +9968,4 @@ rules:
- PROCESS-NAME,Weiyun.exe,🎯 全球直连
- PROCESS-NAME,baidunetdisk.exe,🎯 全球直连
- GEOIP,CN,🎯 全球直连
- MATCH,🚀 节点选择
+6
View File
@@ -296,8 +296,10 @@ declare namespace API {
type CreateRuleGroupRequest = {
name: string;
icon: string;
type: string;
tags: string[];
rules: string;
default: boolean;
enable: boolean;
};
@@ -1283,9 +1285,11 @@ declare namespace API {
id: number;
icon: string;
name: string;
type: string;
tags: string[];
rules: string;
enable: boolean;
default: boolean;
created_at: number;
updated_at: number;
};
@@ -1629,9 +1633,11 @@ declare namespace API {
type UpdateRuleGroupRequest = {
id: number;
icon: string;
type: string;
name: string;
tags: string[];
rules: string;
default: boolean;
enable: boolean;
};
+2
View File
@@ -696,9 +696,11 @@ declare namespace API {
id: number;
icon: string;
name: string;
type: string;
tags: string[];
rules: string;
enable: boolean;
default: boolean;
created_at: number;
updated_at: number;
};
+1 -1
View File
@@ -10,7 +10,7 @@ export const NEXT_PUBLIC_DEFAULT_LANGUAGE =
export const NEXT_PUBLIC_SITE_URL = env('NEXT_PUBLIC_SITE_URL') ?? process.env.NEXT_PUBLIC_SITE_URL;
export const NEXT_PUBLIC_API_URL = env('NEXT_PUBLIC_API_URL') ?? process.env.NEXT_PUBLIC_API_URL;
export const NEXT_PUBLIC_CDN_URL =
env('NEXT_PUBLIC_CDN_URL') || process.env.NEXT_PUBLIC_CDN_URL || 'https://fastly.jsdelivr.net';
env('NEXT_PUBLIC_CDN_URL') || process.env.NEXT_PUBLIC_CDN_URL || 'https://cdn.jsdelivr.net';
export const NEXT_PUBLIC_DEFAULT_USER_EMAIL =
env('NEXT_PUBLIC_DEFAULT_USER_EMAIL') ?? process.env.NEXT_PUBLIC_DEFAULT_USER_EMAIL;
+2
View File
@@ -696,9 +696,11 @@ declare namespace API {
id: number;
icon: string;
name: string;
type: string;
tags: string[];
rules: string;
enable: boolean;
default: boolean;
created_at: number;
updated_at: number;
};
+2
View File
@@ -794,9 +794,11 @@ declare namespace API {
id: number;
icon: string;
name: string;
type: string;
tags: string[];
rules: string;
enable: boolean;
default: boolean;
created_at: number;
updated_at: number;
};
+15 -14
View File
@@ -3,22 +3,23 @@ import matter from 'gray-matter';
const BASE_URL = `${NEXT_PUBLIC_CDN_URL}/gh/perfect-panel/ppanel-tutorial`;
async function getVersion() {
// API rate limit: 60 requests per hour
const response = await fetch(
'https://data.jsdelivr.com/v1/stats/packages/gh/perfect-panel/ppanel-tutorial/versions',
);
const json = await response.json();
return json[0].version;
}
// async function getVersion() {
// // API rate limit: 60 requests per hour
// const response = await fetch(
// 'https://data.jsdelivr.com/v1/stats/packages/gh/perfect-panel/ppanel-tutorial/versions',
// );
// const json = await response.json();
// return json[0].version;
// }
async function getVersionPath() {
return getVersion()
.then((version) => `${BASE_URL}@${version}`)
.catch((error) => {
console.warn('Error fetching the version:', error);
return BASE_URL;
});
// return getVersion()
// .then((version) => `${BASE_URL}@${version}`)
// .catch((error) => {
// console.warn('Error fetching the version:', error);
// return `${BASE_URL}@latest`;
// });
return `${BASE_URL}@latest`;
}
export async function getTutorial(path: string): Promise<{
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ppanel-web",
"version": "1.1.0",
"version": "1.1.1",
"private": true,
"homepage": "https://github.com/perfect-panel/ppanel-web",
"bugs": {