Skip to content

Conversation

@rishabhcli
Copy link
Owner

Summary

  • fetch and display storage quota on dashboard load with brutalist-styled progress visuals
  • surface remaining storage in the toolbar and user menu with updated quota-aware profile data
  • block uploads that exceed remaining quota with clear error messaging

Testing

  • not run (not requested)

Codex Task

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds storage quota management features with a brutalist-styled UI. The implementation fetches and displays storage quota information across multiple components and prevents file uploads that would exceed the user's remaining storage.

Key changes:

  • Added storage quota fetching and display on dashboard with real-time updates after operations
  • Integrated remaining storage indicators in toolbar badge and user menu dropdown
  • Implemented pre-upload validation to block files exceeding available storage with clear error messages

Reviewed Changes

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

Show a summary per file
File Description
src/ui/components/auth/UserMenu.ts Added StorageQuota integration with formatBytes helper, updateQuota method, and quota display in dropdown with remaining storage pill
src/ui/components/Toolbar.ts Added storage badge component with updateStorageBadge method and formatRemaining helper for displaying remaining quota
src/ui/components/Dashboard.ts Added quota fetching on load, quota card rendering with skeleton states, error handling, and quota refresh after file deletion
src/ui/App.ts Added fetchAndApplyQuota method to coordinate quota fetching and updates across components, integrated quota into authentication flow
src/styles.css Added brutalist-styled CSS for storage badge, quota cards, progress bars, and skeleton loading states
src/lib/cloud/sync.ts Added quota validation before file upload to prevent exceeding storage limits with detailed error messages

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

const { used, quota } = this.storageQuota;
const percentUsed = Math.min(
100,
Math.round(this.storageQuota.percentUsed ?? (used / quota) * 100)
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Potential division by zero when quota is 0. This would result in Infinity or NaN for the calculation, which could cause unexpected display issues.

Consider adding a check:

Math.round(this.storageQuota.percentUsed ?? (quota > 0 ? (used / quota) * 100 : 0))
Suggested change
Math.round(this.storageQuota.percentUsed ?? (used / quota) * 100)
Math.round(this.storageQuota.percentUsed ?? (quota > 0 ? (used / quota) * 100 : 0))

Copilot uses AI. Check for mistakes.
Comment on lines +269 to +271
badge.textContent = `${remainingText} free`;
badge.setAttribute('aria-label', `${remainingText} remaining (${percent}% free)`);
badge.style.display = 'inline-flex';
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

[nitpick] The storage badge lacks semantic information for screen readers when displayed. While there's an aria-label attribute, the badge itself doesn't have a role that indicates its purpose. Consider adding a role="status" attribute to make it clear this is a live status indicator:

badge.setAttribute('role', 'status');
badge.setAttribute('aria-label', `${remainingText} remaining (${percent}% free)`);

Copilot uses AI. Check for mistakes.
private formatRemaining(bytes: number): string {
const gb = bytes / (1024 * 1024 * 1024);
if (gb >= 0.1) {
return `${gb.toFixed(1)} GB`;
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

The formatRemaining method can return negative values in the display string when mb is negative (e.g., if bytes is negative). The Math.max(mb, 0) only prevents negative MB values, but if bytes are negative, gb.toFixed(1) on line 277 could still return a negative value like "-0.5 GB".

Consider adding Math.max(0, gb) to ensure GB values are also non-negative:

if (gb >= 0.1) {
  return `${Math.max(0, gb).toFixed(1)} GB`;
}
Suggested change
return `${gb.toFixed(1)} GB`;
return `${Math.max(0, gb).toFixed(1)} GB`;

Copilot uses AI. Check for mistakes.
}

const remainingText = this.formatRemaining(remainingBytes);
const percent = Math.max(0, Math.round((remainingBytes / quotaBytes) * 100));
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Potential division by zero when quotaBytes is 0. This would result in Infinity or NaN for percent, which could cause confusing aria-label text like "0% free" when storage is actually full or "Infinity% free" when quota is zero.

Consider adding a check:

const percent = quotaBytes > 0 ? Math.max(0, Math.round((remainingBytes / quotaBytes) * 100)) : 0;
Suggested change
const percent = Math.max(0, Math.round((remainingBytes / quotaBytes) * 100));
const percent = quotaBytes > 0 ? Math.max(0, Math.round((remainingBytes / quotaBytes) * 100)) : 0;

Copilot uses AI. Check for mistakes.
Signed in
<div style="display: flex; align-items: center; gap: 8px;">
<span style="font-size: 12px; color: #666;">Signed in</span>
<span class="quota-pill" style="font-size: 12px; padding: 4px 8px; border: 2px solid #111; border-radius: 999px; background: #fef3c7; color: #111; font-weight: 700; letter-spacing: -0.01em; box-shadow: 4px 4px 0 #111;">
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

[nitpick] Inline styles for the quota pill are duplicated between the UserMenu dropdown (lines 134-136) and potentially the CSS .quota-pill class. Consider using the CSS class consistently instead of mixing inline styles with the class attribute.

The current implementation applies both inline styles and a class name:

<span class="quota-pill" style="...">

This can lead to maintainability issues and style conflicts. Either use the class with all styles in CSS, or remove the class if using inline styles.

Suggested change
<span class="quota-pill" style="font-size: 12px; padding: 4px 8px; border: 2px solid #111; border-radius: 999px; background: #fef3c7; color: #111; font-weight: 700; letter-spacing: -0.01em; box-shadow: 4px 4px 0 #111;">
<span class="quota-pill">

Copilot uses AI. Check for mistakes.
Comment on lines +224 to +233
private formatBytes(bytes: number, short: boolean = false): string {
const gb = bytes / (1024 * 1024 * 1024);
const mb = bytes / (1024 * 1024);

if (gb >= 0.1) {
return short ? `${gb.toFixed(1)} GB` : `${gb.toFixed(2)}`;
}

return short ? `${mb.toFixed(0)} MB` : `${mb.toFixed(1)}`;
}
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

This formatBytes helper is duplicated across multiple components with slightly different implementations (UserMenu, Dashboard). Consider extracting this into a shared utility module to maintain consistency and avoid duplication.

For example, create a src/lib/utils/format.ts file with:

export function formatBytes(bytes: number, options?: { short?: boolean }): string {
  // Unified implementation
}

Copilot uses AI. Check for mistakes.
Comment on lines +116 to +118
percentUsed: Math.round(
(this.user.storage_used_bytes / this.user.storage_quota_bytes) * 100
),
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

Potential division by zero when this.user.storage_quota_bytes is 0. This would result in Infinity or NaN for percentUsed, which could cause unexpected display issues.

Consider adding a check:

percentUsed: this.user.storage_quota_bytes > 0
  ? Math.round((this.user.storage_used_bytes / this.user.storage_quota_bytes) * 100)
  : 0,
Suggested change
percentUsed: Math.round(
(this.user.storage_used_bytes / this.user.storage_quota_bytes) * 100
),
percentUsed: this.user.storage_quota_bytes > 0
? Math.round((this.user.storage_used_bytes / this.user.storage_quota_bytes) * 100)
: 0,

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants