refactor(quota,auth): change page size selector to number input with range 3-30

This commit is contained in:
Supra4E8C
2026-01-02 17:27:35 +08:00
parent 82bf1806ed
commit 3446280987
5 changed files with 49 additions and 33 deletions

1
.gitignore vendored
View File

@@ -12,6 +12,7 @@ CLAUDE.md
AGENTS.md
antigravity_usage.json
codex_usage.json
style.md
node_modules
dist

View File

@@ -19,6 +19,12 @@ type QuotaUpdater<T> = T | ((prev: T) => T);
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> {
pageSize: number;
totalPages: number;
@@ -34,7 +40,7 @@ interface QuotaPaginationState<T> {
const useQuotaPagination = <T,>(items: T[], defaultPageSize = 6): QuotaPaginationState<T> => {
const [page, setPage] = useState(1);
const [pageSize, setPageSizeState] = useState(defaultPageSize);
const [pageSize, setPageSizeState] = useState(() => clampCardPageSize(defaultPageSize));
const [loading, setLoadingState] = useState(false);
const [loadingScope, setLoadingScope] = useState<'page' | 'all' | null>(null);
@@ -51,7 +57,7 @@ const useQuotaPagination = <T,>(items: T[], defaultPageSize = 6): QuotaPaginatio
}, [items, currentPage, pageSize]);
const setPageSize = useCallback((size: number) => {
setPageSizeState(size);
setPageSizeState(clampCardPageSize(size));
setPage(1);
}, []);
@@ -183,17 +189,19 @@ export function QuotaSection<TState extends QuotaStatusState, TData>({
<div className={config.controlsClassName}>
<div className={config.controlClassName}>
<label>{t('auth_files.page_size_label')}</label>
<select
<input
className={styles.pageSizeSelect}
type="number"
min={MIN_CARD_PAGE_SIZE}
max={MAX_CARD_PAGE_SIZE}
step={1}
value={pageSize}
onChange={(e) => setPageSize(Number(e.target.value) || 6)}
>
<option value={6}>6</option>
<option value={9}>9</option>
<option value={12}>12</option>
<option value={18}>18</option>
<option value={24}>24</option>
</select>
onChange={(e) => {
const value = e.currentTarget.valueAsNumber;
if (!Number.isFinite(value)) return;
setPageSize(value);
}}
/>
</div>
<div className={config.controlClassName}>
<label>{t('common.info')}</label>

View File

@@ -124,7 +124,7 @@
background-color: var(--bg-primary);
color: var(--text-primary);
font-size: 14px;
cursor: pointer;
cursor: text;
height: 38px;
box-sizing: border-box;

View File

@@ -78,6 +78,11 @@ const OAUTH_PROVIDER_PRESETS = [
];
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 {
provider: string;
@@ -172,10 +177,10 @@ export function AuthFilesPage() {
const [modelsFileType, setModelsFileType] = useState('');
const [modelsError, setModelsError] = useState<'unsupported' | null>(null);
// OAuth 排除模型相关
const [excluded, setExcluded] = useState<Record<string, string[]>>({});
// OAuth 排除模型相关
const [excluded, setExcluded] = useState<Record<string, string[]>>({});
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 [savingExcluded, setSavingExcluded] = useState(false);
@@ -184,6 +189,13 @@ export function AuthFilesPage() {
const excludedUnsupportedRef = useRef(false);
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 => {
@@ -853,23 +865,18 @@ export function AuthFilesPage() {
placeholder={t('auth_files.search_placeholder')}
/>
</div>
<div className={styles.filterItem}>
<label>{t('auth_files.page_size_label')}</label>
<select
className={styles.pageSizeSelect}
value={pageSize}
onChange={(e) => {
setPageSize(Number(e.target.value) || 9);
setPage(1);
}}
>
<option value={6}>6</option>
<option value={9}>9</option>
<option value={12}>12</option>
<option value={18}>18</option>
<option value={24}>24</option>
</select>
</div>
<div className={styles.filterItem}>
<label>{t('auth_files.page_size_label')}</label>
<input
className={styles.pageSizeSelect}
type="number"
min={MIN_CARD_PAGE_SIZE}
max={MAX_CARD_PAGE_SIZE}
step={1}
value={pageSize}
onChange={handlePageSizeChange}
/>
</div>
<div className={styles.filterItem}>
<label>{t('common.info')}</label>
<div className={styles.statsInfo}>

View File

@@ -48,7 +48,7 @@
background-color: var(--bg-primary);
color: var(--text-primary);
font-size: 14px;
cursor: pointer;
cursor: text;
height: 38px;
box-sizing: border-box;