fix: defaut ui triage (#4802)

* fix: theme-aware payment paths, auto-group validation, route guards, perf group filtering

- Add common.ThemeAwarePath to generate correct redirect URLs based on
  active theme (default vs classic), replacing hardcoded /console/* paths
  in 7 controllers and service/quota.go (#4765)
- Validate auto-group availability against getUserGroups before defaulting
  form values; playground falls back to 'default' group when 'auto' is
  unavailable (#4796, #4799)
- Enforce HeaderNavModules settings in rankings route (frontend + backend
  API) and SidebarModulesAdmin in playground route to block direct URL
  access when features are disabled (#4704, #4512)
- Filter perf_metrics API response to only include currently configured
  groups, hiding stale data from deleted groups (#4790)
- Preserve query params (pay=success/fail) in /console/topup → /wallet
  frontend redirect

* fix: update hero section text and localization strings for clarity
This commit is contained in:
Calcium-Ion
2026-05-12 16:47:02 +08:00
committed by GitHub
parent a720064d91
commit 469d3747af
27 changed files with 261 additions and 71 deletions
+80
View File
@@ -0,0 +1,80 @@
/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
type ModuleAccess = { enabled: boolean; requireAuth: boolean }
const DEFAULTS: Record<string, ModuleAccess> = {
pricing: { enabled: true, requireAuth: false },
rankings: { enabled: true, requireAuth: false },
}
function parseAccess(raw: unknown, fallback: ModuleAccess): ModuleAccess {
if (typeof raw === 'boolean') return { enabled: raw, requireAuth: fallback.requireAuth }
if (raw && typeof raw === 'object') {
const r = raw as Record<string, unknown>
return {
enabled: typeof r.enabled === 'boolean' ? r.enabled : fallback.enabled,
requireAuth: typeof r.requireAuth === 'boolean' ? r.requireAuth : fallback.requireAuth,
}
}
return { ...fallback }
}
function getCachedStatus(): Record<string, unknown> | null {
try {
const raw = window.localStorage.getItem('status')
return raw ? (JSON.parse(raw) as Record<string, unknown>) : null
} catch {
return null
}
}
export function getModuleAccess(module: 'rankings' | 'pricing'): ModuleAccess {
const status = getCachedStatus()
if (!status) return DEFAULTS[module]
const rawNav = status.HeaderNavModules
if (!rawNav || String(rawNav).trim() === '') return DEFAULTS[module]
try {
const parsed = JSON.parse(String(rawNav)) as Record<string, unknown>
return parseAccess(parsed[module], DEFAULTS[module])
} catch {
return DEFAULTS[module]
}
}
export function isSidebarModuleEnabled(section: string, module: string): boolean {
const status = getCachedStatus()
if (!status) return true
const raw = status.SidebarModulesAdmin
if (!raw || String(raw).trim() === '') return true
try {
const parsed = JSON.parse(String(raw)) as Record<string, Record<string, boolean>>
const sectionConfig = parsed[section]
if (!sectionConfig) return true
if (sectionConfig.enabled === false) return false
if (sectionConfig[module] === false) return false
return true
} catch {
return true
}
}