Skip to content

Add user file quota display in header - #16

Merged
Ahmath-Gadji merged 2 commits into
mainfrom
feat/handling_user_file_quota
Feb 12, 2026
Merged

Add user file quota display in header#16
Ahmath-Gadji merged 2 commits into
mainfrom
feat/handling_user_file_quota

Conversation

@Ahmath-Gadji

@Ahmath-Gadji Ahmath-Gadji commented Feb 8, 2026

Copy link
Copy Markdown
Contributor

This PR adds frontend support for displaying and enforcing the user file quota in OpenRAG. It surfaces real-time quota information in the indexer header and prevents uploads when the quota is reached.
See related PR: linagora/openrag#232.

Changes

  • Introduce a UserInfo type with indexed_files, pending_files, total_files, and file_quota
  • Add fetchUserInfo API function to retrieve user data from the /users/info endpoint
  • Display quota metrics in the indexer header (indexed files, pending files, and quota usage)
  • Render an ∞ symbol when the backend returns -1 (infinite quota)
  • Disable the upload button when the file quota is reached, with a tooltip explaining why
  • Auto-refresh user info every 5 seconds to keep the quota display in sync

Impact

  • Improves transparency by showing users their current quota usage
  • Prevents failed uploads by enforcing quota limits at the UI level
  • Keeps the interface responsive to backend changes via periodic refresh

- Add UserInfo type with indexed_files, pending_files, total_files, and file_quota fields
- Add fetchUserInfo API function to retrieve user info from /users/info endpoint
- Display file quota information in the indexer header (indexed files, pending files, quota usage)
- Show ∞ symbol when quota is infinite (-1 from backend)
- Disable upload button when file quota is reached (gray out with tooltip)
- Auto-refresh user info every 10 seconds to keep quota display updated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds UI + API plumbing to surface user file quota information in the indexer header and prevent uploads when the quota is reached.

Changes:

  • Introduces UserInfo type/state and an fetchUserInfo() API call to /users/info.
  • Displays indexed/pending file counts and quota usage in the indexer header (including ∞ for unlimited).
  • Enforces quota in the upload flow by disabling uploads / truncating selection and showing a warning.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/routes/indexer/+layout.svelte Fetches user info and periodically refreshes it alongside existing route-driven data loading.
src/lib/types/user.ts Adds UserInfo type definition for the new user info endpoint payload.
src/lib/types/index.ts Re-exports the new user types from the central types barrel.
src/lib/states.svelte.ts Adds indexerData.userInfo state for quota display/enforcement.
src/lib/components/indexer/UploadModal/UploadModal.svelte Enforces quota on file selection and disables file picking when quota is exhausted.
src/lib/components/indexer/Header.svelte Renders quota metrics in the header and disables upload button when quota is reached.
src/lib/api/indexer.ts Adds fetchUserInfo() API function calling /users/info.
Comments suppressed due to low confidence (1)

src/routes/indexer/+layout.svelte:83

  • handleRouting() is invoked on every $effect re-run (route changes), but it sets new setInterval timers without clearing any existing ones. Navigating between indexer sub-routes can therefore accumulate multiple refreshTasks / refreshUserInfo intervals and duplicate network traffic. Clear existing intervals before creating new ones (or move interval setup into an $effect with a cleanup function / onMount guard) so only one timer runs at a time.
    $effect(() => {
        console.log("Handling routing for:", page.route.id);
        handleRouting();
    });

    /**
     * This function handles data loading for different routes of the application
     */
    async function handleRouting() {
        if (ui.showLoginPage) return;

        // Load partitions and user info
        indexerData.partitions = await api.fetchPartitions();
        
        // Fetch user info (for quota display)
        try {
            indexerData.userInfo = await api.fetchUserInfo();
            refreshUserInfoInterval = setInterval(refreshUserInfo, 5000); // Refresh every 5 seconds
        } catch (error) {
            console.error("Failed to fetch user info:", error);
        }

        if (page.route.id === "/indexer") {
            // Reset navigation states
            indexerData.currentPartition = { partition: null, files: [] };
            indexerData.currentFile = null;

            // Load tasks
            indexerData.tasks = await api.fetchTasks();
            refreshTasksInterval = setInterval(refreshTasks, 5000); // Refresh every 5 seconds

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/types/user.ts
Comment on lines +6 to +16
import { ListFormat } from "typescript";

/**
* Represents user information (from the GET /user/info endpoint)
*/
export interface UserInfo {
id: string;
display_name: string;
is_admin: boolean;
memberships: ListFormat;
file_count: number;

Copilot AI Feb 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file imports ListFormat from the typescript package as a runtime import. That will bloat the client bundle (and may fail to bundle) since typescript is a devDependency and not intended for browser runtime use. Replace memberships: ListFormat with an appropriate app-level type (e.g. string[]/Membership[]/unknown) and remove the typescript import (or at minimum make it import type).

Copilot uses AI. Check for mistakes.
Comment thread src/lib/types/user.ts Outdated
Comment on lines +59 to +61
isQuotaInfinite
? Infinity
: Math.max(0, (indexerData.userInfo?.file_quota ?? 0) - (indexerData.userInfo?.total_files ?? 0))

Copilot AI Feb 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remainingQuota falls back to 0 when indexerData.userInfo is still null (or if the user-info fetch fails). That makes the file picker disabled and prevents uploads even though the header still allows opening the modal. Consider treating a missing userInfo as "quota unknown" (e.g. allow selection / show a loading state) or disable opening the modal until userInfo is available so the behavior is consistent.

Suggested change
isQuotaInfinite
? Infinity
: Math.max(0, (indexerData.userInfo?.file_quota ?? 0) - (indexerData.userInfo?.total_files ?? 0))
indexerData.userInfo == null
? Infinity
: isQuotaInfinite
? Infinity
: Math.max(0, (indexerData.userInfo.file_quota ?? 0) - (indexerData.userInfo.total_files ?? 0))

Copilot uses AI. Check for mistakes.
Comment thread src/lib/components/indexer/Header.svelte
Comment thread src/routes/indexer/+layout.svelte
Comment thread src/routes/indexer/+layout.svelte
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@Ahmath-Gadji
Ahmath-Gadji merged commit e1118fb into main Feb 12, 2026
@Ahmath-Gadji
Ahmath-Gadji deleted the feat/handling_user_file_quota branch February 12, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants