✨ feat(ratio-sync, ui): add built‑in “Official Ratio Preset” and harden upstream sync
Backend (controller/ratio_sync.go): - Add built‑in official upstream to GetSyncableChannels (ID: -100, BaseURL: https://basellm.github.io) - Support absolute endpoint URLs; otherwise join BaseURL + endpoint (defaults to /api/ratio_config) - Harden HTTP client: - IPv4‑first with IPv6 fallback for github.io - Add ResponseHeaderTimeout - 3 attempts with exponential backoff (200/400/800ms) - Validate Content-Type and limit response body to 10MB (safe decode via io.LimitReader) - Robust parsing: support type1 ratio_config map and type2 pricing list - Use net.SplitHostPort for host parsing - Use float tolerance in differences comparison to avoid false mismatches - Remove unused code (tryDirect) and improve warnings Frontend: - UpstreamRatioSync.jsx: auto-assign official endpoint to /llm-metadata/api/newapi/ratio_config-v1-base.json - ChannelSelectorModal.jsx: - Pin the official source at the top of the list - Show a green “官方” tag next to the status - Refactor status renderer to accept the full record Notes: - Backward compatible; no API surface changes - Official ratio_config reference: https://basellm.github.io/llm-metadata/api/newapi/ratio_config-v1-base.json
This commit is contained in:
@@ -1,3 +1,21 @@
|
||||
/*
|
||||
Copyright (C) 2025 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
|
||||
*/
|
||||
import { useState, useEffect } from 'react';
|
||||
import { API } from '../../helpers';
|
||||
|
||||
@@ -52,22 +70,22 @@ export const useUserPermissions = () => {
|
||||
const isSidebarModuleAllowed = (sectionKey, moduleKey) => {
|
||||
if (!permissions?.sidebar_modules) return true;
|
||||
const sectionPerms = permissions.sidebar_modules[sectionKey];
|
||||
|
||||
|
||||
// 如果整个区域被禁用
|
||||
if (sectionPerms === false) return false;
|
||||
|
||||
|
||||
// 如果区域存在但模块被禁用
|
||||
if (sectionPerms && sectionPerms[moduleKey] === false) return false;
|
||||
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// 获取允许的边栏区域列表
|
||||
const getAllowedSidebarSections = () => {
|
||||
if (!permissions?.sidebar_modules) return [];
|
||||
|
||||
return Object.keys(permissions.sidebar_modules).filter(sectionKey =>
|
||||
isSidebarSectionAllowed(sectionKey)
|
||||
|
||||
return Object.keys(permissions.sidebar_modules).filter((sectionKey) =>
|
||||
isSidebarSectionAllowed(sectionKey),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -75,12 +93,13 @@ export const useUserPermissions = () => {
|
||||
const getAllowedSidebarModules = (sectionKey) => {
|
||||
if (!permissions?.sidebar_modules) return [];
|
||||
const sectionPerms = permissions.sidebar_modules[sectionKey];
|
||||
|
||||
|
||||
if (sectionPerms === false) return [];
|
||||
if (!sectionPerms || typeof sectionPerms !== 'object') return [];
|
||||
|
||||
return Object.keys(sectionPerms).filter(moduleKey =>
|
||||
moduleKey !== 'enabled' && sectionPerms[moduleKey] === true
|
||||
|
||||
return Object.keys(sectionPerms).filter(
|
||||
(moduleKey) =>
|
||||
moduleKey !== 'enabled' && sectionPerms[moduleKey] === true,
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user