mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
fix: RBAC frontend type mismatches and translations
- Move RBAC translations from banSystem to admin namespace in all 4 locales - Fix AccessPolicy type: action (string) -> actions (string[]) - Fix AuditLogEntry type to match backend: add status, request_method, request_path, resource_type, user info - Fix AuditLogFilters: resource -> resource_type, add status filter - Handle null details safely in audit log expanded view - Fix policy form submission and display to use actions array
This commit is contained in:
@@ -60,33 +60,37 @@ export interface AccessPolicy {
|
|||||||
name: string;
|
name: string;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
resource: string;
|
resource: string;
|
||||||
action: string;
|
actions: string[];
|
||||||
effect: 'allow' | 'deny';
|
effect: 'allow' | 'deny';
|
||||||
conditions: Record<string, unknown>;
|
conditions: Record<string, unknown>;
|
||||||
priority: number;
|
priority: number;
|
||||||
|
role_id: number | null;
|
||||||
|
role_name: string | null;
|
||||||
is_active: boolean;
|
is_active: boolean;
|
||||||
|
created_by: number | null;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreatePolicyPayload {
|
export interface CreatePolicyPayload {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
resource: string;
|
resource: string;
|
||||||
action: string;
|
actions: string[];
|
||||||
effect: 'allow' | 'deny';
|
effect: 'allow' | 'deny';
|
||||||
conditions?: Record<string, unknown>;
|
conditions?: Record<string, unknown>;
|
||||||
priority?: number;
|
priority?: number;
|
||||||
|
role_id?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdatePolicyPayload {
|
export interface UpdatePolicyPayload {
|
||||||
name?: string;
|
name?: string;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
resource?: string;
|
resource?: string;
|
||||||
action?: string;
|
actions?: string[];
|
||||||
effect?: 'allow' | 'deny';
|
effect?: 'allow' | 'deny';
|
||||||
conditions?: Record<string, unknown>;
|
conditions?: Record<string, unknown>;
|
||||||
priority?: number;
|
priority?: number;
|
||||||
|
role_id?: number | null;
|
||||||
is_active?: boolean;
|
is_active?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,20 +98,24 @@ export interface AuditLogEntry {
|
|||||||
id: number;
|
id: number;
|
||||||
user_id: number;
|
user_id: number;
|
||||||
action: string;
|
action: string;
|
||||||
resource: string;
|
resource_type: string | null;
|
||||||
resource_id: string | null;
|
resource_id: string | null;
|
||||||
details: Record<string, unknown>;
|
details: Record<string, unknown> | null;
|
||||||
ip_address: string | null;
|
ip_address: string | null;
|
||||||
user_agent: string | null;
|
user_agent: string | null;
|
||||||
|
status: string;
|
||||||
|
request_method: string | null;
|
||||||
|
request_path: string | null;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
user_email: string | null;
|
|
||||||
user_first_name: string | null;
|
user_first_name: string | null;
|
||||||
|
user_email: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuditLogFilters {
|
export interface AuditLogFilters {
|
||||||
user_id?: number;
|
user_id?: number;
|
||||||
action?: string;
|
action?: string;
|
||||||
resource?: string;
|
resource_type?: string;
|
||||||
|
status?: string;
|
||||||
date_from?: string;
|
date_from?: string;
|
||||||
date_to?: string;
|
date_to?: string;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
|
|||||||
@@ -299,7 +299,10 @@
|
|||||||
"extraDevicesIncluded_other": "Incl. {{count}} extra dev.",
|
"extraDevicesIncluded_other": "Incl. {{count}} extra dev.",
|
||||||
"baseTariff": "Tariff",
|
"baseTariff": "Tariff",
|
||||||
"perMonth": "/mo",
|
"perMonth": "/mo",
|
||||||
"summary": "Summary",
|
"summary": {
|
||||||
|
"period": "Period: {{label}}",
|
||||||
|
"traffic": "Traffic: {{gb}} GB"
|
||||||
|
},
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"purchase": "Purchase",
|
"purchase": "Purchase",
|
||||||
"step": "Step {{current}} of {{total}}",
|
"step": "Step {{current}} of {{total}}",
|
||||||
@@ -507,10 +510,6 @@
|
|||||||
"label": "Traffic",
|
"label": "Traffic",
|
||||||
"selectVolume": "Select traffic volume",
|
"selectVolume": "Select traffic volume",
|
||||||
"default": "Default: {{label}}"
|
"default": "Default: {{label}}"
|
||||||
},
|
|
||||||
"summary": {
|
|
||||||
"period": "Period: {{label}}",
|
|
||||||
"traffic": "Traffic: {{gb}} GB"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"balance": {
|
"balance": {
|
||||||
@@ -520,7 +519,41 @@
|
|||||||
"topUpBalance": "Top Up Balance",
|
"topUpBalance": "Top Up Balance",
|
||||||
"enterAmount": "Enter amount",
|
"enterAmount": "Enter amount",
|
||||||
"paymentMethod": "Payment Method",
|
"paymentMethod": "Payment Method",
|
||||||
"paymentMethods": "Payment Methods",
|
"paymentMethods": {
|
||||||
|
"yookassa": {
|
||||||
|
"description": "Pay via YooKassa"
|
||||||
|
},
|
||||||
|
"cryptobot": {
|
||||||
|
"description": "Pay with cryptocurrency via CryptoBot"
|
||||||
|
},
|
||||||
|
"telegram_stars": {
|
||||||
|
"description": "Pay with Telegram Stars"
|
||||||
|
},
|
||||||
|
"heleket": {
|
||||||
|
"description": "Pay with cryptocurrency via Heleket"
|
||||||
|
},
|
||||||
|
"mulenpay": {
|
||||||
|
"description": "Pay via MulenPay"
|
||||||
|
},
|
||||||
|
"pal24": {
|
||||||
|
"description": "Pay via PAL24"
|
||||||
|
},
|
||||||
|
"platega": {
|
||||||
|
"description": "Pay via Platega"
|
||||||
|
},
|
||||||
|
"wata": {
|
||||||
|
"description": "Pay via Wata"
|
||||||
|
},
|
||||||
|
"cloudpayments": {
|
||||||
|
"description": "Pay with bank card via CloudPayments"
|
||||||
|
},
|
||||||
|
"freekassa": {
|
||||||
|
"description": "Pay via FreeKassa"
|
||||||
|
},
|
||||||
|
"tribute": {
|
||||||
|
"description": "Pay with bank card via Tribute"
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactionHistory": "Transaction History",
|
"transactionHistory": "Transaction History",
|
||||||
"noTransactions": "No transactions",
|
"noTransactions": "No transactions",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
@@ -562,41 +595,6 @@
|
|||||||
"topUpToComplete": "Top up your balance to complete the purchase",
|
"topUpToComplete": "Top up your balance to complete the purchase",
|
||||||
"missing": "Missing",
|
"missing": "Missing",
|
||||||
"noPaymentMethods": "No payment methods available",
|
"noPaymentMethods": "No payment methods available",
|
||||||
"paymentMethods": {
|
|
||||||
"yookassa": {
|
|
||||||
"description": "Pay via YooKassa"
|
|
||||||
},
|
|
||||||
"cryptobot": {
|
|
||||||
"description": "Pay with cryptocurrency via CryptoBot"
|
|
||||||
},
|
|
||||||
"telegram_stars": {
|
|
||||||
"description": "Pay with Telegram Stars"
|
|
||||||
},
|
|
||||||
"heleket": {
|
|
||||||
"description": "Pay with cryptocurrency via Heleket"
|
|
||||||
},
|
|
||||||
"mulenpay": {
|
|
||||||
"description": "Pay via MulenPay"
|
|
||||||
},
|
|
||||||
"pal24": {
|
|
||||||
"description": "Pay via PAL24"
|
|
||||||
},
|
|
||||||
"platega": {
|
|
||||||
"description": "Pay via Platega"
|
|
||||||
},
|
|
||||||
"wata": {
|
|
||||||
"description": "Pay via Wata"
|
|
||||||
},
|
|
||||||
"cloudpayments": {
|
|
||||||
"description": "Pay with bank card via CloudPayments"
|
|
||||||
},
|
|
||||||
"freekassa": {
|
|
||||||
"description": "Pay via FreeKassa"
|
|
||||||
},
|
|
||||||
"tribute": {
|
|
||||||
"description": "Pay with bank card via Tribute"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pendingPayments": {
|
"pendingPayments": {
|
||||||
"title": "Pending Payments",
|
"title": "Pending Payments",
|
||||||
"pay": "Pay",
|
"pay": "Pay",
|
||||||
@@ -916,7 +914,7 @@
|
|||||||
"total": "Total",
|
"total": "Total",
|
||||||
"noData": "No traffic data",
|
"noData": "No traffic data",
|
||||||
"loading": "Loading traffic data...",
|
"loading": "Loading traffic data...",
|
||||||
"noTariff": "\u2014",
|
"noTariff": "—",
|
||||||
"search": "Search by name or username",
|
"search": "Search by name or username",
|
||||||
"allTariffs": "All tariffs",
|
"allTariffs": "All tariffs",
|
||||||
"nodes": "Nodes",
|
"nodes": "Nodes",
|
||||||
@@ -1647,7 +1645,7 @@
|
|||||||
"periodsTabHint": "Add periods and prices for the tariff. Users will be able to choose from the added periods.",
|
"periodsTabHint": "Add periods and prices for the tariff. Users will be able to choose from the added periods.",
|
||||||
"addPeriodTitle": "Add period",
|
"addPeriodTitle": "Add period",
|
||||||
"daysLabel": "Days",
|
"daysLabel": "Days",
|
||||||
"priceLabel": "Price (\u20bd)",
|
"priceLabel": "Price (₽)",
|
||||||
"addButton": "Add",
|
"addButton": "Add",
|
||||||
"noPeriodsHint": "No added periods. Add at least one period.",
|
"noPeriodsHint": "No added periods. Add at least one period.",
|
||||||
"daysShort": "d.",
|
"daysShort": "d.",
|
||||||
@@ -1697,7 +1695,7 @@
|
|||||||
"dailyType": "Daily",
|
"dailyType": "Daily",
|
||||||
"periodType": "Period-based",
|
"periodType": "Period-based",
|
||||||
"dailyPriceLabel": "Price per day",
|
"dailyPriceLabel": "Price per day",
|
||||||
"currencyPerDay": "\u20bd/day",
|
"currencyPerDay": "₽/day",
|
||||||
"dailyDeductionDesc": "Charged daily from user's balance",
|
"dailyDeductionDesc": "Charged daily from user's balance",
|
||||||
"dailyPriceRequired": "Enter a price per day greater than 0",
|
"dailyPriceRequired": "Enter a price per day greater than 0",
|
||||||
"cannotSave": "Cannot save tariff:",
|
"cannotSave": "Cannot save tariff:",
|
||||||
@@ -2535,6 +2533,278 @@
|
|||||||
"purchaseDiscount": "Purchase discount",
|
"purchaseDiscount": "Purchase discount",
|
||||||
"purchaseDiscountDesc": "Discount for new users"
|
"purchaseDiscountDesc": "Discount for new users"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"title": "Roles & Permissions",
|
||||||
|
"subtitle": "Manage admin roles and their permissions",
|
||||||
|
"createRole": "Create Role",
|
||||||
|
"noRoles": "No roles found",
|
||||||
|
"systemBadge": "System",
|
||||||
|
"inactiveBadge": "Inactive",
|
||||||
|
"levelLabel": "Level",
|
||||||
|
"usersCount_one": "{{count}} user",
|
||||||
|
"usersCount_other": "{{count}} users",
|
||||||
|
"permissionsCount_one": "{{count}} permission",
|
||||||
|
"permissionsCount_other": "{{count}} permissions",
|
||||||
|
"stats": {
|
||||||
|
"totalRoles": "Total roles",
|
||||||
|
"active": "Active",
|
||||||
|
"system": "System"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"createTitle": "Create Role",
|
||||||
|
"editTitle": "Edit Role",
|
||||||
|
"close": "Close"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"name": "Role name",
|
||||||
|
"namePlaceholder": "e.g. Moderator",
|
||||||
|
"description": "Description",
|
||||||
|
"descriptionPlaceholder": "What this role is for...",
|
||||||
|
"level": "Priority level",
|
||||||
|
"levelValue": "Level value",
|
||||||
|
"levelHint": "Higher level = more authority. Users can only manage roles with a lower level than their own.",
|
||||||
|
"color": "Color",
|
||||||
|
"presets": "Permission presets",
|
||||||
|
"permissions": "Permissions",
|
||||||
|
"toggleSection": "Toggle all {{section}} permissions",
|
||||||
|
"selectedPermissions_one": "{{count}} permission selected",
|
||||||
|
"selectedPermissions_other": "{{count}} permissions selected",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"saving": "Saving...",
|
||||||
|
"save": "Save"
|
||||||
|
},
|
||||||
|
"presets": {
|
||||||
|
"moderator": "Moderator",
|
||||||
|
"marketer": "Marketer",
|
||||||
|
"support": "Support"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "Delete role?",
|
||||||
|
"text": "This role will be permanently deleted. Users with this role will lose its permissions.",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"delete": "Delete",
|
||||||
|
"deleting": "Deleting..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "Failed to load roles",
|
||||||
|
"createFailed": "Failed to create role",
|
||||||
|
"updateFailed": "Failed to update role",
|
||||||
|
"nameRequired": "Role name is required",
|
||||||
|
"deleteFailed": "Failed to delete role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roleAssign": {
|
||||||
|
"title": "Role Assignment",
|
||||||
|
"subtitle": "Assign and manage user roles",
|
||||||
|
"assignSection": "Assign Role",
|
||||||
|
"userLabel": "User",
|
||||||
|
"searchPlaceholder": "Search by name, username, Telegram ID, or email...",
|
||||||
|
"clearUser": "Clear selected user",
|
||||||
|
"noUsersFound": "No users found",
|
||||||
|
"roleLabel": "Role",
|
||||||
|
"selectRole": "Select a role...",
|
||||||
|
"expiresLabel": "Expires at (optional)",
|
||||||
|
"expiresHint": "Leave empty for permanent assignment",
|
||||||
|
"assignButton": "Assign",
|
||||||
|
"assigning": "Assigning...",
|
||||||
|
"assignSuccess": "Role assigned successfully",
|
||||||
|
"currentAssignments": "Current Assignments",
|
||||||
|
"totalAssignments_one": "{{count}} assignment total",
|
||||||
|
"totalAssignments_other": "{{count}} assignments total",
|
||||||
|
"noAssignments": "No role assignments found",
|
||||||
|
"unknownUser": "Unknown user",
|
||||||
|
"system": "System",
|
||||||
|
"permanent": "Permanent",
|
||||||
|
"expired": "expired",
|
||||||
|
"revoke": "Revoke",
|
||||||
|
"revokeAriaLabel": "Revoke role {{role}} from {{user}}",
|
||||||
|
"table": {
|
||||||
|
"user": "User",
|
||||||
|
"role": "Role",
|
||||||
|
"assignedBy": "Assigned by",
|
||||||
|
"assignedAt": "Assigned at",
|
||||||
|
"expires": "Expires",
|
||||||
|
"actions": "Actions"
|
||||||
|
},
|
||||||
|
"pagination": {
|
||||||
|
"showing": "{{from}}-{{to}} of {{total}}",
|
||||||
|
"prev": "Previous page",
|
||||||
|
"next": "Next page"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "Revoke role?",
|
||||||
|
"text": "This user will immediately lose all permissions associated with this role.",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"revoke": "Revoke",
|
||||||
|
"revoking": "Revoking..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"userRequired": "Please select a user",
|
||||||
|
"roleRequired": "Please select a role",
|
||||||
|
"assignFailed": "Failed to assign role",
|
||||||
|
"revokeFailed": "Failed to revoke role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {
|
||||||
|
"title": "Access Policies",
|
||||||
|
"subtitle": "Manage ABAC access control policies",
|
||||||
|
"createPolicy": "Create Policy",
|
||||||
|
"noPolicies": "No policies found",
|
||||||
|
"inactiveBadge": "Inactive",
|
||||||
|
"effectAllow": "Allow",
|
||||||
|
"effectDeny": "Deny",
|
||||||
|
"global": "Global",
|
||||||
|
"unknownRole": "Unknown role",
|
||||||
|
"roleLabel": "Role",
|
||||||
|
"priorityLabel": "Priority",
|
||||||
|
"stats": {
|
||||||
|
"total": "Total policies",
|
||||||
|
"allow": "Allow",
|
||||||
|
"deny": "Deny",
|
||||||
|
"active": "Active"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"createTitle": "Create Policy",
|
||||||
|
"editTitle": "Edit Policy",
|
||||||
|
"close": "Close"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"name": "Policy name",
|
||||||
|
"namePlaceholder": "e.g. Block night access",
|
||||||
|
"description": "Description",
|
||||||
|
"descriptionPlaceholder": "What this policy does...",
|
||||||
|
"effect": "Effect",
|
||||||
|
"resource": "Resource",
|
||||||
|
"selectResource": "Select a resource...",
|
||||||
|
"actions": "Actions",
|
||||||
|
"role": "Role (optional)",
|
||||||
|
"globalOption": "Global (all roles)",
|
||||||
|
"roleHint": "Leave as Global to apply the policy to all roles.",
|
||||||
|
"priority": "Priority",
|
||||||
|
"priorityHint": "Higher priority policies are evaluated first. Deny overrides Allow at equal priority.",
|
||||||
|
"conditions": "Conditions",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"saving": "Saving...",
|
||||||
|
"save": "Save"
|
||||||
|
},
|
||||||
|
"conditions": {
|
||||||
|
"timeRange": "Time range",
|
||||||
|
"timeStart": "Start time",
|
||||||
|
"timeEnd": "End time",
|
||||||
|
"ipWhitelist": "IP whitelist",
|
||||||
|
"ipPlaceholder": "Enter IP and press Enter...",
|
||||||
|
"removeIp": "Remove {{ip}}",
|
||||||
|
"ipCount_one": "{{count}} IP",
|
||||||
|
"ipCount_other": "{{count}} IPs",
|
||||||
|
"rateLimit": "Rate limit",
|
||||||
|
"rateLimitValue": "Rate limit value",
|
||||||
|
"rateValue": "{{count}}/hr",
|
||||||
|
"perHour": "actions per hour"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "Delete policy?",
|
||||||
|
"text": "This policy will be permanently deleted. Access control rules will be recalculated.",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"delete": "Delete",
|
||||||
|
"deleting": "Deleting..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "Failed to load policies",
|
||||||
|
"createFailed": "Failed to create policy",
|
||||||
|
"updateFailed": "Failed to update policy",
|
||||||
|
"nameRequired": "Policy name is required",
|
||||||
|
"resourceRequired": "Please select a resource",
|
||||||
|
"actionsRequired": "Please select at least one action",
|
||||||
|
"deleteFailed": "Failed to delete policy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"auditLog": {
|
||||||
|
"title": "Audit Log",
|
||||||
|
"subtitle": "Review system activity and access history",
|
||||||
|
"back": "Back",
|
||||||
|
"exportCsv": "Export CSV",
|
||||||
|
"exportError": "Failed to export",
|
||||||
|
"exporting": "Exporting...",
|
||||||
|
"refresh": "Refresh",
|
||||||
|
"unknownUser": "Unknown user",
|
||||||
|
"noEntries": "No audit log entries found",
|
||||||
|
"totalEntries_one": "{{count}} entry",
|
||||||
|
"totalEntries_other": "{{count}} entries",
|
||||||
|
"autoRefresh": {
|
||||||
|
"label": "Auto-refresh",
|
||||||
|
"tooltip": "Auto-refresh every 30 seconds"
|
||||||
|
},
|
||||||
|
"filters": {
|
||||||
|
"title": "Filters",
|
||||||
|
"active": "Active",
|
||||||
|
"action": "Action",
|
||||||
|
"actionPlaceholder": "Search by action...",
|
||||||
|
"resource": "Resource type",
|
||||||
|
"allResources": "All resources",
|
||||||
|
"status": "Status",
|
||||||
|
"allStatuses": "All statuses",
|
||||||
|
"dateFrom": "Date from",
|
||||||
|
"dateTo": "Date to",
|
||||||
|
"apply": "Apply",
|
||||||
|
"clear": "Clear"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"success": "Success",
|
||||||
|
"denied": "Denied",
|
||||||
|
"error": "Error"
|
||||||
|
},
|
||||||
|
"resourceTypes": {
|
||||||
|
"users": "Users",
|
||||||
|
"tickets": "Tickets",
|
||||||
|
"roles": "Roles",
|
||||||
|
"policies": "Policies",
|
||||||
|
"settings": "Settings",
|
||||||
|
"broadcasts": "Broadcasts",
|
||||||
|
"tariffs": "Tariffs",
|
||||||
|
"servers": "Servers",
|
||||||
|
"payments": "Payments",
|
||||||
|
"campaigns": "Campaigns",
|
||||||
|
"promocodes": "Promo Codes"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"userAgent": "User Agent",
|
||||||
|
"requestPath": "Request Path",
|
||||||
|
"ipAddress": "IP Address",
|
||||||
|
"timestamp": "Timestamp",
|
||||||
|
"before": "Before",
|
||||||
|
"after": "After",
|
||||||
|
"fullDetails": "Full Details"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"justNow": "Just now",
|
||||||
|
"minutesAgo_one": "{{count}} min ago",
|
||||||
|
"minutesAgo_other": "{{count}} min ago",
|
||||||
|
"hoursAgo_one": "{{count}} hr ago",
|
||||||
|
"hoursAgo_other": "{{count}} hrs ago",
|
||||||
|
"daysAgo_one": "{{count}} day ago",
|
||||||
|
"daysAgo_other": "{{count}} days ago"
|
||||||
|
},
|
||||||
|
"pagination": {
|
||||||
|
"pageSize": "Per page:",
|
||||||
|
"pageOf": "{{current}} / {{total}}",
|
||||||
|
"first": "First page",
|
||||||
|
"previous": "Previous page",
|
||||||
|
"next": "Next page",
|
||||||
|
"last": "Last page"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "Failed to load audit log",
|
||||||
|
"retry": "Try again"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"adminUpdates": {
|
"adminUpdates": {
|
||||||
@@ -2929,278 +3199,6 @@
|
|||||||
"unhealthy": "Unhealthy",
|
"unhealthy": "Unhealthy",
|
||||||
"components": "Components",
|
"components": "Components",
|
||||||
"uptime": "Uptime"
|
"uptime": "Uptime"
|
||||||
},
|
|
||||||
"roles": {
|
|
||||||
"title": "Roles & Permissions",
|
|
||||||
"subtitle": "Manage admin roles and their permissions",
|
|
||||||
"createRole": "Create Role",
|
|
||||||
"noRoles": "No roles found",
|
|
||||||
"systemBadge": "System",
|
|
||||||
"inactiveBadge": "Inactive",
|
|
||||||
"levelLabel": "Level",
|
|
||||||
"usersCount_one": "{{count}} user",
|
|
||||||
"usersCount_other": "{{count}} users",
|
|
||||||
"permissionsCount_one": "{{count}} permission",
|
|
||||||
"permissionsCount_other": "{{count}} permissions",
|
|
||||||
"stats": {
|
|
||||||
"totalRoles": "Total roles",
|
|
||||||
"active": "Active",
|
|
||||||
"system": "System"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"edit": "Edit",
|
|
||||||
"delete": "Delete"
|
|
||||||
},
|
|
||||||
"modal": {
|
|
||||||
"createTitle": "Create Role",
|
|
||||||
"editTitle": "Edit Role",
|
|
||||||
"close": "Close"
|
|
||||||
},
|
|
||||||
"form": {
|
|
||||||
"name": "Role name",
|
|
||||||
"namePlaceholder": "e.g. Moderator",
|
|
||||||
"description": "Description",
|
|
||||||
"descriptionPlaceholder": "What this role is for...",
|
|
||||||
"level": "Priority level",
|
|
||||||
"levelValue": "Level value",
|
|
||||||
"levelHint": "Higher level = more authority. Users can only manage roles with a lower level than their own.",
|
|
||||||
"color": "Color",
|
|
||||||
"presets": "Permission presets",
|
|
||||||
"permissions": "Permissions",
|
|
||||||
"toggleSection": "Toggle all {{section}} permissions",
|
|
||||||
"selectedPermissions_one": "{{count}} permission selected",
|
|
||||||
"selectedPermissions_other": "{{count}} permissions selected",
|
|
||||||
"cancel": "Cancel",
|
|
||||||
"saving": "Saving...",
|
|
||||||
"save": "Save"
|
|
||||||
},
|
|
||||||
"presets": {
|
|
||||||
"moderator": "Moderator",
|
|
||||||
"marketer": "Marketer",
|
|
||||||
"support": "Support"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "Delete role?",
|
|
||||||
"text": "This role will be permanently deleted. Users with this role will lose its permissions.",
|
|
||||||
"cancel": "Cancel",
|
|
||||||
"delete": "Delete",
|
|
||||||
"deleting": "Deleting..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "Failed to load roles",
|
|
||||||
"createFailed": "Failed to create role",
|
|
||||||
"updateFailed": "Failed to update role",
|
|
||||||
"nameRequired": "Role name is required",
|
|
||||||
"deleteFailed": "Failed to delete role"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"roleAssign": {
|
|
||||||
"title": "Role Assignment",
|
|
||||||
"subtitle": "Assign and manage user roles",
|
|
||||||
"assignSection": "Assign Role",
|
|
||||||
"userLabel": "User",
|
|
||||||
"searchPlaceholder": "Search by name, username, Telegram ID, or email...",
|
|
||||||
"clearUser": "Clear selected user",
|
|
||||||
"noUsersFound": "No users found",
|
|
||||||
"roleLabel": "Role",
|
|
||||||
"selectRole": "Select a role...",
|
|
||||||
"expiresLabel": "Expires at (optional)",
|
|
||||||
"expiresHint": "Leave empty for permanent assignment",
|
|
||||||
"assignButton": "Assign",
|
|
||||||
"assigning": "Assigning...",
|
|
||||||
"assignSuccess": "Role assigned successfully",
|
|
||||||
"currentAssignments": "Current Assignments",
|
|
||||||
"totalAssignments_one": "{{count}} assignment total",
|
|
||||||
"totalAssignments_other": "{{count}} assignments total",
|
|
||||||
"noAssignments": "No role assignments found",
|
|
||||||
"unknownUser": "Unknown user",
|
|
||||||
"system": "System",
|
|
||||||
"permanent": "Permanent",
|
|
||||||
"expired": "expired",
|
|
||||||
"revoke": "Revoke",
|
|
||||||
"revokeAriaLabel": "Revoke role {{role}} from {{user}}",
|
|
||||||
"table": {
|
|
||||||
"user": "User",
|
|
||||||
"role": "Role",
|
|
||||||
"assignedBy": "Assigned by",
|
|
||||||
"assignedAt": "Assigned at",
|
|
||||||
"expires": "Expires",
|
|
||||||
"actions": "Actions"
|
|
||||||
},
|
|
||||||
"pagination": {
|
|
||||||
"showing": "{{from}}-{{to}} of {{total}}",
|
|
||||||
"prev": "Previous page",
|
|
||||||
"next": "Next page"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "Revoke role?",
|
|
||||||
"text": "This user will immediately lose all permissions associated with this role.",
|
|
||||||
"cancel": "Cancel",
|
|
||||||
"revoke": "Revoke",
|
|
||||||
"revoking": "Revoking..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"userRequired": "Please select a user",
|
|
||||||
"roleRequired": "Please select a role",
|
|
||||||
"assignFailed": "Failed to assign role",
|
|
||||||
"revokeFailed": "Failed to revoke role"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"policies": {
|
|
||||||
"title": "Access Policies",
|
|
||||||
"subtitle": "Manage ABAC access control policies",
|
|
||||||
"createPolicy": "Create Policy",
|
|
||||||
"noPolicies": "No policies found",
|
|
||||||
"inactiveBadge": "Inactive",
|
|
||||||
"effectAllow": "Allow",
|
|
||||||
"effectDeny": "Deny",
|
|
||||||
"global": "Global",
|
|
||||||
"unknownRole": "Unknown role",
|
|
||||||
"roleLabel": "Role",
|
|
||||||
"priorityLabel": "Priority",
|
|
||||||
"stats": {
|
|
||||||
"total": "Total policies",
|
|
||||||
"allow": "Allow",
|
|
||||||
"deny": "Deny",
|
|
||||||
"active": "Active"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"edit": "Edit",
|
|
||||||
"delete": "Delete"
|
|
||||||
},
|
|
||||||
"modal": {
|
|
||||||
"createTitle": "Create Policy",
|
|
||||||
"editTitle": "Edit Policy",
|
|
||||||
"close": "Close"
|
|
||||||
},
|
|
||||||
"form": {
|
|
||||||
"name": "Policy name",
|
|
||||||
"namePlaceholder": "e.g. Block night access",
|
|
||||||
"description": "Description",
|
|
||||||
"descriptionPlaceholder": "What this policy does...",
|
|
||||||
"effect": "Effect",
|
|
||||||
"resource": "Resource",
|
|
||||||
"selectResource": "Select a resource...",
|
|
||||||
"actions": "Actions",
|
|
||||||
"role": "Role (optional)",
|
|
||||||
"globalOption": "Global (all roles)",
|
|
||||||
"roleHint": "Leave as Global to apply the policy to all roles.",
|
|
||||||
"priority": "Priority",
|
|
||||||
"priorityHint": "Higher priority policies are evaluated first. Deny overrides Allow at equal priority.",
|
|
||||||
"conditions": "Conditions",
|
|
||||||
"cancel": "Cancel",
|
|
||||||
"saving": "Saving...",
|
|
||||||
"save": "Save"
|
|
||||||
},
|
|
||||||
"conditions": {
|
|
||||||
"timeRange": "Time range",
|
|
||||||
"timeStart": "Start time",
|
|
||||||
"timeEnd": "End time",
|
|
||||||
"ipWhitelist": "IP whitelist",
|
|
||||||
"ipPlaceholder": "Enter IP and press Enter...",
|
|
||||||
"removeIp": "Remove {{ip}}",
|
|
||||||
"ipCount_one": "{{count}} IP",
|
|
||||||
"ipCount_other": "{{count}} IPs",
|
|
||||||
"rateLimit": "Rate limit",
|
|
||||||
"rateLimitValue": "Rate limit value",
|
|
||||||
"rateValue": "{{count}}/hr",
|
|
||||||
"perHour": "actions per hour"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "Delete policy?",
|
|
||||||
"text": "This policy will be permanently deleted. Access control rules will be recalculated.",
|
|
||||||
"cancel": "Cancel",
|
|
||||||
"delete": "Delete",
|
|
||||||
"deleting": "Deleting..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "Failed to load policies",
|
|
||||||
"createFailed": "Failed to create policy",
|
|
||||||
"updateFailed": "Failed to update policy",
|
|
||||||
"nameRequired": "Policy name is required",
|
|
||||||
"resourceRequired": "Please select a resource",
|
|
||||||
"actionsRequired": "Please select at least one action",
|
|
||||||
"deleteFailed": "Failed to delete policy"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"auditLog": {
|
|
||||||
"title": "Audit Log",
|
|
||||||
"subtitle": "Review system activity and access history",
|
|
||||||
"back": "Back",
|
|
||||||
"exportCsv": "Export CSV",
|
|
||||||
"exportError": "Failed to export",
|
|
||||||
"exporting": "Exporting...",
|
|
||||||
"refresh": "Refresh",
|
|
||||||
"unknownUser": "Unknown user",
|
|
||||||
"noEntries": "No audit log entries found",
|
|
||||||
"totalEntries_one": "{{count}} entry",
|
|
||||||
"totalEntries_other": "{{count}} entries",
|
|
||||||
"autoRefresh": {
|
|
||||||
"label": "Auto-refresh",
|
|
||||||
"tooltip": "Auto-refresh every 30 seconds"
|
|
||||||
},
|
|
||||||
"filters": {
|
|
||||||
"title": "Filters",
|
|
||||||
"active": "Active",
|
|
||||||
"action": "Action",
|
|
||||||
"actionPlaceholder": "Search by action...",
|
|
||||||
"resource": "Resource type",
|
|
||||||
"allResources": "All resources",
|
|
||||||
"status": "Status",
|
|
||||||
"allStatuses": "All statuses",
|
|
||||||
"dateFrom": "Date from",
|
|
||||||
"dateTo": "Date to",
|
|
||||||
"apply": "Apply",
|
|
||||||
"clear": "Clear"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"success": "Success",
|
|
||||||
"denied": "Denied",
|
|
||||||
"error": "Error"
|
|
||||||
},
|
|
||||||
"resourceTypes": {
|
|
||||||
"users": "Users",
|
|
||||||
"tickets": "Tickets",
|
|
||||||
"roles": "Roles",
|
|
||||||
"policies": "Policies",
|
|
||||||
"settings": "Settings",
|
|
||||||
"broadcasts": "Broadcasts",
|
|
||||||
"tariffs": "Tariffs",
|
|
||||||
"servers": "Servers",
|
|
||||||
"payments": "Payments",
|
|
||||||
"campaigns": "Campaigns",
|
|
||||||
"promocodes": "Promo Codes"
|
|
||||||
},
|
|
||||||
"details": {
|
|
||||||
"userAgent": "User Agent",
|
|
||||||
"requestPath": "Request Path",
|
|
||||||
"ipAddress": "IP Address",
|
|
||||||
"timestamp": "Timestamp",
|
|
||||||
"before": "Before",
|
|
||||||
"after": "After",
|
|
||||||
"fullDetails": "Full Details"
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"justNow": "Just now",
|
|
||||||
"minutesAgo_one": "{{count}} min ago",
|
|
||||||
"minutesAgo_other": "{{count}} min ago",
|
|
||||||
"hoursAgo_one": "{{count}} hr ago",
|
|
||||||
"hoursAgo_other": "{{count}} hrs ago",
|
|
||||||
"daysAgo_one": "{{count}} day ago",
|
|
||||||
"daysAgo_other": "{{count}} days ago"
|
|
||||||
},
|
|
||||||
"pagination": {
|
|
||||||
"pageSize": "Per page:",
|
|
||||||
"pageOf": "{{current}} / {{total}}",
|
|
||||||
"first": "First page",
|
|
||||||
"previous": "Previous page",
|
|
||||||
"next": "Next page",
|
|
||||||
"last": "Last page"
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "Failed to load audit log",
|
|
||||||
"retry": "Try again"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
|
|||||||
@@ -280,7 +280,10 @@
|
|||||||
"selectServers": "انتخاب سرورها",
|
"selectServers": "انتخاب سرورها",
|
||||||
"selectDevices": "انتخاب دستگاهها",
|
"selectDevices": "انتخاب دستگاهها",
|
||||||
"perDevice": "/ دستگاه",
|
"perDevice": "/ دستگاه",
|
||||||
"summary": "خلاصه",
|
"summary": {
|
||||||
|
"period": "دوره: {{label}}",
|
||||||
|
"traffic": "ترافیک: {{gb}} GB"
|
||||||
|
},
|
||||||
"total": "جمع کل",
|
"total": "جمع کل",
|
||||||
"purchase": "خرید",
|
"purchase": "خرید",
|
||||||
"step": "مرحله {{current}} از {{total}}",
|
"step": "مرحله {{current}} از {{total}}",
|
||||||
@@ -392,10 +395,6 @@
|
|||||||
"selectVolume": "انتخاب حجم ترافیک",
|
"selectVolume": "انتخاب حجم ترافیک",
|
||||||
"default": "پیشفرض: {{label}}"
|
"default": "پیشفرض: {{label}}"
|
||||||
},
|
},
|
||||||
"summary": {
|
|
||||||
"period": "دوره: {{label}}",
|
|
||||||
"traffic": "ترافیک: {{gb}} GB"
|
|
||||||
},
|
|
||||||
"confirmDeleteAllDevices": "همه دستگاهها حذف شوند؟",
|
"confirmDeleteAllDevices": "همه دستگاهها حذف شوند؟",
|
||||||
"confirmDeleteDevice": "این دستگاه حذف شود؟",
|
"confirmDeleteDevice": "این دستگاه حذف شود؟",
|
||||||
"currentTariff": "فعلی",
|
"currentTariff": "فعلی",
|
||||||
@@ -795,7 +794,7 @@
|
|||||||
"total": "کل",
|
"total": "کل",
|
||||||
"noData": "داده ترافیکی موجود نیست",
|
"noData": "داده ترافیکی موجود نیست",
|
||||||
"loading": "در حال بارگذاری دادههای ترافیک...",
|
"loading": "در حال بارگذاری دادههای ترافیک...",
|
||||||
"noTariff": "\u2014",
|
"noTariff": "—",
|
||||||
"search": "جستجو بر اساس نام یا نام کاربری",
|
"search": "جستجو بر اساس نام یا نام کاربری",
|
||||||
"allTariffs": "همه تعرفهها",
|
"allTariffs": "همه تعرفهها",
|
||||||
"nodes": "نودها",
|
"nodes": "نودها",
|
||||||
@@ -2325,6 +2324,269 @@
|
|||||||
"lightness": "روشنایی",
|
"lightness": "روشنایی",
|
||||||
"quickPresets": "پیشتنظیمهای سریع",
|
"quickPresets": "پیشتنظیمهای سریع",
|
||||||
"saturation": "اشباع"
|
"saturation": "اشباع"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"title": "نقشها و مجوزها",
|
||||||
|
"subtitle": "مدیریت نقشهای مدیران و مجوزهای آنها",
|
||||||
|
"createRole": "ایجاد نقش",
|
||||||
|
"noRoles": "نقشی یافت نشد",
|
||||||
|
"systemBadge": "سیستمی",
|
||||||
|
"inactiveBadge": "غیرفعال",
|
||||||
|
"levelLabel": "سطح",
|
||||||
|
"usersCount_other": "{{count}} کاربر",
|
||||||
|
"permissionsCount_other": "{{count}} مجوز",
|
||||||
|
"stats": {
|
||||||
|
"totalRoles": "کل نقشها",
|
||||||
|
"active": "فعال",
|
||||||
|
"system": "سیستمی"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"edit": "ویرایش",
|
||||||
|
"delete": "حذف"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"createTitle": "ایجاد نقش",
|
||||||
|
"editTitle": "ویرایش نقش",
|
||||||
|
"close": "بستن"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"name": "نام نقش",
|
||||||
|
"namePlaceholder": "مثلاً مدیر محتوا",
|
||||||
|
"description": "توضیحات",
|
||||||
|
"descriptionPlaceholder": "کاربرد این نقش...",
|
||||||
|
"level": "سطح اولویت",
|
||||||
|
"levelValue": "مقدار سطح",
|
||||||
|
"levelHint": "سطح بالاتر = اختیارات بیشتر. کاربران فقط میتوانند نقشهایی با سطح پایینتر از خود را مدیریت کنند.",
|
||||||
|
"color": "رنگ",
|
||||||
|
"presets": "الگوهای مجوز",
|
||||||
|
"permissions": "مجوزها",
|
||||||
|
"toggleSection": "تغییر وضعیت تمام مجوزهای {{section}}",
|
||||||
|
"selectedPermissions_other": "{{count}} مجوز انتخاب شده",
|
||||||
|
"cancel": "لغو",
|
||||||
|
"saving": "در حال ذخیره...",
|
||||||
|
"save": "ذخیره"
|
||||||
|
},
|
||||||
|
"presets": {
|
||||||
|
"moderator": "مدیر محتوا",
|
||||||
|
"marketer": "بازاریاب",
|
||||||
|
"support": "پشتیبانی"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "حذف نقش؟",
|
||||||
|
"text": "این نقش برای همیشه حذف خواهد شد. کاربران دارای این نقش مجوزهای آن را از دست خواهند داد.",
|
||||||
|
"cancel": "لغو",
|
||||||
|
"delete": "حذف",
|
||||||
|
"deleting": "در حال حذف..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "بارگذاری نقشها ناموفق بود",
|
||||||
|
"createFailed": "ایجاد نقش ناموفق بود",
|
||||||
|
"updateFailed": "بهروزرسانی نقش ناموفق بود",
|
||||||
|
"nameRequired": "نام نقش الزامی است",
|
||||||
|
"deleteFailed": "حذف نقش ناموفق بود"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roleAssign": {
|
||||||
|
"title": "تخصیص نقش",
|
||||||
|
"subtitle": "تخصیص و مدیریت نقشهای کاربران",
|
||||||
|
"assignSection": "تخصیص نقش",
|
||||||
|
"userLabel": "کاربر",
|
||||||
|
"searchPlaceholder": "جستجو بر اساس نام، نام کاربری، شناسه تلگرام یا ایمیل...",
|
||||||
|
"clearUser": "پاک کردن کاربر انتخابشده",
|
||||||
|
"noUsersFound": "کاربری یافت نشد",
|
||||||
|
"roleLabel": "نقش",
|
||||||
|
"selectRole": "یک نقش انتخاب کنید...",
|
||||||
|
"expiresLabel": "تاریخ انقضا (اختیاری)",
|
||||||
|
"expiresHint": "برای تخصیص دائمی خالی بگذارید",
|
||||||
|
"assignButton": "تخصیص",
|
||||||
|
"assigning": "در حال تخصیص...",
|
||||||
|
"assignSuccess": "نقش با موفقیت تخصیص داده شد",
|
||||||
|
"currentAssignments": "تخصیصهای فعلی",
|
||||||
|
"totalAssignments_other": "{{count}} تخصیص",
|
||||||
|
"noAssignments": "تخصیص نقشی یافت نشد",
|
||||||
|
"unknownUser": "کاربر ناشناخته",
|
||||||
|
"system": "سیستم",
|
||||||
|
"permanent": "دائمی",
|
||||||
|
"expired": "منقضی شده",
|
||||||
|
"revoke": "لغو",
|
||||||
|
"revokeAriaLabel": "لغو نقش {{role}} از {{user}}",
|
||||||
|
"table": {
|
||||||
|
"user": "کاربر",
|
||||||
|
"role": "نقش",
|
||||||
|
"assignedBy": "تخصیصدهنده",
|
||||||
|
"assignedAt": "تاریخ تخصیص",
|
||||||
|
"expires": "انقضا",
|
||||||
|
"actions": "عملیات"
|
||||||
|
},
|
||||||
|
"pagination": {
|
||||||
|
"showing": "{{from}}-{{to}} از {{total}}",
|
||||||
|
"prev": "صفحه قبل",
|
||||||
|
"next": "صفحه بعد"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "لغو نقش؟",
|
||||||
|
"text": "این کاربر فوراً تمام مجوزهای مرتبط با این نقش را از دست خواهد داد.",
|
||||||
|
"cancel": "لغو",
|
||||||
|
"revoke": "لغو نقش",
|
||||||
|
"revoking": "در حال لغو..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"userRequired": "لطفاً یک کاربر انتخاب کنید",
|
||||||
|
"roleRequired": "لطفاً یک نقش انتخاب کنید",
|
||||||
|
"assignFailed": "تخصیص نقش ناموفق بود",
|
||||||
|
"revokeFailed": "لغو نقش ناموفق بود"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {
|
||||||
|
"title": "سیاستهای دسترسی",
|
||||||
|
"subtitle": "مدیریت سیاستهای کنترل دسترسی ABAC",
|
||||||
|
"createPolicy": "ایجاد سیاست",
|
||||||
|
"noPolicies": "سیاستی یافت نشد",
|
||||||
|
"inactiveBadge": "غیرفعال",
|
||||||
|
"effectAllow": "اجازه",
|
||||||
|
"effectDeny": "رد",
|
||||||
|
"global": "سراسری",
|
||||||
|
"unknownRole": "نقش ناشناخته",
|
||||||
|
"roleLabel": "نقش",
|
||||||
|
"priorityLabel": "اولویت",
|
||||||
|
"stats": {
|
||||||
|
"total": "کل سیاستها",
|
||||||
|
"allow": "اجازه",
|
||||||
|
"deny": "رد",
|
||||||
|
"active": "فعال"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"edit": "ویرایش",
|
||||||
|
"delete": "حذف"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"createTitle": "ایجاد سیاست",
|
||||||
|
"editTitle": "ویرایش سیاست",
|
||||||
|
"close": "بستن"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"name": "نام سیاست",
|
||||||
|
"namePlaceholder": "مثلاً مسدودسازی دسترسی شبانه",
|
||||||
|
"description": "توضیحات",
|
||||||
|
"descriptionPlaceholder": "عملکرد این سیاست...",
|
||||||
|
"effect": "اثر",
|
||||||
|
"resource": "منبع",
|
||||||
|
"selectResource": "یک منبع انتخاب کنید...",
|
||||||
|
"actions": "عملیات",
|
||||||
|
"role": "نقش (اختیاری)",
|
||||||
|
"globalOption": "سراسری (همه نقشها)",
|
||||||
|
"roleHint": "سراسری بگذارید تا سیاست برای همه نقشها اعمال شود.",
|
||||||
|
"priority": "اولویت",
|
||||||
|
"priorityHint": "سیاستهای با اولویت بالاتر ابتدا ارزیابی میشوند. رد در اولویت مساوی بر اجازه غلبه میکند.",
|
||||||
|
"conditions": "شرایط",
|
||||||
|
"cancel": "لغو",
|
||||||
|
"saving": "در حال ذخیره...",
|
||||||
|
"save": "ذخیره"
|
||||||
|
},
|
||||||
|
"conditions": {
|
||||||
|
"timeRange": "بازه زمانی",
|
||||||
|
"timeStart": "زمان شروع",
|
||||||
|
"timeEnd": "زمان پایان",
|
||||||
|
"ipWhitelist": "لیست سفید IP",
|
||||||
|
"ipPlaceholder": "IP را وارد کنید و Enter بزنید...",
|
||||||
|
"removeIp": "حذف {{ip}}",
|
||||||
|
"ipCount_other": "{{count}} IP",
|
||||||
|
"rateLimit": "محدودیت نرخ",
|
||||||
|
"rateLimitValue": "مقدار محدودیت نرخ",
|
||||||
|
"rateValue": "{{count}}/ساعت",
|
||||||
|
"perHour": "عملیات در ساعت"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "حذف سیاست؟",
|
||||||
|
"text": "این سیاست برای همیشه حذف خواهد شد. قوانین کنترل دسترسی مجدداً محاسبه خواهند شد.",
|
||||||
|
"cancel": "لغو",
|
||||||
|
"delete": "حذف",
|
||||||
|
"deleting": "در حال حذف..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "بارگذاری سیاستها ناموفق بود",
|
||||||
|
"createFailed": "ایجاد سیاست ناموفق بود",
|
||||||
|
"updateFailed": "بهروزرسانی سیاست ناموفق بود",
|
||||||
|
"nameRequired": "نام سیاست الزامی است",
|
||||||
|
"resourceRequired": "لطفاً یک منبع انتخاب کنید",
|
||||||
|
"actionsRequired": "لطفاً حداقل یک عملیات انتخاب کنید",
|
||||||
|
"deleteFailed": "حذف سیاست ناموفق بود"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"auditLog": {
|
||||||
|
"title": "گزارش بازرسی",
|
||||||
|
"subtitle": "بررسی فعالیت سیستم و تاریخچه دسترسی",
|
||||||
|
"back": "بازگشت",
|
||||||
|
"exportCsv": "خروجی CSV",
|
||||||
|
"exportError": "خطا در خروجی",
|
||||||
|
"exporting": "در حال خروجی...",
|
||||||
|
"refresh": "بازخوانی",
|
||||||
|
"unknownUser": "کاربر ناشناخته",
|
||||||
|
"noEntries": "رکوردی در گزارش بازرسی یافت نشد",
|
||||||
|
"totalEntries_other": "{{count}} رکورد",
|
||||||
|
"autoRefresh": {
|
||||||
|
"label": "بازخوانی خودکار",
|
||||||
|
"tooltip": "بازخوانی خودکار هر ۳۰ ثانیه"
|
||||||
|
},
|
||||||
|
"filters": {
|
||||||
|
"title": "فیلترها",
|
||||||
|
"active": "فعال",
|
||||||
|
"action": "عملیات",
|
||||||
|
"actionPlaceholder": "جستجو بر اساس عملیات...",
|
||||||
|
"resource": "نوع منبع",
|
||||||
|
"allResources": "همه منابع",
|
||||||
|
"status": "وضعیت",
|
||||||
|
"allStatuses": "همه وضعیتها",
|
||||||
|
"dateFrom": "از تاریخ",
|
||||||
|
"dateTo": "تا تاریخ",
|
||||||
|
"apply": "اعمال",
|
||||||
|
"clear": "پاک کردن"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"success": "موفق",
|
||||||
|
"denied": "رد شده",
|
||||||
|
"error": "خطا"
|
||||||
|
},
|
||||||
|
"resourceTypes": {
|
||||||
|
"users": "کاربران",
|
||||||
|
"tickets": "تیکتها",
|
||||||
|
"roles": "نقشها",
|
||||||
|
"policies": "سیاستها",
|
||||||
|
"settings": "تنظیمات",
|
||||||
|
"broadcasts": "پیامرسانی",
|
||||||
|
"tariffs": "تعرفهها",
|
||||||
|
"servers": "سرورها",
|
||||||
|
"payments": "پرداختها",
|
||||||
|
"campaigns": "کمپینها",
|
||||||
|
"promocodes": "کدهای تخفیف"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"userAgent": "عامل کاربر",
|
||||||
|
"requestPath": "مسیر درخواست",
|
||||||
|
"ipAddress": "آدرس IP",
|
||||||
|
"timestamp": "زمان",
|
||||||
|
"before": "قبل",
|
||||||
|
"after": "بعد",
|
||||||
|
"fullDetails": "جزئیات کامل"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"justNow": "همین الان",
|
||||||
|
"minutesAgo_other": "{{count}} دقیقه پیش",
|
||||||
|
"hoursAgo_other": "{{count}} ساعت پیش",
|
||||||
|
"daysAgo_other": "{{count}} روز پیش"
|
||||||
|
},
|
||||||
|
"pagination": {
|
||||||
|
"pageSize": "در هر صفحه:",
|
||||||
|
"pageOf": "{{current}} / {{total}}",
|
||||||
|
"first": "صفحه اول",
|
||||||
|
"previous": "صفحه قبل",
|
||||||
|
"next": "صفحه بعد",
|
||||||
|
"last": "صفحه آخر"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "بارگذاری گزارش بازرسی ناموفق بود",
|
||||||
|
"retry": "تلاش مجدد"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"adminUpdates": {
|
"adminUpdates": {
|
||||||
@@ -2792,269 +3054,6 @@
|
|||||||
"node": "گره",
|
"node": "گره",
|
||||||
"requests": "درخواستها",
|
"requests": "درخواستها",
|
||||||
"ipHistory": "تاریخچه IP"
|
"ipHistory": "تاریخچه IP"
|
||||||
},
|
|
||||||
"roles": {
|
|
||||||
"title": "نقشها و مجوزها",
|
|
||||||
"subtitle": "مدیریت نقشهای مدیران و مجوزهای آنها",
|
|
||||||
"createRole": "ایجاد نقش",
|
|
||||||
"noRoles": "نقشی یافت نشد",
|
|
||||||
"systemBadge": "سیستمی",
|
|
||||||
"inactiveBadge": "غیرفعال",
|
|
||||||
"levelLabel": "سطح",
|
|
||||||
"usersCount_other": "{{count}} کاربر",
|
|
||||||
"permissionsCount_other": "{{count}} مجوز",
|
|
||||||
"stats": {
|
|
||||||
"totalRoles": "کل نقشها",
|
|
||||||
"active": "فعال",
|
|
||||||
"system": "سیستمی"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"edit": "ویرایش",
|
|
||||||
"delete": "حذف"
|
|
||||||
},
|
|
||||||
"modal": {
|
|
||||||
"createTitle": "ایجاد نقش",
|
|
||||||
"editTitle": "ویرایش نقش",
|
|
||||||
"close": "بستن"
|
|
||||||
},
|
|
||||||
"form": {
|
|
||||||
"name": "نام نقش",
|
|
||||||
"namePlaceholder": "مثلاً مدیر محتوا",
|
|
||||||
"description": "توضیحات",
|
|
||||||
"descriptionPlaceholder": "کاربرد این نقش...",
|
|
||||||
"level": "سطح اولویت",
|
|
||||||
"levelValue": "مقدار سطح",
|
|
||||||
"levelHint": "سطح بالاتر = اختیارات بیشتر. کاربران فقط میتوانند نقشهایی با سطح پایینتر از خود را مدیریت کنند.",
|
|
||||||
"color": "رنگ",
|
|
||||||
"presets": "الگوهای مجوز",
|
|
||||||
"permissions": "مجوزها",
|
|
||||||
"toggleSection": "تغییر وضعیت تمام مجوزهای {{section}}",
|
|
||||||
"selectedPermissions_other": "{{count}} مجوز انتخاب شده",
|
|
||||||
"cancel": "لغو",
|
|
||||||
"saving": "در حال ذخیره...",
|
|
||||||
"save": "ذخیره"
|
|
||||||
},
|
|
||||||
"presets": {
|
|
||||||
"moderator": "مدیر محتوا",
|
|
||||||
"marketer": "بازاریاب",
|
|
||||||
"support": "پشتیبانی"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "حذف نقش؟",
|
|
||||||
"text": "این نقش برای همیشه حذف خواهد شد. کاربران دارای این نقش مجوزهای آن را از دست خواهند داد.",
|
|
||||||
"cancel": "لغو",
|
|
||||||
"delete": "حذف",
|
|
||||||
"deleting": "در حال حذف..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "بارگذاری نقشها ناموفق بود",
|
|
||||||
"createFailed": "ایجاد نقش ناموفق بود",
|
|
||||||
"updateFailed": "بهروزرسانی نقش ناموفق بود",
|
|
||||||
"nameRequired": "نام نقش الزامی است",
|
|
||||||
"deleteFailed": "حذف نقش ناموفق بود"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"roleAssign": {
|
|
||||||
"title": "تخصیص نقش",
|
|
||||||
"subtitle": "تخصیص و مدیریت نقشهای کاربران",
|
|
||||||
"assignSection": "تخصیص نقش",
|
|
||||||
"userLabel": "کاربر",
|
|
||||||
"searchPlaceholder": "جستجو بر اساس نام، نام کاربری، شناسه تلگرام یا ایمیل...",
|
|
||||||
"clearUser": "پاک کردن کاربر انتخابشده",
|
|
||||||
"noUsersFound": "کاربری یافت نشد",
|
|
||||||
"roleLabel": "نقش",
|
|
||||||
"selectRole": "یک نقش انتخاب کنید...",
|
|
||||||
"expiresLabel": "تاریخ انقضا (اختیاری)",
|
|
||||||
"expiresHint": "برای تخصیص دائمی خالی بگذارید",
|
|
||||||
"assignButton": "تخصیص",
|
|
||||||
"assigning": "در حال تخصیص...",
|
|
||||||
"assignSuccess": "نقش با موفقیت تخصیص داده شد",
|
|
||||||
"currentAssignments": "تخصیصهای فعلی",
|
|
||||||
"totalAssignments_other": "{{count}} تخصیص",
|
|
||||||
"noAssignments": "تخصیص نقشی یافت نشد",
|
|
||||||
"unknownUser": "کاربر ناشناخته",
|
|
||||||
"system": "سیستم",
|
|
||||||
"permanent": "دائمی",
|
|
||||||
"expired": "منقضی شده",
|
|
||||||
"revoke": "لغو",
|
|
||||||
"revokeAriaLabel": "لغو نقش {{role}} از {{user}}",
|
|
||||||
"table": {
|
|
||||||
"user": "کاربر",
|
|
||||||
"role": "نقش",
|
|
||||||
"assignedBy": "تخصیصدهنده",
|
|
||||||
"assignedAt": "تاریخ تخصیص",
|
|
||||||
"expires": "انقضا",
|
|
||||||
"actions": "عملیات"
|
|
||||||
},
|
|
||||||
"pagination": {
|
|
||||||
"showing": "{{from}}-{{to}} از {{total}}",
|
|
||||||
"prev": "صفحه قبل",
|
|
||||||
"next": "صفحه بعد"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "لغو نقش؟",
|
|
||||||
"text": "این کاربر فوراً تمام مجوزهای مرتبط با این نقش را از دست خواهد داد.",
|
|
||||||
"cancel": "لغو",
|
|
||||||
"revoke": "لغو نقش",
|
|
||||||
"revoking": "در حال لغو..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"userRequired": "لطفاً یک کاربر انتخاب کنید",
|
|
||||||
"roleRequired": "لطفاً یک نقش انتخاب کنید",
|
|
||||||
"assignFailed": "تخصیص نقش ناموفق بود",
|
|
||||||
"revokeFailed": "لغو نقش ناموفق بود"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"policies": {
|
|
||||||
"title": "سیاستهای دسترسی",
|
|
||||||
"subtitle": "مدیریت سیاستهای کنترل دسترسی ABAC",
|
|
||||||
"createPolicy": "ایجاد سیاست",
|
|
||||||
"noPolicies": "سیاستی یافت نشد",
|
|
||||||
"inactiveBadge": "غیرفعال",
|
|
||||||
"effectAllow": "اجازه",
|
|
||||||
"effectDeny": "رد",
|
|
||||||
"global": "سراسری",
|
|
||||||
"unknownRole": "نقش ناشناخته",
|
|
||||||
"roleLabel": "نقش",
|
|
||||||
"priorityLabel": "اولویت",
|
|
||||||
"stats": {
|
|
||||||
"total": "کل سیاستها",
|
|
||||||
"allow": "اجازه",
|
|
||||||
"deny": "رد",
|
|
||||||
"active": "فعال"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"edit": "ویرایش",
|
|
||||||
"delete": "حذف"
|
|
||||||
},
|
|
||||||
"modal": {
|
|
||||||
"createTitle": "ایجاد سیاست",
|
|
||||||
"editTitle": "ویرایش سیاست",
|
|
||||||
"close": "بستن"
|
|
||||||
},
|
|
||||||
"form": {
|
|
||||||
"name": "نام سیاست",
|
|
||||||
"namePlaceholder": "مثلاً مسدودسازی دسترسی شبانه",
|
|
||||||
"description": "توضیحات",
|
|
||||||
"descriptionPlaceholder": "عملکرد این سیاست...",
|
|
||||||
"effect": "اثر",
|
|
||||||
"resource": "منبع",
|
|
||||||
"selectResource": "یک منبع انتخاب کنید...",
|
|
||||||
"actions": "عملیات",
|
|
||||||
"role": "نقش (اختیاری)",
|
|
||||||
"globalOption": "سراسری (همه نقشها)",
|
|
||||||
"roleHint": "سراسری بگذارید تا سیاست برای همه نقشها اعمال شود.",
|
|
||||||
"priority": "اولویت",
|
|
||||||
"priorityHint": "سیاستهای با اولویت بالاتر ابتدا ارزیابی میشوند. رد در اولویت مساوی بر اجازه غلبه میکند.",
|
|
||||||
"conditions": "شرایط",
|
|
||||||
"cancel": "لغو",
|
|
||||||
"saving": "در حال ذخیره...",
|
|
||||||
"save": "ذخیره"
|
|
||||||
},
|
|
||||||
"conditions": {
|
|
||||||
"timeRange": "بازه زمانی",
|
|
||||||
"timeStart": "زمان شروع",
|
|
||||||
"timeEnd": "زمان پایان",
|
|
||||||
"ipWhitelist": "لیست سفید IP",
|
|
||||||
"ipPlaceholder": "IP را وارد کنید و Enter بزنید...",
|
|
||||||
"removeIp": "حذف {{ip}}",
|
|
||||||
"ipCount_other": "{{count}} IP",
|
|
||||||
"rateLimit": "محدودیت نرخ",
|
|
||||||
"rateLimitValue": "مقدار محدودیت نرخ",
|
|
||||||
"rateValue": "{{count}}/ساعت",
|
|
||||||
"perHour": "عملیات در ساعت"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "حذف سیاست؟",
|
|
||||||
"text": "این سیاست برای همیشه حذف خواهد شد. قوانین کنترل دسترسی مجدداً محاسبه خواهند شد.",
|
|
||||||
"cancel": "لغو",
|
|
||||||
"delete": "حذف",
|
|
||||||
"deleting": "در حال حذف..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "بارگذاری سیاستها ناموفق بود",
|
|
||||||
"createFailed": "ایجاد سیاست ناموفق بود",
|
|
||||||
"updateFailed": "بهروزرسانی سیاست ناموفق بود",
|
|
||||||
"nameRequired": "نام سیاست الزامی است",
|
|
||||||
"resourceRequired": "لطفاً یک منبع انتخاب کنید",
|
|
||||||
"actionsRequired": "لطفاً حداقل یک عملیات انتخاب کنید",
|
|
||||||
"deleteFailed": "حذف سیاست ناموفق بود"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"auditLog": {
|
|
||||||
"title": "گزارش بازرسی",
|
|
||||||
"subtitle": "بررسی فعالیت سیستم و تاریخچه دسترسی",
|
|
||||||
"back": "بازگشت",
|
|
||||||
"exportCsv": "خروجی CSV",
|
|
||||||
"exportError": "خطا در خروجی",
|
|
||||||
"exporting": "در حال خروجی...",
|
|
||||||
"refresh": "بازخوانی",
|
|
||||||
"unknownUser": "کاربر ناشناخته",
|
|
||||||
"noEntries": "رکوردی در گزارش بازرسی یافت نشد",
|
|
||||||
"totalEntries_other": "{{count}} رکورد",
|
|
||||||
"autoRefresh": {
|
|
||||||
"label": "بازخوانی خودکار",
|
|
||||||
"tooltip": "بازخوانی خودکار هر ۳۰ ثانیه"
|
|
||||||
},
|
|
||||||
"filters": {
|
|
||||||
"title": "فیلترها",
|
|
||||||
"active": "فعال",
|
|
||||||
"action": "عملیات",
|
|
||||||
"actionPlaceholder": "جستجو بر اساس عملیات...",
|
|
||||||
"resource": "نوع منبع",
|
|
||||||
"allResources": "همه منابع",
|
|
||||||
"status": "وضعیت",
|
|
||||||
"allStatuses": "همه وضعیتها",
|
|
||||||
"dateFrom": "از تاریخ",
|
|
||||||
"dateTo": "تا تاریخ",
|
|
||||||
"apply": "اعمال",
|
|
||||||
"clear": "پاک کردن"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"success": "موفق",
|
|
||||||
"denied": "رد شده",
|
|
||||||
"error": "خطا"
|
|
||||||
},
|
|
||||||
"resourceTypes": {
|
|
||||||
"users": "کاربران",
|
|
||||||
"tickets": "تیکتها",
|
|
||||||
"roles": "نقشها",
|
|
||||||
"policies": "سیاستها",
|
|
||||||
"settings": "تنظیمات",
|
|
||||||
"broadcasts": "پیامرسانی",
|
|
||||||
"tariffs": "تعرفهها",
|
|
||||||
"servers": "سرورها",
|
|
||||||
"payments": "پرداختها",
|
|
||||||
"campaigns": "کمپینها",
|
|
||||||
"promocodes": "کدهای تخفیف"
|
|
||||||
},
|
|
||||||
"details": {
|
|
||||||
"userAgent": "عامل کاربر",
|
|
||||||
"requestPath": "مسیر درخواست",
|
|
||||||
"ipAddress": "آدرس IP",
|
|
||||||
"timestamp": "زمان",
|
|
||||||
"before": "قبل",
|
|
||||||
"after": "بعد",
|
|
||||||
"fullDetails": "جزئیات کامل"
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"justNow": "همین الان",
|
|
||||||
"minutesAgo_other": "{{count}} دقیقه پیش",
|
|
||||||
"hoursAgo_other": "{{count}} ساعت پیش",
|
|
||||||
"daysAgo_other": "{{count}} روز پیش"
|
|
||||||
},
|
|
||||||
"pagination": {
|
|
||||||
"pageSize": "در هر صفحه:",
|
|
||||||
"pageOf": "{{current}} / {{total}}",
|
|
||||||
"first": "صفحه اول",
|
|
||||||
"previous": "صفحه قبل",
|
|
||||||
"next": "صفحه بعد",
|
|
||||||
"last": "صفحه آخر"
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "بارگذاری گزارش بازرسی ناموفق بود",
|
|
||||||
"retry": "تلاش مجدد"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"blocking": {
|
"blocking": {
|
||||||
|
|||||||
@@ -320,7 +320,10 @@
|
|||||||
"extraDevicesIncluded_many": "Вкл. {{count}} доп. устр.",
|
"extraDevicesIncluded_many": "Вкл. {{count}} доп. устр.",
|
||||||
"baseTariff": "Тариф",
|
"baseTariff": "Тариф",
|
||||||
"perMonth": "/мес",
|
"perMonth": "/мес",
|
||||||
"summary": "Итого",
|
"summary": {
|
||||||
|
"period": "Период: {{label}}",
|
||||||
|
"traffic": "Трафик: {{gb}} ГБ"
|
||||||
|
},
|
||||||
"total": "К оплате",
|
"total": "К оплате",
|
||||||
"purchase": "Купить",
|
"purchase": "Купить",
|
||||||
"step": "Шаг {{current}} из {{total}}",
|
"step": "Шаг {{current}} из {{total}}",
|
||||||
@@ -535,10 +538,6 @@
|
|||||||
"label": "Трафик",
|
"label": "Трафик",
|
||||||
"selectVolume": "Выбрать объём трафика",
|
"selectVolume": "Выбрать объём трафика",
|
||||||
"default": "По умолчанию: {{label}}"
|
"default": "По умолчанию: {{label}}"
|
||||||
},
|
|
||||||
"summary": {
|
|
||||||
"period": "Период: {{label}}",
|
|
||||||
"traffic": "Трафик: {{gb}} ГБ"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"balance": {
|
"balance": {
|
||||||
@@ -548,7 +547,41 @@
|
|||||||
"topUpBalance": "Пополнение баланса",
|
"topUpBalance": "Пополнение баланса",
|
||||||
"enterAmount": "Введите сумму",
|
"enterAmount": "Введите сумму",
|
||||||
"paymentMethod": "Способ оплаты",
|
"paymentMethod": "Способ оплаты",
|
||||||
"paymentMethods": "Способы оплаты",
|
"paymentMethods": {
|
||||||
|
"yookassa": {
|
||||||
|
"description": "Оплата через ЮKassa"
|
||||||
|
},
|
||||||
|
"cryptobot": {
|
||||||
|
"description": "Оплата криптовалютой через CryptoBot"
|
||||||
|
},
|
||||||
|
"telegram_stars": {
|
||||||
|
"description": "Оплата через Telegram Stars"
|
||||||
|
},
|
||||||
|
"heleket": {
|
||||||
|
"description": "Оплата криптовалютой через Heleket"
|
||||||
|
},
|
||||||
|
"mulenpay": {
|
||||||
|
"description": "Оплата через MulenPay"
|
||||||
|
},
|
||||||
|
"pal24": {
|
||||||
|
"description": "Оплата через PAL24"
|
||||||
|
},
|
||||||
|
"platega": {
|
||||||
|
"description": "Оплата через Platega"
|
||||||
|
},
|
||||||
|
"wata": {
|
||||||
|
"description": "Оплата через Wata"
|
||||||
|
},
|
||||||
|
"cloudpayments": {
|
||||||
|
"description": "Оплата банковской картой через CloudPayments"
|
||||||
|
},
|
||||||
|
"freekassa": {
|
||||||
|
"description": "Оплата через FreeKassa"
|
||||||
|
},
|
||||||
|
"tribute": {
|
||||||
|
"description": "Оплата банковской картой через Tribute"
|
||||||
|
}
|
||||||
|
},
|
||||||
"transactionHistory": "История операций",
|
"transactionHistory": "История операций",
|
||||||
"noTransactions": "Нет операций",
|
"noTransactions": "Нет операций",
|
||||||
"date": "Дата",
|
"date": "Дата",
|
||||||
@@ -590,41 +623,6 @@
|
|||||||
"topUpToComplete": "Пополните баланс для завершения покупки",
|
"topUpToComplete": "Пополните баланс для завершения покупки",
|
||||||
"missing": "Не хватает",
|
"missing": "Не хватает",
|
||||||
"noPaymentMethods": "Способы оплаты недоступны",
|
"noPaymentMethods": "Способы оплаты недоступны",
|
||||||
"paymentMethods": {
|
|
||||||
"yookassa": {
|
|
||||||
"description": "Оплата через ЮKassa"
|
|
||||||
},
|
|
||||||
"cryptobot": {
|
|
||||||
"description": "Оплата криптовалютой через CryptoBot"
|
|
||||||
},
|
|
||||||
"telegram_stars": {
|
|
||||||
"description": "Оплата через Telegram Stars"
|
|
||||||
},
|
|
||||||
"heleket": {
|
|
||||||
"description": "Оплата криптовалютой через Heleket"
|
|
||||||
},
|
|
||||||
"mulenpay": {
|
|
||||||
"description": "Оплата через MulenPay"
|
|
||||||
},
|
|
||||||
"pal24": {
|
|
||||||
"description": "Оплата через PAL24"
|
|
||||||
},
|
|
||||||
"platega": {
|
|
||||||
"description": "Оплата через Platega"
|
|
||||||
},
|
|
||||||
"wata": {
|
|
||||||
"description": "Оплата через Wata"
|
|
||||||
},
|
|
||||||
"cloudpayments": {
|
|
||||||
"description": "Оплата банковской картой через CloudPayments"
|
|
||||||
},
|
|
||||||
"freekassa": {
|
|
||||||
"description": "Оплата через FreeKassa"
|
|
||||||
},
|
|
||||||
"tribute": {
|
|
||||||
"description": "Оплата банковской картой через Tribute"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pendingPayments": {
|
"pendingPayments": {
|
||||||
"title": "Ожидающие платежи",
|
"title": "Ожидающие платежи",
|
||||||
"pay": "Оплатить",
|
"pay": "Оплатить",
|
||||||
@@ -937,7 +935,7 @@
|
|||||||
"total": "Всего",
|
"total": "Всего",
|
||||||
"noData": "Нет данных о трафике",
|
"noData": "Нет данных о трафике",
|
||||||
"loading": "Загрузка данных о трафике...",
|
"loading": "Загрузка данных о трафике...",
|
||||||
"noTariff": "\u2014",
|
"noTariff": "—",
|
||||||
"search": "Поиск по имени или юзернейму",
|
"search": "Поиск по имени или юзернейму",
|
||||||
"allTariffs": "Все тарифы",
|
"allTariffs": "Все тарифы",
|
||||||
"nodes": "Ноды",
|
"nodes": "Ноды",
|
||||||
@@ -2087,7 +2085,7 @@
|
|||||||
"name": "Название",
|
"name": "Название",
|
||||||
"namePlaceholder": "Введите название тарифа",
|
"namePlaceholder": "Введите название тарифа",
|
||||||
"description": "Описание",
|
"description": "Описание",
|
||||||
"descriptionPlaceholder": "Введите описание тарифа",
|
"descriptionPlaceholder": "Краткое описание тарифа",
|
||||||
"trafficLimit": "Лимит трафика",
|
"trafficLimit": "Лимит трафика",
|
||||||
"trafficHint": "0 = безлимитный трафик",
|
"trafficHint": "0 = безлимитный трафик",
|
||||||
"deviceLimit": "Лимит устройств",
|
"deviceLimit": "Лимит устройств",
|
||||||
@@ -2155,7 +2153,6 @@
|
|||||||
"nameExampleDaily": "Например: Суточный",
|
"nameExampleDaily": "Например: Суточный",
|
||||||
"nameHint": "От 2 до 50 символов",
|
"nameHint": "От 2 до 50 символов",
|
||||||
"descriptionLabel": "Описание",
|
"descriptionLabel": "Описание",
|
||||||
"descriptionPlaceholder": "Краткое описание тарифа",
|
|
||||||
"trafficLimitLabel": "Лимит трафика",
|
"trafficLimitLabel": "Лимит трафика",
|
||||||
"gbUnit": "ГБ",
|
"gbUnit": "ГБ",
|
||||||
"trafficLimitHint": "0 = безлимитный трафик",
|
"trafficLimitHint": "0 = безлимитный трафик",
|
||||||
@@ -3082,6 +3079,287 @@
|
|||||||
"lightness": "Яркость",
|
"lightness": "Яркость",
|
||||||
"quickPresets": "Быстрые пресеты",
|
"quickPresets": "Быстрые пресеты",
|
||||||
"saturation": "Насыщенность"
|
"saturation": "Насыщенность"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"title": "Роли и права",
|
||||||
|
"subtitle": "Управление ролями администраторов и их правами",
|
||||||
|
"createRole": "Создать роль",
|
||||||
|
"noRoles": "Роли не найдены",
|
||||||
|
"systemBadge": "Системная",
|
||||||
|
"inactiveBadge": "Неактивна",
|
||||||
|
"levelLabel": "Уровень",
|
||||||
|
"usersCount_one": "{{count}} пользователь",
|
||||||
|
"usersCount_few": "{{count}} пользователя",
|
||||||
|
"usersCount_many": "{{count}} пользователей",
|
||||||
|
"permissionsCount_one": "{{count}} разрешение",
|
||||||
|
"permissionsCount_few": "{{count}} разрешения",
|
||||||
|
"permissionsCount_many": "{{count}} разрешений",
|
||||||
|
"stats": {
|
||||||
|
"totalRoles": "Всего ролей",
|
||||||
|
"active": "Активные",
|
||||||
|
"system": "Системные"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"edit": "Редактировать",
|
||||||
|
"delete": "Удалить"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"createTitle": "Создание роли",
|
||||||
|
"editTitle": "Редактирование роли",
|
||||||
|
"close": "Закрыть"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"name": "Название роли",
|
||||||
|
"namePlaceholder": "например, Модератор",
|
||||||
|
"description": "Описание",
|
||||||
|
"descriptionPlaceholder": "Для чего нужна эта роль...",
|
||||||
|
"level": "Уровень приоритета",
|
||||||
|
"levelValue": "Значение уровня",
|
||||||
|
"levelHint": "Чем выше уровень, тем больше полномочий. Пользователи могут управлять только ролями с уровнем ниже своего.",
|
||||||
|
"color": "Цвет",
|
||||||
|
"presets": "Шаблоны прав",
|
||||||
|
"permissions": "Разрешения",
|
||||||
|
"toggleSection": "Переключить все права {{section}}",
|
||||||
|
"selectedPermissions_one": "{{count}} разрешение выбрано",
|
||||||
|
"selectedPermissions_few": "{{count}} разрешения выбрано",
|
||||||
|
"selectedPermissions_many": "{{count}} разрешений выбрано",
|
||||||
|
"cancel": "Отмена",
|
||||||
|
"saving": "Сохранение...",
|
||||||
|
"save": "Сохранить"
|
||||||
|
},
|
||||||
|
"presets": {
|
||||||
|
"moderator": "Модератор",
|
||||||
|
"marketer": "Маркетолог",
|
||||||
|
"support": "Поддержка"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "Удалить роль?",
|
||||||
|
"text": "Роль будет безвозвратно удалена. Пользователи с этой ролью потеряют её права.",
|
||||||
|
"cancel": "Отмена",
|
||||||
|
"delete": "Удалить",
|
||||||
|
"deleting": "Удаление..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "Не удалось загрузить роли",
|
||||||
|
"createFailed": "Не удалось создать роль",
|
||||||
|
"updateFailed": "Не удалось обновить роль",
|
||||||
|
"nameRequired": "Укажите название роли",
|
||||||
|
"deleteFailed": "Не удалось удалить роль"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roleAssign": {
|
||||||
|
"title": "Назначение ролей",
|
||||||
|
"subtitle": "Назначение и управление ролями пользователей",
|
||||||
|
"assignSection": "Назначить роль",
|
||||||
|
"userLabel": "Пользователь",
|
||||||
|
"searchPlaceholder": "Поиск по имени, username, Telegram ID или email...",
|
||||||
|
"clearUser": "Очистить выбранного пользователя",
|
||||||
|
"noUsersFound": "Пользователи не найдены",
|
||||||
|
"roleLabel": "Роль",
|
||||||
|
"selectRole": "Выберите роль...",
|
||||||
|
"expiresLabel": "Истекает (необязательно)",
|
||||||
|
"expiresHint": "Оставьте пустым для бессрочного назначения",
|
||||||
|
"assignButton": "Назначить",
|
||||||
|
"assigning": "Назначение...",
|
||||||
|
"assignSuccess": "Роль успешно назначена",
|
||||||
|
"currentAssignments": "Текущие назначения",
|
||||||
|
"totalAssignments_one": "{{count}} назначение",
|
||||||
|
"totalAssignments_few": "{{count}} назначения",
|
||||||
|
"totalAssignments_many": "{{count}} назначений",
|
||||||
|
"noAssignments": "Назначения ролей не найдены",
|
||||||
|
"unknownUser": "Неизвестный пользователь",
|
||||||
|
"system": "Система",
|
||||||
|
"permanent": "Бессрочно",
|
||||||
|
"expired": "истекло",
|
||||||
|
"revoke": "Отозвать",
|
||||||
|
"revokeAriaLabel": "Отозвать роль {{role}} у {{user}}",
|
||||||
|
"table": {
|
||||||
|
"user": "Пользователь",
|
||||||
|
"role": "Роль",
|
||||||
|
"assignedBy": "Назначил",
|
||||||
|
"assignedAt": "Дата назначения",
|
||||||
|
"expires": "Истекает",
|
||||||
|
"actions": "Действия"
|
||||||
|
},
|
||||||
|
"pagination": {
|
||||||
|
"showing": "{{from}}-{{to}} из {{total}}",
|
||||||
|
"prev": "Предыдущая страница",
|
||||||
|
"next": "Следующая страница"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "Отозвать роль?",
|
||||||
|
"text": "Пользователь немедленно потеряет все права, связанные с этой ролью.",
|
||||||
|
"cancel": "Отмена",
|
||||||
|
"revoke": "Отозвать",
|
||||||
|
"revoking": "Отзыв..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"userRequired": "Выберите пользователя",
|
||||||
|
"roleRequired": "Выберите роль",
|
||||||
|
"assignFailed": "Не удалось назначить роль",
|
||||||
|
"revokeFailed": "Не удалось отозвать роль"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {
|
||||||
|
"title": "Политики доступа",
|
||||||
|
"subtitle": "Управление политиками контроля доступа ABAC",
|
||||||
|
"createPolicy": "Создать политику",
|
||||||
|
"noPolicies": "Политики не найдены",
|
||||||
|
"inactiveBadge": "Неактивна",
|
||||||
|
"effectAllow": "Разрешить",
|
||||||
|
"effectDeny": "Запретить",
|
||||||
|
"global": "Глобальная",
|
||||||
|
"unknownRole": "Неизвестная роль",
|
||||||
|
"roleLabel": "Роль",
|
||||||
|
"priorityLabel": "Приоритет",
|
||||||
|
"stats": {
|
||||||
|
"total": "Всего политик",
|
||||||
|
"allow": "Разрешающие",
|
||||||
|
"deny": "Запрещающие",
|
||||||
|
"active": "Активные"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"edit": "Редактировать",
|
||||||
|
"delete": "Удалить"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"createTitle": "Создание политики",
|
||||||
|
"editTitle": "Редактирование политики",
|
||||||
|
"close": "Закрыть"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"name": "Название политики",
|
||||||
|
"namePlaceholder": "например, Блокировка ночного доступа",
|
||||||
|
"description": "Описание",
|
||||||
|
"descriptionPlaceholder": "Что делает эта политика...",
|
||||||
|
"effect": "Эффект",
|
||||||
|
"resource": "Ресурс",
|
||||||
|
"selectResource": "Выберите ресурс...",
|
||||||
|
"actions": "Действия",
|
||||||
|
"role": "Роль (необязательно)",
|
||||||
|
"globalOption": "Глобальная (все роли)",
|
||||||
|
"roleHint": "Оставьте Глобальная, чтобы политика применялась ко всем ролям.",
|
||||||
|
"priority": "Приоритет",
|
||||||
|
"priorityHint": "Политики с более высоким приоритетом проверяются первыми. Запрет перекрывает Разрешение при равном приоритете.",
|
||||||
|
"conditions": "Условия",
|
||||||
|
"cancel": "Отмена",
|
||||||
|
"saving": "Сохранение...",
|
||||||
|
"save": "Сохранить"
|
||||||
|
},
|
||||||
|
"conditions": {
|
||||||
|
"timeRange": "Временной диапазон",
|
||||||
|
"timeStart": "Время начала",
|
||||||
|
"timeEnd": "Время окончания",
|
||||||
|
"ipWhitelist": "Белый список IP",
|
||||||
|
"ipPlaceholder": "Введите IP и нажмите Enter...",
|
||||||
|
"removeIp": "Удалить {{ip}}",
|
||||||
|
"ipCount_one": "{{count}} IP",
|
||||||
|
"ipCount_few": "{{count}} IP",
|
||||||
|
"ipCount_many": "{{count}} IP",
|
||||||
|
"rateLimit": "Лимит запросов",
|
||||||
|
"rateLimitValue": "Значение лимита запросов",
|
||||||
|
"rateValue": "{{count}}/ч",
|
||||||
|
"perHour": "действий в час"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "Удалить политику?",
|
||||||
|
"text": "Политика будет безвозвратно удалена. Правила контроля доступа будут пересчитаны.",
|
||||||
|
"cancel": "Отмена",
|
||||||
|
"delete": "Удалить",
|
||||||
|
"deleting": "Удаление..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "Не удалось загрузить политики",
|
||||||
|
"createFailed": "Не удалось создать политику",
|
||||||
|
"updateFailed": "Не удалось обновить политику",
|
||||||
|
"nameRequired": "Укажите название политики",
|
||||||
|
"resourceRequired": "Выберите ресурс",
|
||||||
|
"actionsRequired": "Выберите хотя бы одно действие",
|
||||||
|
"deleteFailed": "Не удалось удалить политику"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"auditLog": {
|
||||||
|
"title": "Журнал аудита",
|
||||||
|
"subtitle": "Просмотр активности системы и истории доступа",
|
||||||
|
"back": "Назад",
|
||||||
|
"exportCsv": "Экспорт CSV",
|
||||||
|
"exportError": "Ошибка экспорта",
|
||||||
|
"exporting": "Экспорт...",
|
||||||
|
"refresh": "Обновить",
|
||||||
|
"unknownUser": "Неизвестный пользователь",
|
||||||
|
"noEntries": "Записи журнала аудита не найдены",
|
||||||
|
"totalEntries_one": "{{count}} запись",
|
||||||
|
"totalEntries_few": "{{count}} записи",
|
||||||
|
"totalEntries_many": "{{count}} записей",
|
||||||
|
"autoRefresh": {
|
||||||
|
"label": "Автообновление",
|
||||||
|
"tooltip": "Автообновление каждые 30 секунд"
|
||||||
|
},
|
||||||
|
"filters": {
|
||||||
|
"title": "Фильтры",
|
||||||
|
"active": "Активны",
|
||||||
|
"action": "Действие",
|
||||||
|
"actionPlaceholder": "Поиск по действию...",
|
||||||
|
"resource": "Тип ресурса",
|
||||||
|
"allResources": "Все ресурсы",
|
||||||
|
"status": "Статус",
|
||||||
|
"allStatuses": "Все статусы",
|
||||||
|
"dateFrom": "Дата от",
|
||||||
|
"dateTo": "Дата до",
|
||||||
|
"apply": "Применить",
|
||||||
|
"clear": "Сбросить"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"success": "Успешно",
|
||||||
|
"denied": "Отказано",
|
||||||
|
"error": "Ошибка"
|
||||||
|
},
|
||||||
|
"resourceTypes": {
|
||||||
|
"users": "Пользователи",
|
||||||
|
"tickets": "Тикеты",
|
||||||
|
"roles": "Роли",
|
||||||
|
"policies": "Политики",
|
||||||
|
"settings": "Настройки",
|
||||||
|
"broadcasts": "Рассылки",
|
||||||
|
"tariffs": "Тарифы",
|
||||||
|
"servers": "Серверы",
|
||||||
|
"payments": "Платежи",
|
||||||
|
"campaigns": "Кампании",
|
||||||
|
"promocodes": "Промокоды"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"userAgent": "User Agent",
|
||||||
|
"requestPath": "Путь запроса",
|
||||||
|
"ipAddress": "IP-адрес",
|
||||||
|
"timestamp": "Время",
|
||||||
|
"before": "До",
|
||||||
|
"after": "После",
|
||||||
|
"fullDetails": "Полные данные"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"justNow": "Только что",
|
||||||
|
"minutesAgo_one": "{{count}} мин назад",
|
||||||
|
"minutesAgo_few": "{{count}} мин назад",
|
||||||
|
"minutesAgo_many": "{{count}} мин назад",
|
||||||
|
"hoursAgo_one": "{{count}} ч назад",
|
||||||
|
"hoursAgo_few": "{{count}} ч назад",
|
||||||
|
"hoursAgo_many": "{{count}} ч назад",
|
||||||
|
"daysAgo_one": "{{count}} день назад",
|
||||||
|
"daysAgo_few": "{{count}} дня назад",
|
||||||
|
"daysAgo_many": "{{count}} дней назад"
|
||||||
|
},
|
||||||
|
"pagination": {
|
||||||
|
"pageSize": "На странице:",
|
||||||
|
"pageOf": "{{current}} / {{total}}",
|
||||||
|
"first": "Первая страница",
|
||||||
|
"previous": "Предыдущая страница",
|
||||||
|
"next": "Следующая страница",
|
||||||
|
"last": "Последняя страница"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "Не удалось загрузить журнал аудита",
|
||||||
|
"retry": "Попробовать снова"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"adminUpdates": {
|
"adminUpdates": {
|
||||||
@@ -3481,287 +3759,6 @@
|
|||||||
"unhealthy": "Проблема",
|
"unhealthy": "Проблема",
|
||||||
"components": "Компоненты",
|
"components": "Компоненты",
|
||||||
"uptime": "Аптайм"
|
"uptime": "Аптайм"
|
||||||
},
|
|
||||||
"roles": {
|
|
||||||
"title": "Роли и права",
|
|
||||||
"subtitle": "Управление ролями администраторов и их правами",
|
|
||||||
"createRole": "Создать роль",
|
|
||||||
"noRoles": "Роли не найдены",
|
|
||||||
"systemBadge": "Системная",
|
|
||||||
"inactiveBadge": "Неактивна",
|
|
||||||
"levelLabel": "Уровень",
|
|
||||||
"usersCount_one": "{{count}} пользователь",
|
|
||||||
"usersCount_few": "{{count}} пользователя",
|
|
||||||
"usersCount_many": "{{count}} пользователей",
|
|
||||||
"permissionsCount_one": "{{count}} разрешение",
|
|
||||||
"permissionsCount_few": "{{count}} разрешения",
|
|
||||||
"permissionsCount_many": "{{count}} разрешений",
|
|
||||||
"stats": {
|
|
||||||
"totalRoles": "Всего ролей",
|
|
||||||
"active": "Активные",
|
|
||||||
"system": "Системные"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"edit": "Редактировать",
|
|
||||||
"delete": "Удалить"
|
|
||||||
},
|
|
||||||
"modal": {
|
|
||||||
"createTitle": "Создание роли",
|
|
||||||
"editTitle": "Редактирование роли",
|
|
||||||
"close": "Закрыть"
|
|
||||||
},
|
|
||||||
"form": {
|
|
||||||
"name": "Название роли",
|
|
||||||
"namePlaceholder": "например, Модератор",
|
|
||||||
"description": "Описание",
|
|
||||||
"descriptionPlaceholder": "Для чего нужна эта роль...",
|
|
||||||
"level": "Уровень приоритета",
|
|
||||||
"levelValue": "Значение уровня",
|
|
||||||
"levelHint": "Чем выше уровень, тем больше полномочий. Пользователи могут управлять только ролями с уровнем ниже своего.",
|
|
||||||
"color": "Цвет",
|
|
||||||
"presets": "Шаблоны прав",
|
|
||||||
"permissions": "Разрешения",
|
|
||||||
"toggleSection": "Переключить все права {{section}}",
|
|
||||||
"selectedPermissions_one": "{{count}} разрешение выбрано",
|
|
||||||
"selectedPermissions_few": "{{count}} разрешения выбрано",
|
|
||||||
"selectedPermissions_many": "{{count}} разрешений выбрано",
|
|
||||||
"cancel": "Отмена",
|
|
||||||
"saving": "Сохранение...",
|
|
||||||
"save": "Сохранить"
|
|
||||||
},
|
|
||||||
"presets": {
|
|
||||||
"moderator": "Модератор",
|
|
||||||
"marketer": "Маркетолог",
|
|
||||||
"support": "Поддержка"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "Удалить роль?",
|
|
||||||
"text": "Роль будет безвозвратно удалена. Пользователи с этой ролью потеряют её права.",
|
|
||||||
"cancel": "Отмена",
|
|
||||||
"delete": "Удалить",
|
|
||||||
"deleting": "Удаление..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "Не удалось загрузить роли",
|
|
||||||
"createFailed": "Не удалось создать роль",
|
|
||||||
"updateFailed": "Не удалось обновить роль",
|
|
||||||
"nameRequired": "Укажите название роли",
|
|
||||||
"deleteFailed": "Не удалось удалить роль"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"roleAssign": {
|
|
||||||
"title": "Назначение ролей",
|
|
||||||
"subtitle": "Назначение и управление ролями пользователей",
|
|
||||||
"assignSection": "Назначить роль",
|
|
||||||
"userLabel": "Пользователь",
|
|
||||||
"searchPlaceholder": "Поиск по имени, username, Telegram ID или email...",
|
|
||||||
"clearUser": "Очистить выбранного пользователя",
|
|
||||||
"noUsersFound": "Пользователи не найдены",
|
|
||||||
"roleLabel": "Роль",
|
|
||||||
"selectRole": "Выберите роль...",
|
|
||||||
"expiresLabel": "Истекает (необязательно)",
|
|
||||||
"expiresHint": "Оставьте пустым для бессрочного назначения",
|
|
||||||
"assignButton": "Назначить",
|
|
||||||
"assigning": "Назначение...",
|
|
||||||
"assignSuccess": "Роль успешно назначена",
|
|
||||||
"currentAssignments": "Текущие назначения",
|
|
||||||
"totalAssignments_one": "{{count}} назначение",
|
|
||||||
"totalAssignments_few": "{{count}} назначения",
|
|
||||||
"totalAssignments_many": "{{count}} назначений",
|
|
||||||
"noAssignments": "Назначения ролей не найдены",
|
|
||||||
"unknownUser": "Неизвестный пользователь",
|
|
||||||
"system": "Система",
|
|
||||||
"permanent": "Бессрочно",
|
|
||||||
"expired": "истекло",
|
|
||||||
"revoke": "Отозвать",
|
|
||||||
"revokeAriaLabel": "Отозвать роль {{role}} у {{user}}",
|
|
||||||
"table": {
|
|
||||||
"user": "Пользователь",
|
|
||||||
"role": "Роль",
|
|
||||||
"assignedBy": "Назначил",
|
|
||||||
"assignedAt": "Дата назначения",
|
|
||||||
"expires": "Истекает",
|
|
||||||
"actions": "Действия"
|
|
||||||
},
|
|
||||||
"pagination": {
|
|
||||||
"showing": "{{from}}-{{to}} из {{total}}",
|
|
||||||
"prev": "Предыдущая страница",
|
|
||||||
"next": "Следующая страница"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "Отозвать роль?",
|
|
||||||
"text": "Пользователь немедленно потеряет все права, связанные с этой ролью.",
|
|
||||||
"cancel": "Отмена",
|
|
||||||
"revoke": "Отозвать",
|
|
||||||
"revoking": "Отзыв..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"userRequired": "Выберите пользователя",
|
|
||||||
"roleRequired": "Выберите роль",
|
|
||||||
"assignFailed": "Не удалось назначить роль",
|
|
||||||
"revokeFailed": "Не удалось отозвать роль"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"policies": {
|
|
||||||
"title": "Политики доступа",
|
|
||||||
"subtitle": "Управление политиками контроля доступа ABAC",
|
|
||||||
"createPolicy": "Создать политику",
|
|
||||||
"noPolicies": "Политики не найдены",
|
|
||||||
"inactiveBadge": "Неактивна",
|
|
||||||
"effectAllow": "Разрешить",
|
|
||||||
"effectDeny": "Запретить",
|
|
||||||
"global": "Глобальная",
|
|
||||||
"unknownRole": "Неизвестная роль",
|
|
||||||
"roleLabel": "Роль",
|
|
||||||
"priorityLabel": "Приоритет",
|
|
||||||
"stats": {
|
|
||||||
"total": "Всего политик",
|
|
||||||
"allow": "Разрешающие",
|
|
||||||
"deny": "Запрещающие",
|
|
||||||
"active": "Активные"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"edit": "Редактировать",
|
|
||||||
"delete": "Удалить"
|
|
||||||
},
|
|
||||||
"modal": {
|
|
||||||
"createTitle": "Создание политики",
|
|
||||||
"editTitle": "Редактирование политики",
|
|
||||||
"close": "Закрыть"
|
|
||||||
},
|
|
||||||
"form": {
|
|
||||||
"name": "Название политики",
|
|
||||||
"namePlaceholder": "например, Блокировка ночного доступа",
|
|
||||||
"description": "Описание",
|
|
||||||
"descriptionPlaceholder": "Что делает эта политика...",
|
|
||||||
"effect": "Эффект",
|
|
||||||
"resource": "Ресурс",
|
|
||||||
"selectResource": "Выберите ресурс...",
|
|
||||||
"actions": "Действия",
|
|
||||||
"role": "Роль (необязательно)",
|
|
||||||
"globalOption": "Глобальная (все роли)",
|
|
||||||
"roleHint": "Оставьте Глобальная, чтобы политика применялась ко всем ролям.",
|
|
||||||
"priority": "Приоритет",
|
|
||||||
"priorityHint": "Политики с более высоким приоритетом проверяются первыми. Запрет перекрывает Разрешение при равном приоритете.",
|
|
||||||
"conditions": "Условия",
|
|
||||||
"cancel": "Отмена",
|
|
||||||
"saving": "Сохранение...",
|
|
||||||
"save": "Сохранить"
|
|
||||||
},
|
|
||||||
"conditions": {
|
|
||||||
"timeRange": "Временной диапазон",
|
|
||||||
"timeStart": "Время начала",
|
|
||||||
"timeEnd": "Время окончания",
|
|
||||||
"ipWhitelist": "Белый список IP",
|
|
||||||
"ipPlaceholder": "Введите IP и нажмите Enter...",
|
|
||||||
"removeIp": "Удалить {{ip}}",
|
|
||||||
"ipCount_one": "{{count}} IP",
|
|
||||||
"ipCount_few": "{{count}} IP",
|
|
||||||
"ipCount_many": "{{count}} IP",
|
|
||||||
"rateLimit": "Лимит запросов",
|
|
||||||
"rateLimitValue": "Значение лимита запросов",
|
|
||||||
"rateValue": "{{count}}/ч",
|
|
||||||
"perHour": "действий в час"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "Удалить политику?",
|
|
||||||
"text": "Политика будет безвозвратно удалена. Правила контроля доступа будут пересчитаны.",
|
|
||||||
"cancel": "Отмена",
|
|
||||||
"delete": "Удалить",
|
|
||||||
"deleting": "Удаление..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "Не удалось загрузить политики",
|
|
||||||
"createFailed": "Не удалось создать политику",
|
|
||||||
"updateFailed": "Не удалось обновить политику",
|
|
||||||
"nameRequired": "Укажите название политики",
|
|
||||||
"resourceRequired": "Выберите ресурс",
|
|
||||||
"actionsRequired": "Выберите хотя бы одно действие",
|
|
||||||
"deleteFailed": "Не удалось удалить политику"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"auditLog": {
|
|
||||||
"title": "Журнал аудита",
|
|
||||||
"subtitle": "Просмотр активности системы и истории доступа",
|
|
||||||
"back": "Назад",
|
|
||||||
"exportCsv": "Экспорт CSV",
|
|
||||||
"exportError": "Ошибка экспорта",
|
|
||||||
"exporting": "Экспорт...",
|
|
||||||
"refresh": "Обновить",
|
|
||||||
"unknownUser": "Неизвестный пользователь",
|
|
||||||
"noEntries": "Записи журнала аудита не найдены",
|
|
||||||
"totalEntries_one": "{{count}} запись",
|
|
||||||
"totalEntries_few": "{{count}} записи",
|
|
||||||
"totalEntries_many": "{{count}} записей",
|
|
||||||
"autoRefresh": {
|
|
||||||
"label": "Автообновление",
|
|
||||||
"tooltip": "Автообновление каждые 30 секунд"
|
|
||||||
},
|
|
||||||
"filters": {
|
|
||||||
"title": "Фильтры",
|
|
||||||
"active": "Активны",
|
|
||||||
"action": "Действие",
|
|
||||||
"actionPlaceholder": "Поиск по действию...",
|
|
||||||
"resource": "Тип ресурса",
|
|
||||||
"allResources": "Все ресурсы",
|
|
||||||
"status": "Статус",
|
|
||||||
"allStatuses": "Все статусы",
|
|
||||||
"dateFrom": "Дата от",
|
|
||||||
"dateTo": "Дата до",
|
|
||||||
"apply": "Применить",
|
|
||||||
"clear": "Сбросить"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"success": "Успешно",
|
|
||||||
"denied": "Отказано",
|
|
||||||
"error": "Ошибка"
|
|
||||||
},
|
|
||||||
"resourceTypes": {
|
|
||||||
"users": "Пользователи",
|
|
||||||
"tickets": "Тикеты",
|
|
||||||
"roles": "Роли",
|
|
||||||
"policies": "Политики",
|
|
||||||
"settings": "Настройки",
|
|
||||||
"broadcasts": "Рассылки",
|
|
||||||
"tariffs": "Тарифы",
|
|
||||||
"servers": "Серверы",
|
|
||||||
"payments": "Платежи",
|
|
||||||
"campaigns": "Кампании",
|
|
||||||
"promocodes": "Промокоды"
|
|
||||||
},
|
|
||||||
"details": {
|
|
||||||
"userAgent": "User Agent",
|
|
||||||
"requestPath": "Путь запроса",
|
|
||||||
"ipAddress": "IP-адрес",
|
|
||||||
"timestamp": "Время",
|
|
||||||
"before": "До",
|
|
||||||
"after": "После",
|
|
||||||
"fullDetails": "Полные данные"
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"justNow": "Только что",
|
|
||||||
"minutesAgo_one": "{{count}} мин назад",
|
|
||||||
"minutesAgo_few": "{{count}} мин назад",
|
|
||||||
"minutesAgo_many": "{{count}} мин назад",
|
|
||||||
"hoursAgo_one": "{{count}} ч назад",
|
|
||||||
"hoursAgo_few": "{{count}} ч назад",
|
|
||||||
"hoursAgo_many": "{{count}} ч назад",
|
|
||||||
"daysAgo_one": "{{count}} день назад",
|
|
||||||
"daysAgo_few": "{{count}} дня назад",
|
|
||||||
"daysAgo_many": "{{count}} дней назад"
|
|
||||||
},
|
|
||||||
"pagination": {
|
|
||||||
"pageSize": "На странице:",
|
|
||||||
"pageOf": "{{current}} / {{total}}",
|
|
||||||
"first": "Первая страница",
|
|
||||||
"previous": "Предыдущая страница",
|
|
||||||
"next": "Следующая страница",
|
|
||||||
"last": "Последняя страница"
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "Не удалось загрузить журнал аудита",
|
|
||||||
"retry": "Попробовать снова"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
|
|||||||
@@ -280,7 +280,10 @@
|
|||||||
"selectServers": "选择服务器",
|
"selectServers": "选择服务器",
|
||||||
"selectDevices": "选择设备",
|
"selectDevices": "选择设备",
|
||||||
"perDevice": "/ 设备",
|
"perDevice": "/ 设备",
|
||||||
"summary": "摘要",
|
"summary": {
|
||||||
|
"period": "周期:{{label}}",
|
||||||
|
"traffic": "流量:{{gb}} GB"
|
||||||
|
},
|
||||||
"total": "总计",
|
"total": "总计",
|
||||||
"purchase": "购买",
|
"purchase": "购买",
|
||||||
"step": "第 {{current}} 步,共 {{total}} 步",
|
"step": "第 {{current}} 步,共 {{total}} 步",
|
||||||
@@ -427,10 +430,6 @@
|
|||||||
"resumeBtn": "恢复",
|
"resumeBtn": "恢复",
|
||||||
"title": "暂停订阅",
|
"title": "暂停订阅",
|
||||||
"willBeCharged": "将扣费"
|
"willBeCharged": "将扣费"
|
||||||
},
|
|
||||||
"summary": {
|
|
||||||
"period": "周期:{{label}}",
|
|
||||||
"traffic": "流量:{{gb}} GB"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"balance": {
|
"balance": {
|
||||||
@@ -795,7 +794,7 @@
|
|||||||
"total": "总计",
|
"total": "总计",
|
||||||
"noData": "无流量数据",
|
"noData": "无流量数据",
|
||||||
"loading": "正在加载流量数据...",
|
"loading": "正在加载流量数据...",
|
||||||
"noTariff": "\u2014",
|
"noTariff": "—",
|
||||||
"search": "按名称或用户名搜索",
|
"search": "按名称或用户名搜索",
|
||||||
"allTariffs": "所有套餐",
|
"allTariffs": "所有套餐",
|
||||||
"nodes": "节点",
|
"nodes": "节点",
|
||||||
@@ -2324,6 +2323,269 @@
|
|||||||
"toPanel": "到面板",
|
"toPanel": "到面板",
|
||||||
"toPanelDesc": "从机器人导出用户到RemnaWave"
|
"toPanelDesc": "从机器人导出用户到RemnaWave"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"title": "角色与权限",
|
||||||
|
"subtitle": "管理管理员角色及其权限",
|
||||||
|
"createRole": "创建角色",
|
||||||
|
"noRoles": "未找到角色",
|
||||||
|
"systemBadge": "系统",
|
||||||
|
"inactiveBadge": "未激活",
|
||||||
|
"levelLabel": "级别",
|
||||||
|
"usersCount_other": "{{count}} 个用户",
|
||||||
|
"permissionsCount_other": "{{count}} 个权限",
|
||||||
|
"stats": {
|
||||||
|
"totalRoles": "角色总数",
|
||||||
|
"active": "活跃",
|
||||||
|
"system": "系统"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"createTitle": "创建角色",
|
||||||
|
"editTitle": "编辑角色",
|
||||||
|
"close": "关闭"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"name": "角色名称",
|
||||||
|
"namePlaceholder": "例如:版主",
|
||||||
|
"description": "描述",
|
||||||
|
"descriptionPlaceholder": "此角色的用途...",
|
||||||
|
"level": "优先级",
|
||||||
|
"levelValue": "级别值",
|
||||||
|
"levelHint": "级别越高,权限越大。用户只能管理级别低于自己的角色。",
|
||||||
|
"color": "颜色",
|
||||||
|
"presets": "权限预设",
|
||||||
|
"permissions": "权限",
|
||||||
|
"toggleSection": "切换所有 {{section}} 权限",
|
||||||
|
"selectedPermissions_other": "已选择 {{count}} 个权限",
|
||||||
|
"cancel": "取消",
|
||||||
|
"saving": "保存中...",
|
||||||
|
"save": "保存"
|
||||||
|
},
|
||||||
|
"presets": {
|
||||||
|
"moderator": "版主",
|
||||||
|
"marketer": "营销员",
|
||||||
|
"support": "客服"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "删除角色?",
|
||||||
|
"text": "此角色将被永久删除。拥有此角色的用户将失去其权限。",
|
||||||
|
"cancel": "取消",
|
||||||
|
"delete": "删除",
|
||||||
|
"deleting": "删除中..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "加载角色失败",
|
||||||
|
"createFailed": "创建角色失败",
|
||||||
|
"updateFailed": "更新角色失败",
|
||||||
|
"nameRequired": "请输入角色名称",
|
||||||
|
"deleteFailed": "删除角色失败"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roleAssign": {
|
||||||
|
"title": "角色分配",
|
||||||
|
"subtitle": "分配和管理用户角色",
|
||||||
|
"assignSection": "分配角色",
|
||||||
|
"userLabel": "用户",
|
||||||
|
"searchPlaceholder": "按名称、用户名、Telegram ID或邮箱搜索...",
|
||||||
|
"clearUser": "清除已选用户",
|
||||||
|
"noUsersFound": "未找到用户",
|
||||||
|
"roleLabel": "角色",
|
||||||
|
"selectRole": "选择角色...",
|
||||||
|
"expiresLabel": "到期时间(可选)",
|
||||||
|
"expiresHint": "留空表示永久分配",
|
||||||
|
"assignButton": "分配",
|
||||||
|
"assigning": "分配中...",
|
||||||
|
"assignSuccess": "角色分配成功",
|
||||||
|
"currentAssignments": "当前分配",
|
||||||
|
"totalAssignments_other": "共 {{count}} 个分配",
|
||||||
|
"noAssignments": "未找到角色分配",
|
||||||
|
"unknownUser": "未知用户",
|
||||||
|
"system": "系统",
|
||||||
|
"permanent": "永久",
|
||||||
|
"expired": "已过期",
|
||||||
|
"revoke": "撤销",
|
||||||
|
"revokeAriaLabel": "撤销 {{user}} 的角色 {{role}}",
|
||||||
|
"table": {
|
||||||
|
"user": "用户",
|
||||||
|
"role": "角色",
|
||||||
|
"assignedBy": "分配者",
|
||||||
|
"assignedAt": "分配时间",
|
||||||
|
"expires": "到期",
|
||||||
|
"actions": "操作"
|
||||||
|
},
|
||||||
|
"pagination": {
|
||||||
|
"showing": "{{from}}-{{to}} / {{total}}",
|
||||||
|
"prev": "上一页",
|
||||||
|
"next": "下一页"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "撤销角色?",
|
||||||
|
"text": "该用户将立即失去与此角色相关的所有权限。",
|
||||||
|
"cancel": "取消",
|
||||||
|
"revoke": "撤销",
|
||||||
|
"revoking": "撤销中..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"userRequired": "请选择用户",
|
||||||
|
"roleRequired": "请选择角色",
|
||||||
|
"assignFailed": "角色分配失败",
|
||||||
|
"revokeFailed": "角色撤销失败"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {
|
||||||
|
"title": "访问策略",
|
||||||
|
"subtitle": "管理ABAC访问控制策略",
|
||||||
|
"createPolicy": "创建策略",
|
||||||
|
"noPolicies": "未找到策略",
|
||||||
|
"inactiveBadge": "未激活",
|
||||||
|
"effectAllow": "允许",
|
||||||
|
"effectDeny": "拒绝",
|
||||||
|
"global": "全局",
|
||||||
|
"unknownRole": "未知角色",
|
||||||
|
"roleLabel": "角色",
|
||||||
|
"priorityLabel": "优先级",
|
||||||
|
"stats": {
|
||||||
|
"total": "策略总数",
|
||||||
|
"allow": "允许",
|
||||||
|
"deny": "拒绝",
|
||||||
|
"active": "活跃"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"createTitle": "创建策略",
|
||||||
|
"editTitle": "编辑策略",
|
||||||
|
"close": "关闭"
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"name": "策略名称",
|
||||||
|
"namePlaceholder": "例如:阻止夜间访问",
|
||||||
|
"description": "描述",
|
||||||
|
"descriptionPlaceholder": "此策略的作用...",
|
||||||
|
"effect": "效果",
|
||||||
|
"resource": "资源",
|
||||||
|
"selectResource": "选择资源...",
|
||||||
|
"actions": "操作",
|
||||||
|
"role": "角色(可选)",
|
||||||
|
"globalOption": "全局(所有角色)",
|
||||||
|
"roleHint": "保留全局以将策略应用于所有角色。",
|
||||||
|
"priority": "优先级",
|
||||||
|
"priorityHint": "优先级高的策略先被评估。同等优先级下,拒绝覆盖允许。",
|
||||||
|
"conditions": "条件",
|
||||||
|
"cancel": "取消",
|
||||||
|
"saving": "保存中...",
|
||||||
|
"save": "保存"
|
||||||
|
},
|
||||||
|
"conditions": {
|
||||||
|
"timeRange": "时间范围",
|
||||||
|
"timeStart": "开始时间",
|
||||||
|
"timeEnd": "结束时间",
|
||||||
|
"ipWhitelist": "IP白名单",
|
||||||
|
"ipPlaceholder": "输入IP并按回车...",
|
||||||
|
"removeIp": "移除 {{ip}}",
|
||||||
|
"ipCount_other": "{{count}} 个IP",
|
||||||
|
"rateLimit": "速率限制",
|
||||||
|
"rateLimitValue": "速率限制值",
|
||||||
|
"rateValue": "{{count}}/小时",
|
||||||
|
"perHour": "每小时操作数"
|
||||||
|
},
|
||||||
|
"confirm": {
|
||||||
|
"title": "删除策略?",
|
||||||
|
"text": "此策略将被永久删除。访问控制规则将被重新计算。",
|
||||||
|
"cancel": "取消",
|
||||||
|
"delete": "删除",
|
||||||
|
"deleting": "删除中..."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "加载策略失败",
|
||||||
|
"createFailed": "创建策略失败",
|
||||||
|
"updateFailed": "更新策略失败",
|
||||||
|
"nameRequired": "请输入策略名称",
|
||||||
|
"resourceRequired": "请选择资源",
|
||||||
|
"actionsRequired": "请至少选择一个操作",
|
||||||
|
"deleteFailed": "删除策略失败"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"auditLog": {
|
||||||
|
"title": "审计日志",
|
||||||
|
"subtitle": "查看系统活动和访问历史",
|
||||||
|
"back": "返回",
|
||||||
|
"exportCsv": "导出CSV",
|
||||||
|
"exportError": "导出失败",
|
||||||
|
"exporting": "导出中...",
|
||||||
|
"refresh": "刷新",
|
||||||
|
"unknownUser": "未知用户",
|
||||||
|
"noEntries": "未找到审计日志条目",
|
||||||
|
"totalEntries_other": "{{count}} 条记录",
|
||||||
|
"autoRefresh": {
|
||||||
|
"label": "自动刷新",
|
||||||
|
"tooltip": "每30秒自动刷新"
|
||||||
|
},
|
||||||
|
"filters": {
|
||||||
|
"title": "筛选",
|
||||||
|
"active": "已激活",
|
||||||
|
"action": "操作",
|
||||||
|
"actionPlaceholder": "按操作搜索...",
|
||||||
|
"resource": "资源类型",
|
||||||
|
"allResources": "所有资源",
|
||||||
|
"status": "状态",
|
||||||
|
"allStatuses": "所有状态",
|
||||||
|
"dateFrom": "开始日期",
|
||||||
|
"dateTo": "结束日期",
|
||||||
|
"apply": "应用",
|
||||||
|
"clear": "清除"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"success": "成功",
|
||||||
|
"denied": "拒绝",
|
||||||
|
"error": "错误"
|
||||||
|
},
|
||||||
|
"resourceTypes": {
|
||||||
|
"users": "用户",
|
||||||
|
"tickets": "工单",
|
||||||
|
"roles": "角色",
|
||||||
|
"policies": "策略",
|
||||||
|
"settings": "设置",
|
||||||
|
"broadcasts": "群发",
|
||||||
|
"tariffs": "套餐",
|
||||||
|
"servers": "服务器",
|
||||||
|
"payments": "支付",
|
||||||
|
"campaigns": "活动",
|
||||||
|
"promocodes": "促销码"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"userAgent": "用户代理",
|
||||||
|
"requestPath": "请求路径",
|
||||||
|
"ipAddress": "IP地址",
|
||||||
|
"timestamp": "时间戳",
|
||||||
|
"before": "之前",
|
||||||
|
"after": "之后",
|
||||||
|
"fullDetails": "完整详情"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"justNow": "刚刚",
|
||||||
|
"minutesAgo_other": "{{count}} 分钟前",
|
||||||
|
"hoursAgo_other": "{{count}} 小时前",
|
||||||
|
"daysAgo_other": "{{count}} 天前"
|
||||||
|
},
|
||||||
|
"pagination": {
|
||||||
|
"pageSize": "每页:",
|
||||||
|
"pageOf": "{{current}} / {{total}}",
|
||||||
|
"first": "第一页",
|
||||||
|
"previous": "上一页",
|
||||||
|
"next": "下一页",
|
||||||
|
"last": "最后一页"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"loadFailed": "加载审计日志失败",
|
||||||
|
"retry": "重试"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"adminUpdates": {
|
"adminUpdates": {
|
||||||
@@ -2818,269 +3080,6 @@
|
|||||||
"node": "节点",
|
"node": "节点",
|
||||||
"requests": "请求数",
|
"requests": "请求数",
|
||||||
"ipHistory": "IP历史"
|
"ipHistory": "IP历史"
|
||||||
},
|
|
||||||
"roles": {
|
|
||||||
"title": "角色与权限",
|
|
||||||
"subtitle": "管理管理员角色及其权限",
|
|
||||||
"createRole": "创建角色",
|
|
||||||
"noRoles": "未找到角色",
|
|
||||||
"systemBadge": "系统",
|
|
||||||
"inactiveBadge": "未激活",
|
|
||||||
"levelLabel": "级别",
|
|
||||||
"usersCount_other": "{{count}} 个用户",
|
|
||||||
"permissionsCount_other": "{{count}} 个权限",
|
|
||||||
"stats": {
|
|
||||||
"totalRoles": "角色总数",
|
|
||||||
"active": "活跃",
|
|
||||||
"system": "系统"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"edit": "编辑",
|
|
||||||
"delete": "删除"
|
|
||||||
},
|
|
||||||
"modal": {
|
|
||||||
"createTitle": "创建角色",
|
|
||||||
"editTitle": "编辑角色",
|
|
||||||
"close": "关闭"
|
|
||||||
},
|
|
||||||
"form": {
|
|
||||||
"name": "角色名称",
|
|
||||||
"namePlaceholder": "例如:版主",
|
|
||||||
"description": "描述",
|
|
||||||
"descriptionPlaceholder": "此角色的用途...",
|
|
||||||
"level": "优先级",
|
|
||||||
"levelValue": "级别值",
|
|
||||||
"levelHint": "级别越高,权限越大。用户只能管理级别低于自己的角色。",
|
|
||||||
"color": "颜色",
|
|
||||||
"presets": "权限预设",
|
|
||||||
"permissions": "权限",
|
|
||||||
"toggleSection": "切换所有 {{section}} 权限",
|
|
||||||
"selectedPermissions_other": "已选择 {{count}} 个权限",
|
|
||||||
"cancel": "取消",
|
|
||||||
"saving": "保存中...",
|
|
||||||
"save": "保存"
|
|
||||||
},
|
|
||||||
"presets": {
|
|
||||||
"moderator": "版主",
|
|
||||||
"marketer": "营销员",
|
|
||||||
"support": "客服"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "删除角色?",
|
|
||||||
"text": "此角色将被永久删除。拥有此角色的用户将失去其权限。",
|
|
||||||
"cancel": "取消",
|
|
||||||
"delete": "删除",
|
|
||||||
"deleting": "删除中..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "加载角色失败",
|
|
||||||
"createFailed": "创建角色失败",
|
|
||||||
"updateFailed": "更新角色失败",
|
|
||||||
"nameRequired": "请输入角色名称",
|
|
||||||
"deleteFailed": "删除角色失败"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"roleAssign": {
|
|
||||||
"title": "角色分配",
|
|
||||||
"subtitle": "分配和管理用户角色",
|
|
||||||
"assignSection": "分配角色",
|
|
||||||
"userLabel": "用户",
|
|
||||||
"searchPlaceholder": "按名称、用户名、Telegram ID或邮箱搜索...",
|
|
||||||
"clearUser": "清除已选用户",
|
|
||||||
"noUsersFound": "未找到用户",
|
|
||||||
"roleLabel": "角色",
|
|
||||||
"selectRole": "选择角色...",
|
|
||||||
"expiresLabel": "到期时间(可选)",
|
|
||||||
"expiresHint": "留空表示永久分配",
|
|
||||||
"assignButton": "分配",
|
|
||||||
"assigning": "分配中...",
|
|
||||||
"assignSuccess": "角色分配成功",
|
|
||||||
"currentAssignments": "当前分配",
|
|
||||||
"totalAssignments_other": "共 {{count}} 个分配",
|
|
||||||
"noAssignments": "未找到角色分配",
|
|
||||||
"unknownUser": "未知用户",
|
|
||||||
"system": "系统",
|
|
||||||
"permanent": "永久",
|
|
||||||
"expired": "已过期",
|
|
||||||
"revoke": "撤销",
|
|
||||||
"revokeAriaLabel": "撤销 {{user}} 的角色 {{role}}",
|
|
||||||
"table": {
|
|
||||||
"user": "用户",
|
|
||||||
"role": "角色",
|
|
||||||
"assignedBy": "分配者",
|
|
||||||
"assignedAt": "分配时间",
|
|
||||||
"expires": "到期",
|
|
||||||
"actions": "操作"
|
|
||||||
},
|
|
||||||
"pagination": {
|
|
||||||
"showing": "{{from}}-{{to}} / {{total}}",
|
|
||||||
"prev": "上一页",
|
|
||||||
"next": "下一页"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "撤销角色?",
|
|
||||||
"text": "该用户将立即失去与此角色相关的所有权限。",
|
|
||||||
"cancel": "取消",
|
|
||||||
"revoke": "撤销",
|
|
||||||
"revoking": "撤销中..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"userRequired": "请选择用户",
|
|
||||||
"roleRequired": "请选择角色",
|
|
||||||
"assignFailed": "角色分配失败",
|
|
||||||
"revokeFailed": "角色撤销失败"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"policies": {
|
|
||||||
"title": "访问策略",
|
|
||||||
"subtitle": "管理ABAC访问控制策略",
|
|
||||||
"createPolicy": "创建策略",
|
|
||||||
"noPolicies": "未找到策略",
|
|
||||||
"inactiveBadge": "未激活",
|
|
||||||
"effectAllow": "允许",
|
|
||||||
"effectDeny": "拒绝",
|
|
||||||
"global": "全局",
|
|
||||||
"unknownRole": "未知角色",
|
|
||||||
"roleLabel": "角色",
|
|
||||||
"priorityLabel": "优先级",
|
|
||||||
"stats": {
|
|
||||||
"total": "策略总数",
|
|
||||||
"allow": "允许",
|
|
||||||
"deny": "拒绝",
|
|
||||||
"active": "活跃"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"edit": "编辑",
|
|
||||||
"delete": "删除"
|
|
||||||
},
|
|
||||||
"modal": {
|
|
||||||
"createTitle": "创建策略",
|
|
||||||
"editTitle": "编辑策略",
|
|
||||||
"close": "关闭"
|
|
||||||
},
|
|
||||||
"form": {
|
|
||||||
"name": "策略名称",
|
|
||||||
"namePlaceholder": "例如:阻止夜间访问",
|
|
||||||
"description": "描述",
|
|
||||||
"descriptionPlaceholder": "此策略的作用...",
|
|
||||||
"effect": "效果",
|
|
||||||
"resource": "资源",
|
|
||||||
"selectResource": "选择资源...",
|
|
||||||
"actions": "操作",
|
|
||||||
"role": "角色(可选)",
|
|
||||||
"globalOption": "全局(所有角色)",
|
|
||||||
"roleHint": "保留全局以将策略应用于所有角色。",
|
|
||||||
"priority": "优先级",
|
|
||||||
"priorityHint": "优先级高的策略先被评估。同等优先级下,拒绝覆盖允许。",
|
|
||||||
"conditions": "条件",
|
|
||||||
"cancel": "取消",
|
|
||||||
"saving": "保存中...",
|
|
||||||
"save": "保存"
|
|
||||||
},
|
|
||||||
"conditions": {
|
|
||||||
"timeRange": "时间范围",
|
|
||||||
"timeStart": "开始时间",
|
|
||||||
"timeEnd": "结束时间",
|
|
||||||
"ipWhitelist": "IP白名单",
|
|
||||||
"ipPlaceholder": "输入IP并按回车...",
|
|
||||||
"removeIp": "移除 {{ip}}",
|
|
||||||
"ipCount_other": "{{count}} 个IP",
|
|
||||||
"rateLimit": "速率限制",
|
|
||||||
"rateLimitValue": "速率限制值",
|
|
||||||
"rateValue": "{{count}}/小时",
|
|
||||||
"perHour": "每小时操作数"
|
|
||||||
},
|
|
||||||
"confirm": {
|
|
||||||
"title": "删除策略?",
|
|
||||||
"text": "此策略将被永久删除。访问控制规则将被重新计算。",
|
|
||||||
"cancel": "取消",
|
|
||||||
"delete": "删除",
|
|
||||||
"deleting": "删除中..."
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "加载策略失败",
|
|
||||||
"createFailed": "创建策略失败",
|
|
||||||
"updateFailed": "更新策略失败",
|
|
||||||
"nameRequired": "请输入策略名称",
|
|
||||||
"resourceRequired": "请选择资源",
|
|
||||||
"actionsRequired": "请至少选择一个操作",
|
|
||||||
"deleteFailed": "删除策略失败"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"auditLog": {
|
|
||||||
"title": "审计日志",
|
|
||||||
"subtitle": "查看系统活动和访问历史",
|
|
||||||
"back": "返回",
|
|
||||||
"exportCsv": "导出CSV",
|
|
||||||
"exportError": "导出失败",
|
|
||||||
"exporting": "导出中...",
|
|
||||||
"refresh": "刷新",
|
|
||||||
"unknownUser": "未知用户",
|
|
||||||
"noEntries": "未找到审计日志条目",
|
|
||||||
"totalEntries_other": "{{count}} 条记录",
|
|
||||||
"autoRefresh": {
|
|
||||||
"label": "自动刷新",
|
|
||||||
"tooltip": "每30秒自动刷新"
|
|
||||||
},
|
|
||||||
"filters": {
|
|
||||||
"title": "筛选",
|
|
||||||
"active": "已激活",
|
|
||||||
"action": "操作",
|
|
||||||
"actionPlaceholder": "按操作搜索...",
|
|
||||||
"resource": "资源类型",
|
|
||||||
"allResources": "所有资源",
|
|
||||||
"status": "状态",
|
|
||||||
"allStatuses": "所有状态",
|
|
||||||
"dateFrom": "开始日期",
|
|
||||||
"dateTo": "结束日期",
|
|
||||||
"apply": "应用",
|
|
||||||
"clear": "清除"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"success": "成功",
|
|
||||||
"denied": "拒绝",
|
|
||||||
"error": "错误"
|
|
||||||
},
|
|
||||||
"resourceTypes": {
|
|
||||||
"users": "用户",
|
|
||||||
"tickets": "工单",
|
|
||||||
"roles": "角色",
|
|
||||||
"policies": "策略",
|
|
||||||
"settings": "设置",
|
|
||||||
"broadcasts": "群发",
|
|
||||||
"tariffs": "套餐",
|
|
||||||
"servers": "服务器",
|
|
||||||
"payments": "支付",
|
|
||||||
"campaigns": "活动",
|
|
||||||
"promocodes": "促销码"
|
|
||||||
},
|
|
||||||
"details": {
|
|
||||||
"userAgent": "用户代理",
|
|
||||||
"requestPath": "请求路径",
|
|
||||||
"ipAddress": "IP地址",
|
|
||||||
"timestamp": "时间戳",
|
|
||||||
"before": "之前",
|
|
||||||
"after": "之后",
|
|
||||||
"fullDetails": "完整详情"
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"justNow": "刚刚",
|
|
||||||
"minutesAgo_other": "{{count}} 分钟前",
|
|
||||||
"hoursAgo_other": "{{count}} 小时前",
|
|
||||||
"daysAgo_other": "{{count}} 天前"
|
|
||||||
},
|
|
||||||
"pagination": {
|
|
||||||
"pageSize": "每页:",
|
|
||||||
"pageOf": "{{current}} / {{total}}",
|
|
||||||
"first": "第一页",
|
|
||||||
"previous": "上一页",
|
|
||||||
"next": "下一页",
|
|
||||||
"last": "最后一页"
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"loadFailed": "加载审计日志失败",
|
|
||||||
"retry": "重试"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,27 +118,6 @@ const INITIAL_FILTERS: FiltersState = {
|
|||||||
|
|
||||||
// === Utility functions ===
|
// === Utility functions ===
|
||||||
|
|
||||||
function getStatusFromEntry(entry: AuditLogEntry): string {
|
|
||||||
const details = entry.details;
|
|
||||||
if (typeof details.status === 'string') return details.status;
|
|
||||||
if (typeof details.error === 'string') return 'error';
|
|
||||||
if (details.denied === true) return 'denied';
|
|
||||||
return 'success';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMethodFromEntry(entry: AuditLogEntry): string | null {
|
|
||||||
const details = entry.details;
|
|
||||||
if (typeof details.method === 'string') return details.method.toUpperCase();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRequestPathFromEntry(entry: AuditLogEntry): string | null {
|
|
||||||
const details = entry.details;
|
|
||||||
if (typeof details.path === 'string') return details.path;
|
|
||||||
if (typeof details.request_path === 'string') return details.request_path;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatRelativeTime(
|
function formatRelativeTime(
|
||||||
dateString: string,
|
dateString: string,
|
||||||
t: (key: string, opts?: Record<string, unknown>) => string,
|
t: (key: string, opts?: Record<string, unknown>) => string,
|
||||||
@@ -216,9 +195,9 @@ interface LogEntryCardProps {
|
|||||||
|
|
||||||
function LogEntryCard({ entry, isExpanded, onToggle }: LogEntryCardProps) {
|
function LogEntryCard({ entry, isExpanded, onToggle }: LogEntryCardProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const status = getStatusFromEntry(entry);
|
const status = entry.status;
|
||||||
const method = getMethodFromEntry(entry);
|
const method = entry.request_method?.toUpperCase() ?? null;
|
||||||
const requestPath = getRequestPathFromEntry(entry);
|
const requestPath = entry.request_path;
|
||||||
const userName = entry.user_first_name || entry.user_email || t('admin.auditLog.unknownUser');
|
const userName = entry.user_first_name || entry.user_email || t('admin.auditLog.unknownUser');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -254,7 +233,7 @@ function LogEntryCard({ entry, isExpanded, onToggle }: LogEntryCardProps) {
|
|||||||
|
|
||||||
{/* Resource */}
|
{/* Resource */}
|
||||||
<div className="flex shrink-0 items-center gap-2 text-sm text-dark-400">
|
<div className="flex shrink-0 items-center gap-2 text-sm text-dark-400">
|
||||||
<span>{entry.resource}</span>
|
<span>{entry.resource_type}</span>
|
||||||
{entry.resource_id && (
|
{entry.resource_id && (
|
||||||
<span className="rounded bg-dark-700 px-1.5 py-0.5 font-mono text-xs text-dark-300">
|
<span className="rounded bg-dark-700 px-1.5 py-0.5 font-mono text-xs text-dark-300">
|
||||||
#{entry.resource_id}
|
#{entry.resource_id}
|
||||||
@@ -323,7 +302,7 @@ function LogEntryCard({ entry, isExpanded, onToggle }: LogEntryCardProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Before/after diff */}
|
{/* Before/after diff */}
|
||||||
{'before' in entry.details && entry.details.before != null && (
|
{entry.details && 'before' in entry.details && entry.details.before != null && (
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-1 text-xs font-medium uppercase text-dark-500">
|
<p className="mb-1 text-xs font-medium uppercase text-dark-500">
|
||||||
{t('admin.auditLog.details.before')}
|
{t('admin.auditLog.details.before')}
|
||||||
@@ -334,7 +313,7 @@ function LogEntryCard({ entry, isExpanded, onToggle }: LogEntryCardProps) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{'after' in entry.details && entry.details.after != null && (
|
{entry.details && 'after' in entry.details && entry.details.after != null && (
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-1 text-xs font-medium uppercase text-dark-500">
|
<p className="mb-1 text-xs font-medium uppercase text-dark-500">
|
||||||
{t('admin.auditLog.details.after')}
|
{t('admin.auditLog.details.after')}
|
||||||
@@ -347,14 +326,16 @@ function LogEntryCard({ entry, isExpanded, onToggle }: LogEntryCardProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Full details JSON */}
|
{/* Full details JSON */}
|
||||||
<div className="mt-4">
|
{entry.details && (
|
||||||
<p className="mb-1 text-xs font-medium uppercase text-dark-500">
|
<div className="mt-4">
|
||||||
{t('admin.auditLog.details.fullDetails')}
|
<p className="mb-1 text-xs font-medium uppercase text-dark-500">
|
||||||
</p>
|
{t('admin.auditLog.details.fullDetails')}
|
||||||
<pre className="max-h-60 overflow-auto rounded-lg bg-dark-900 p-3 text-xs text-dark-300">
|
</p>
|
||||||
{JSON.stringify(entry.details, null, 2)}
|
<pre className="max-h-60 overflow-auto rounded-lg bg-dark-900 p-3 text-xs text-dark-300">
|
||||||
</pre>
|
{JSON.stringify(entry.details, null, 2)}
|
||||||
</div>
|
</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -397,7 +378,10 @@ export default function AdminAuditLog() {
|
|||||||
params.action = appliedFilters.action.trim();
|
params.action = appliedFilters.action.trim();
|
||||||
}
|
}
|
||||||
if (appliedFilters.resource) {
|
if (appliedFilters.resource) {
|
||||||
params.resource = appliedFilters.resource;
|
params.resource_type = appliedFilters.resource;
|
||||||
|
}
|
||||||
|
if (appliedFilters.status) {
|
||||||
|
params.status = appliedFilters.status;
|
||||||
}
|
}
|
||||||
if (appliedFilters.dateFrom) {
|
if (appliedFilters.dateFrom) {
|
||||||
params.date_from = appliedFilters.dateFrom;
|
params.date_from = appliedFilters.dateFrom;
|
||||||
@@ -467,7 +451,7 @@ export default function AdminAuditLog() {
|
|||||||
try {
|
try {
|
||||||
const exportParams: AuditLogFilters = {};
|
const exportParams: AuditLogFilters = {};
|
||||||
if (appliedFilters.action.trim()) exportParams.action = appliedFilters.action.trim();
|
if (appliedFilters.action.trim()) exportParams.action = appliedFilters.action.trim();
|
||||||
if (appliedFilters.resource) exportParams.resource = appliedFilters.resource;
|
if (appliedFilters.resource) exportParams.resource_type = appliedFilters.resource;
|
||||||
if (appliedFilters.dateFrom) exportParams.date_from = appliedFilters.dateFrom;
|
if (appliedFilters.dateFrom) exportParams.date_from = appliedFilters.dateFrom;
|
||||||
if (appliedFilters.dateTo) exportParams.date_to = appliedFilters.dateTo;
|
if (appliedFilters.dateTo) exportParams.date_to = appliedFilters.dateTo;
|
||||||
|
|
||||||
@@ -495,7 +479,7 @@ export default function AdminAuditLog() {
|
|||||||
// Filter status entries client-side (status is derived from details, not a backend field)
|
// Filter status entries client-side (status is derived from details, not a backend field)
|
||||||
const filteredEntries = useMemo(() => {
|
const filteredEntries = useMemo(() => {
|
||||||
if (!appliedFilters.status) return entries;
|
if (!appliedFilters.status) return entries;
|
||||||
return entries.filter((entry) => getStatusFromEntry(entry) === appliedFilters.status);
|
return entries.filter((entry) => entry.status === appliedFilters.status);
|
||||||
}, [entries, appliedFilters.status]);
|
}, [entries, appliedFilters.status]);
|
||||||
|
|
||||||
const hasActiveFilters = useMemo(() => {
|
const hasActiveFilters = useMemo(() => {
|
||||||
|
|||||||
@@ -433,14 +433,7 @@ export default function AdminPolicies() {
|
|||||||
// Determine the role_id from conditions if present
|
// Determine the role_id from conditions if present
|
||||||
const roleId = typeof policy.conditions.role_id === 'number' ? policy.conditions.role_id : null;
|
const roleId = typeof policy.conditions.role_id === 'number' ? policy.conditions.role_id : null;
|
||||||
|
|
||||||
// Parse actions — the API stores a single `action` string which may be comma-separated or
|
const actions = Array.isArray(policy.actions) ? policy.actions : [];
|
||||||
// a single action. Normalize to an array.
|
|
||||||
const actions = policy.action
|
|
||||||
? policy.action
|
|
||||||
.split(',')
|
|
||||||
.map((a) => a.trim())
|
|
||||||
.filter(Boolean)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
setEditingPolicy(policy);
|
setEditingPolicy(policy);
|
||||||
setFormData({
|
setFormData({
|
||||||
@@ -511,17 +504,16 @@ export default function AdminPolicies() {
|
|||||||
conditionsPayload.role_id = formData.role_id;
|
conditionsPayload.role_id = formData.role_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionString = formData.actions.join(',');
|
|
||||||
|
|
||||||
if (editingPolicy) {
|
if (editingPolicy) {
|
||||||
const payload: UpdatePolicyPayload = {
|
const payload: UpdatePolicyPayload = {
|
||||||
name: formData.name.trim(),
|
name: formData.name.trim(),
|
||||||
description: formData.description.trim() || null,
|
description: formData.description.trim() || null,
|
||||||
effect: formData.effect,
|
effect: formData.effect,
|
||||||
resource: formData.resource,
|
resource: formData.resource,
|
||||||
action: actionString,
|
actions: formData.actions,
|
||||||
conditions: conditionsPayload,
|
conditions: conditionsPayload,
|
||||||
priority: formData.priority,
|
priority: formData.priority,
|
||||||
|
role_id: formData.role_id,
|
||||||
};
|
};
|
||||||
updateMutation.mutate({ id: editingPolicy.id, payload });
|
updateMutation.mutate({ id: editingPolicy.id, payload });
|
||||||
} else {
|
} else {
|
||||||
@@ -530,9 +522,10 @@ export default function AdminPolicies() {
|
|||||||
description: formData.description.trim() || null,
|
description: formData.description.trim() || null,
|
||||||
effect: formData.effect,
|
effect: formData.effect,
|
||||||
resource: formData.resource,
|
resource: formData.resource,
|
||||||
action: actionString,
|
actions: formData.actions,
|
||||||
conditions: conditionsPayload,
|
conditions: conditionsPayload,
|
||||||
priority: formData.priority,
|
priority: formData.priority,
|
||||||
|
role_id: formData.role_id,
|
||||||
};
|
};
|
||||||
createMutation.mutate(payload);
|
createMutation.mutate(payload);
|
||||||
}
|
}
|
||||||
@@ -705,7 +698,9 @@ export default function AdminPolicies() {
|
|||||||
{policy.resource}
|
{policy.resource}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-dark-500">:</span>
|
<span className="text-dark-500">:</span>
|
||||||
<span className="font-mono text-xs text-dark-300">{policy.action}</span>
|
<span className="font-mono text-xs text-dark-300">
|
||||||
|
{(policy.actions ?? []).join(', ')}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Info row */}
|
{/* Info row */}
|
||||||
|
|||||||
Reference in New Issue
Block a user