mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-02 02:40:50 +08:00
refactor(quota,auth): change page size selector to number input with range 3-30
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,6 +12,7 @@ CLAUDE.md
|
|||||||
AGENTS.md
|
AGENTS.md
|
||||||
antigravity_usage.json
|
antigravity_usage.json
|
||||||
codex_usage.json
|
codex_usage.json
|
||||||
|
style.md
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ type QuotaUpdater<T> = T | ((prev: T) => T);
|
|||||||
|
|
||||||
type QuotaSetter<T> = (updater: QuotaUpdater<T>) => void;
|
type QuotaSetter<T> = (updater: QuotaUpdater<T>) => void;
|
||||||
|
|
||||||
|
const MIN_CARD_PAGE_SIZE = 3;
|
||||||
|
const MAX_CARD_PAGE_SIZE = 30;
|
||||||
|
|
||||||
|
const clampCardPageSize = (value: number) =>
|
||||||
|
Math.min(MAX_CARD_PAGE_SIZE, Math.max(MIN_CARD_PAGE_SIZE, Math.round(value)));
|
||||||
|
|
||||||
interface QuotaPaginationState<T> {
|
interface QuotaPaginationState<T> {
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
@@ -34,7 +40,7 @@ interface QuotaPaginationState<T> {
|
|||||||
|
|
||||||
const useQuotaPagination = <T,>(items: T[], defaultPageSize = 6): QuotaPaginationState<T> => {
|
const useQuotaPagination = <T,>(items: T[], defaultPageSize = 6): QuotaPaginationState<T> => {
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [pageSize, setPageSizeState] = useState(defaultPageSize);
|
const [pageSize, setPageSizeState] = useState(() => clampCardPageSize(defaultPageSize));
|
||||||
const [loading, setLoadingState] = useState(false);
|
const [loading, setLoadingState] = useState(false);
|
||||||
const [loadingScope, setLoadingScope] = useState<'page' | 'all' | null>(null);
|
const [loadingScope, setLoadingScope] = useState<'page' | 'all' | null>(null);
|
||||||
|
|
||||||
@@ -51,7 +57,7 @@ const useQuotaPagination = <T,>(items: T[], defaultPageSize = 6): QuotaPaginatio
|
|||||||
}, [items, currentPage, pageSize]);
|
}, [items, currentPage, pageSize]);
|
||||||
|
|
||||||
const setPageSize = useCallback((size: number) => {
|
const setPageSize = useCallback((size: number) => {
|
||||||
setPageSizeState(size);
|
setPageSizeState(clampCardPageSize(size));
|
||||||
setPage(1);
|
setPage(1);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -183,17 +189,19 @@ export function QuotaSection<TState extends QuotaStatusState, TData>({
|
|||||||
<div className={config.controlsClassName}>
|
<div className={config.controlsClassName}>
|
||||||
<div className={config.controlClassName}>
|
<div className={config.controlClassName}>
|
||||||
<label>{t('auth_files.page_size_label')}</label>
|
<label>{t('auth_files.page_size_label')}</label>
|
||||||
<select
|
<input
|
||||||
className={styles.pageSizeSelect}
|
className={styles.pageSizeSelect}
|
||||||
|
type="number"
|
||||||
|
min={MIN_CARD_PAGE_SIZE}
|
||||||
|
max={MAX_CARD_PAGE_SIZE}
|
||||||
|
step={1}
|
||||||
value={pageSize}
|
value={pageSize}
|
||||||
onChange={(e) => setPageSize(Number(e.target.value) || 6)}
|
onChange={(e) => {
|
||||||
>
|
const value = e.currentTarget.valueAsNumber;
|
||||||
<option value={6}>6</option>
|
if (!Number.isFinite(value)) return;
|
||||||
<option value={9}>9</option>
|
setPageSize(value);
|
||||||
<option value={12}>12</option>
|
}}
|
||||||
<option value={18}>18</option>
|
/>
|
||||||
<option value={24}>24</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={config.controlClassName}>
|
<div className={config.controlClassName}>
|
||||||
<label>{t('common.info')}</label>
|
<label>{t('common.info')}</label>
|
||||||
|
|||||||
@@ -124,7 +124,7 @@
|
|||||||
background-color: var(--bg-primary);
|
background-color: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
cursor: pointer;
|
cursor: text;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,11 @@ const OAUTH_PROVIDER_PRESETS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const OAUTH_PROVIDER_EXCLUDES = new Set(['all', 'unknown', 'empty']);
|
const OAUTH_PROVIDER_EXCLUDES = new Set(['all', 'unknown', 'empty']);
|
||||||
|
const MIN_CARD_PAGE_SIZE = 3;
|
||||||
|
const MAX_CARD_PAGE_SIZE = 30;
|
||||||
|
|
||||||
|
const clampCardPageSize = (value: number) =>
|
||||||
|
Math.min(MAX_CARD_PAGE_SIZE, Math.max(MIN_CARD_PAGE_SIZE, Math.round(value)));
|
||||||
|
|
||||||
interface ExcludedFormState {
|
interface ExcludedFormState {
|
||||||
provider: string;
|
provider: string;
|
||||||
@@ -172,10 +177,10 @@ export function AuthFilesPage() {
|
|||||||
const [modelsFileType, setModelsFileType] = useState('');
|
const [modelsFileType, setModelsFileType] = useState('');
|
||||||
const [modelsError, setModelsError] = useState<'unsupported' | null>(null);
|
const [modelsError, setModelsError] = useState<'unsupported' | null>(null);
|
||||||
|
|
||||||
// OAuth 排除模型相关
|
// OAuth 排除模型相关
|
||||||
const [excluded, setExcluded] = useState<Record<string, string[]>>({});
|
const [excluded, setExcluded] = useState<Record<string, string[]>>({});
|
||||||
const [excludedError, setExcludedError] = useState<'unsupported' | null>(null);
|
const [excludedError, setExcludedError] = useState<'unsupported' | null>(null);
|
||||||
const [excludedModalOpen, setExcludedModalOpen] = useState(false);
|
const [excludedModalOpen, setExcludedModalOpen] = useState(false);
|
||||||
const [excludedForm, setExcludedForm] = useState<ExcludedFormState>({ provider: '', modelsText: '' });
|
const [excludedForm, setExcludedForm] = useState<ExcludedFormState>({ provider: '', modelsText: '' });
|
||||||
const [savingExcluded, setSavingExcluded] = useState(false);
|
const [savingExcluded, setSavingExcluded] = useState(false);
|
||||||
|
|
||||||
@@ -184,6 +189,13 @@ export function AuthFilesPage() {
|
|||||||
const excludedUnsupportedRef = useRef(false);
|
const excludedUnsupportedRef = useRef(false);
|
||||||
|
|
||||||
const disableControls = connectionStatus !== 'connected';
|
const disableControls = connectionStatus !== 'connected';
|
||||||
|
|
||||||
|
const handlePageSizeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = event.currentTarget.valueAsNumber;
|
||||||
|
if (!Number.isFinite(value)) return;
|
||||||
|
setPageSize(clampCardPageSize(value));
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
|
||||||
// 格式化修改时间
|
// 格式化修改时间
|
||||||
const formatModified = (item: AuthFileItem): string => {
|
const formatModified = (item: AuthFileItem): string => {
|
||||||
@@ -853,23 +865,18 @@ export function AuthFilesPage() {
|
|||||||
placeholder={t('auth_files.search_placeholder')}
|
placeholder={t('auth_files.search_placeholder')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.filterItem}>
|
<div className={styles.filterItem}>
|
||||||
<label>{t('auth_files.page_size_label')}</label>
|
<label>{t('auth_files.page_size_label')}</label>
|
||||||
<select
|
<input
|
||||||
className={styles.pageSizeSelect}
|
className={styles.pageSizeSelect}
|
||||||
value={pageSize}
|
type="number"
|
||||||
onChange={(e) => {
|
min={MIN_CARD_PAGE_SIZE}
|
||||||
setPageSize(Number(e.target.value) || 9);
|
max={MAX_CARD_PAGE_SIZE}
|
||||||
setPage(1);
|
step={1}
|
||||||
}}
|
value={pageSize}
|
||||||
>
|
onChange={handlePageSizeChange}
|
||||||
<option value={6}>6</option>
|
/>
|
||||||
<option value={9}>9</option>
|
</div>
|
||||||
<option value={12}>12</option>
|
|
||||||
<option value={18}>18</option>
|
|
||||||
<option value={24}>24</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className={styles.filterItem}>
|
<div className={styles.filterItem}>
|
||||||
<label>{t('common.info')}</label>
|
<label>{t('common.info')}</label>
|
||||||
<div className={styles.statsInfo}>
|
<div className={styles.statsInfo}>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
background-color: var(--bg-primary);
|
background-color: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
cursor: pointer;
|
cursor: text;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user