1. Overview
The File Repository Module is a comprehensive file management system within the Nimbly audit administration platform. This module provides centralized storage, organization, and [access control](../Settings/Access control/AccessControlOverview.md) for various types of files used across the audit workflow.
1.1 Purpose
- Centralized file storage and management
- Version control for audit documents
- [Access control](../Settings/Access control/AccessControlOverview.md) and [permissions](../Settings/Access control/AccessControlOverview.md) management
- File categorization and tagging
- Search and retrieval capabilities
1.2 Key Features
- File upload and download
- Folder structure organization
- File metadata management
- Search functionality
- [Access control](../Settings/Access control/AccessControlOverview.md)
- File preview capabilities
- Integration with other modules
2. Architecture
The Repository module follows a component-based architecture pattern integrated within the React-Redux ecosystem of the audit-admin application.
graph TD A[User] --> B[React Routes] B --> C[Repository Page] C --> D[Repository Container] D --> E[Redux Store] E --> F[Redux Saga] F --> G[API Services] G --> H[Backend API] D --> I[Layout Components] D --> J[Feature Components] D --> K[Modal Components] I --> L[Header] I --> M[SubHeader] I --> N[View Components] J --> O[Upload] J --> P[Share] J --> Q[Search] K --> R[File Operations] K --> S[Confirmations]
2.1 Module Structure
src/
├── pages/repository/
│ └── RepositoryPage.tsx # Main page wrapper
├── components/repository/
│ ├── Repository.tsx # Primary container
│ ├── RepositoryDashboard.tsx # Storage dashboard
│ ├── layout/ # Layout components
│ │ ├── RepositoryHeader.tsx # Top navigation bar
│ │ ├── RepositorySubHeader.tsx # Search and filters
│ │ ├── RepositoryTitle.tsx # Breadcrumb navigation
│ │ ├── RepositoryFloatingMenu.tsx # Bulk action menu
│ │ ├── RepositoryTableView.tsx # List view
│ │ └── RepositoryTileView.tsx # Grid view
│ ├── component/ # Feature components
│ │ ├── modal/ # Modal dialogs
│ │ │ ├── RepositoryModal.tsx # Modal orchestrator
│ │ │ ├── NewFolderModal.tsx # Create folder
│ │ │ ├── ShareModal.tsx # Share files
│ │ │ └── ... (other modals)
│ │ ├── RepositoryFileList.tsx # File listing
│ │ ├── RepositoryFolderList.tsx # Folder listing
│ │ └── FileThumbnail.tsx # File preview
│ └── utils/ # Utility functions
│ ├── useRepository.ts # CRUD operations
│ ├── useRepositoryUpload.ts # Upload management
│ ├── useRepositoryDownload.ts # Download handling
│ └── repositoryUtils.ts # Helper functions
├── reducers/repository/ # Redux state management
│ ├── repository.reducer.ts # Main reducer
│ ├── repository.action.ts # Action creators
│ ├── repository.actionTypes.ts # Action constants
│ └── type.d.ts # TypeScript types
├── services/repository/ # API services
│ └── repository.service.ts # API interactions
└── routes/ # Route definitions
└── admin-routes.js # Admin route config
2.2 Component Architecture Details
2.2.1 Layout Components
The layout components form the structural foundation of the repository interface:
RepositoryHeader
- Displays current storage usage with visual indicator
- Provides “Add New” dropdown for file/folder uploads
- Navigates to storage dashboard on click
- Integrates with upload hooks for file selection
- Responsive design for mobile/desktop views
RepositorySubHeader
- Search input with real-time suggestions
- View toggle between grid and list layouts
- Filter button opening filter sidebar
- Sort dropdown with multiple options
- Bulk selection controls when in select mode
RepositoryTitle
- Dynamic breadcrumb navigation
- Displays current folder hierarchy
- Click handlers for folder navigation
- Truncates long paths with ellipsis
- Shows folder count and size info
2.2.2 Modal System Architecture
The modal system uses a centralized pattern for consistency:
// Modal orchestrator pattern
const RepositoryModal = ({ uploadStates, handleRetry, handleCancel }) => {
const modals = useSelector(selectModalStates);
return (
<>
{modals.isNewFolderModalVisible && <NewFolderModal />}
{modals.isShareModalVisible && <ShareModal />}
{modals.isFilePreviewModalVisible && <FilePreviewModal />}
{/* ... other modals */}
</>
);
};Each modal follows consistent patterns:
- Redux state for visibility control
- Props for data passing
- Callback handlers for actions
- Loading states during operations
- Error handling with user feedback
2.2.3 Custom Hooks Deep Dive
useRepository Hook
The core hook managing CRUD operations:
export const useRepository = () => {
const dispatch = useDispatch();
const { files, folders, selectedFile } = useSelector(selectRepository);
const createNewFolder = async (name: string) => {
// Validation
// API call
// Optimistic update
// Error handling
};
const renameItem = async (id: string, newName: string) => {
// Similar pattern
};
const deleteItem = async (id: string) => {
// Soft delete to trash
};
const restoreItem = async (id: string) => {
// Restore from trash
};
const shareItem = async (id: string, users: string[]) => {
// Update permissions
};
return {
createNewFolder,
renameItem,
deleteItem,
restoreItem,
shareItem,
// ... other methods
};
};useRepositoryUpload Hook
Manages complex upload workflows:
export const useRepositoryUpload = () => {
const [uploadQueue, setUploadQueue] = useState<UploadItem[]>([]);
const [progress, setProgress] = useState<Record<string, number>>({});
const initFileUpload = async (files: FileList) => {
// Validate files
// Create upload items
// Get signed URLs
// Start uploads
// Track progress
// Handle completion
};
const initFolderUpload = async (folder: any) => {
// Similar but for folders
// Recursive file handling
};
const handleRetry = (itemId: string) => {
// Retry failed upload
};
const handleCancel = (itemId: string) => {
// Cancel ongoing upload
};
return {
uploadQueue,
progress,
initFileUpload,
initFolderUpload,
handleRetry,
handleCancel,
};
};3. Routes and Navigation
3.1 Route Configuration
The Repository module is accessible through the following routes defined in admin-routes.js:
| Route Path | Component | Description |
|---|---|---|
/repository | RepositoryPage | Main repository view with default tab |
/repository/:tab | RepositoryPage | Repository with specific tab selected |
/repository/folder/:id | RepositoryPage | View specific folder contents |
3.2 Access Control
The repository routes are protected by:
- Authentication: User must be logged in
- Feature Flag:
Features.FILE_REPOSITORYmust be enabled - Role: Admin access required
3.3 Navigation Tabs
The repository module supports multiple navigation tabs:
| Tab | Enum Value | Description |
|---|---|---|
| My Files | MY_FILES | User’s personal files and folders |
| Shared with Me | SHARED_WITH_ME | Files shared by other users |
| Recent | RECENT | Recently accessed files |
| Starred | STARRED | Files marked as favorite |
| Trash | TRASH | Deleted files (soft delete) |
| Search | SEARCH | Search results view |
| Dashboard | [DASHBOARD](../Dashboard/DashboardOverview.md) | Storage usage dashboard |
| Folder | FOLDER | Folder contents view |
4. Components
The Repository module consists of various specialized components organized into logical groups:
4.1 Core Components
4.1.1 Repository.tsx
src/components/repository/Repository.tsx
- Root container component that orchestrates the entire repository module
- Manages upload states and modal visibility
- Implements tab-based navigation between different views
- Integrates with Redux store for state management
4.1.2 RepositoryDashboard.tsx
src/components/repository/RepositoryDashboard.tsx
- Storage usage dashboard component
- Displays organization-wide storage consumption
- Shows breakdown between Repository and LMS storage
- Implements pagination for user storage list
4.2 Layout Components
| Component | Purpose |
|---|---|
| RepositoryHeader | Main header with storage indicator and upload actions |
| RepositorySubHeader | Search bar, view toggle, filters, and sorting controls |
| RepositoryTitle | Dynamic breadcrumb navigation display |
| RepositoryFloatingMenu | Contextual actions for selected items |
| RepositoryTableView | List view layout for files and folders |
| RepositoryTileView | Grid view layout with thumbnails |
4.3 Modal Components
The module uses a centralized modal system managed by RepositoryModal.tsx:
| Modal | Functionality |
|---|---|
| NewFolderModal | Create new folder with name validation |
| RenameItemModal | Rename files or folders |
| ShareModal | Share items with other users |
| FilePreviewModal | Preview images and documents |
| UploadModal | File upload with progress tracking |
| MoveToTrashModal | Soft delete confirmation |
| DeleteForeverModal | Permanent deletion confirmation |
| RestoreModal | Restore items from trash |
| EmptyTrashModal | Clear all trash items |
| StarredModal | Mark items as favorite |
4.4 Feature Components
4.4.1 File Management
- RepositoryFileList: Displays files grouped by sections with bulk selection
- FileThumbnail: Individual file representation with icon/preview
- FileUploadProgress: Real-time upload progress indicator
4.4.2 Folder Management
- RepositoryFolderList: Folder navigation with hierarchy support
- FolderThumbnail: Folder representation with nested item count
4.4.3 View Components
- RepositoryViewContainer: Switches between table and tile views
- RepositoryViewByDays: Groups items by date (Today, Yesterday, etc.)
- RepositorySearchSection: Displays search results with highlighting
5. API Endpoints
The Repository module interacts with the backend through a RESTful API. All endpoints are prefixed with the base URL configured in baseURL.ts.
5.1 Base Configuration
FILE_REPO_API_URL = apiURLAlt + '/file-repo';5.2 Repository Service APIs
| Method | Endpoint | Function | Description |
|---|---|---|---|
| GET | /file-repo | fetchRepository() | Fetch paginated repository items with filters |
| GET | /file-repo/folders | fetchRepositoryFolderList() | Get all folders for navigation |
| GET | /file-repo/search | searchRepository() | Search files and folders |
| POST | /file-repo | createRepositoryItem() | Create new file or folder |
| PUT | /file-repo | updateRepositoryItem() | Update item properties (rename, star, etc.) |
| GET | /file-repo/signedUploadURL | getRepositorySignedUrl() | Get signed URL for file upload |
| POST | /file-repo/download | downloadRepositoryItem() | Download single or multiple items |
| GET | /file-repo/user/all | fetchRepositoryStorageDetails() | Get user storage usage details |
| POST | /file-repo/user | createRepositoryUser() | Initialize user repository |
5.3 Organization Usage APIs
| Method | Endpoint | Function | Description |
|---|---|---|---|
| GET | /file-repo/tracker/:organizationID | fetchRepositoryOrganizationUsageRequest() | Get organization storage usage |
5.4 Query Parameters
5.4.1 Fetch Repository Items
list: Type of items to fetch (myFiles, sharedWithMe, recent, starred, trash)parentID: Folder ID for nested navigationpage: Page number for paginationlimit: Items per pagesortBy: Sort field (name, lastModifiedDate, size)sortType: Sort direction (asc, desc)qFileType: Filter by file typesqUser: Filter by shared usersqStartDate: Filter by date range startqEndDate: Filter by date range end
5.4.2 Search Parameters
search: Search query string- Additional filter parameters as above
5.5 Request/Response Types
The API uses TypeScript interfaces from @nimbly-technologies/nimbly-common:
interface CreateRepositoryItemRequest {
name: string;
type: 'file' | 'folder';
parentID?: string;
entityInfo: Record<string, any>;
metadata?: {
size?: number;
mimeType?: string;
lastModified?: Date;
};
}
interface GetRepositoryItemsResponse {
id: string;
name: string;
type: string;
kind: Kind; // FILE or FOLDER
size: number;
lastModifiedDate: Date;
createdDate: Date;
owner: {
id: string;
name: string;
email: string;
};
sharedWith: string[];
starred: boolean;
parentID: string | null;
path: string;
downloadURL?: string;
thumbnailURL?: string;
metadata: Record<string, any>;
}
interface PaginatedRepositoryItems {
docs: GetRepositoryItemsResponse[];
totalDocs: number;
page: number;
limit: number;
totalPages: number;
hasNextPage: boolean;
hasPrevPage: boolean;
}
interface UpdateRepositoryItemRequest {
operation: RepositoryItemOperations;
entityIDs: string[];
data?: {
name?: string;
starred?: boolean;
sharedWith?: string[];
parentID?: string;
};
}5.6 API Error Handling
The API implements comprehensive error handling:
interface APIError {
status: number;
message: string;
code: string;
details?: any;
}
// Common error codes
enum RepositoryErrorCodes {
STORAGE_LIMIT_EXCEEDED = 'STORAGE_LIMIT_EXCEEDED',
FILE_TOO_LARGE = 'FILE_TOO_LARGE',
INVALID_FILE_TYPE = 'INVALID_FILE_TYPE',
PERMISSION_DENIED = 'PERMISSION_DENIED',
ITEM_NOT_FOUND = 'ITEM_NOT_FOUND',
DUPLICATE_NAME = 'DUPLICATE_NAME',
}5.7 API Rate Limiting
The repository API implements rate limiting:
- Upload endpoints: 100 requests per minute
- Read endpoints: 1000 requests per minute
- Search endpoints: 200 requests per minute
- Batch operations: 50 requests per minute
Headers returned:
X-RateLimit-Limit: Maximum requests allowedX-RateLimit-Remaining: Requests remainingX-RateLimit-Reset: Reset timestamp
6. Data Flow
The Repository module follows a unidirectional data flow pattern using Redux for state management:
sequenceDiagram participant User participant Component participant Hook participant Redux participant API participant Backend User->>Component: Interaction (click, type) Component->>Hook: Call custom hook Hook->>Redux: Dispatch action Redux->>Redux: Update state Hook->>API: API call (if async) API->>Backend: HTTP request Backend-->>API: Response API-->>Hook: Process data Hook->>Redux: Dispatch success/error Redux-->>Component: State update Component-->>User: UI update
6.1 State Management Architecture
The Repository module implements a sophisticated state management system using Redux:
6.1.1 Redux Architecture
graph TB A[Components] --> B[Actions] B --> C[Reducers] C --> D[Store] D --> E[Selectors] E --> A B --> F[Middleware] F --> G[API Calls] G --> H[Backend] H --> I[Response] I --> B
6.2 State Slices
6.2.1 Main Repository State
Managed by repository.reducer.ts:
const initialState: RepositoryState = {
// UI State
isLoading: false,
isLoadingNextPage: false,
isLoadingSearch: false,
error: '',
// View Settings
activeTab: RepositoryTabEnum.MY_FILES,
viewType: LmsViewType.TILE,
gridSize: 6,
// Data
files: [],
folders: [],
fileSections: {}, // Files grouped by date
// Selection
selectedFile: null,
selectedFileIds: new Set(),
selectedFolderIds: new Set(),
totalSelectedItems: 0,
totalSelectedFilesSize: 0,
// Navigation
folderHierarchy: [],
// Search & Filters
searchQuery: '',
filters: {
qFileType: [],
qUser: [],
qLocation: '',
qStartDate: null,
qEndDate: null,
},
// Pagination
page: 1,
limit: 24,
totalPages: 0,
totalDocs: 0,
// Modal States
isFilePreviewModalVisible: false,
isNewFolderModalVisible: false,
// ... other modals
};6.2.2 Repository Folder List State
Manages available folders for navigation:
interface RepositoryFolderListState {
isLoading: boolean;
error: string;
folders: RepositoryFolderList[];
}6.2.3 User Storage Usage State
Tracks per-user storage consumption:
interface RepositoryUserUsageState {
isLoading: boolean;
docs: UserStorageDoc[];
page: number;
limit: number;
totalDocs: number;
sortBy: RepositoryUserUsageSortBy;
sortType: 'asc' | 'desc';
}6.2.4 Organization Usage State
Monitors organization-wide storage:
interface RepositoryOrganizationUsageState {
isLoading: boolean;
totalUsedStorageGB: number;
totalOrganizationUsedStorageGB: number;
allocationPerEntity: {
REPOSITORY: number;
LMS: number;
};
}6.3 Action Patterns
Actions follow a consistent naming convention:
// Synchronous actions
export const setActiveRepositoryTab = createAction('repository/SET_ACTIVE_TAB')<RepositoryTabEnum>();
export const setRepositoryFiles = createAction('repository/SET_FILES')<GetRepositoryItemsResponse[]>();
// Async actions (with request/success/failure)
export const fetchRepositoryRequest = createAction('repository/FETCH_REQUEST')();
export const fetchRepositorySuccess = createAction('repository/FETCH_SUCCESS')<PaginatedRepositoryItems>();
export const fetchRepositoryFailure = createAction('repository/FETCH_FAILURE')<string>();6.4 Selector Patterns
Selectors provide derived state and memoization:
// Basic selectors
const selectRepository = (state: RootState) => state.repository;
const selectActiveTab = (state: RootState) => state.repository.activeTab;
// Computed selectors
const selectVisibleItems = createSelector([selectFiles, selectFolders, selectActiveTab], (files, folders, tab) => {
// Logic to compute visible items based on tab
});
// Parameterized selectors
const selectFileById = (fileId: string) => createSelector([selectFiles], (files) => files.find((f) => f.id === fileId));6.5 Middleware Integration
The module uses custom middleware for:
- API Call Management
- Automatic token attachment
- Error handling
- Loading state management
- State Persistence
- Selected view preferences
- Filter settings
- Sort preferences
- Analytics Tracking
- File operations
- Usage patterns
- Error events
10.9 Performance Optimizations
- Normalized State
- Files stored flat, not nested
- Relationships via IDs
- Efficient updates
- Memoized Selectors
- Reselect library usage
- Computed values cached
- Re-render optimization
- Lazy Loading
- Pagination for large datasets
- Virtual scrolling for lists
- On-demand data fetching
- Optimistic Updates
- Immediate UI feedback
- Background synchronization
- Rollback on failure
7. State Management
The Repository module utilizes Redux for centralized state management with clear separation of concerns:
7.1 Action Types Organization
Actions are organized into logical groups:
// UI Actions
'repository/SET_LOADING';
'repository/SET_ERROR';
'repository/TOGGLE_MODAL';
'repository/SET_VIEW_TYPE';
// Data Actions
'repository/SET_FILES';
'repository/SET_FOLDERS';
'repository/SET_FILE_SECTIONS';
'repository/UPDATE_ITEM';
// Navigation Actions
'repository/SET_ACTIVE_TAB';
'repository/SET_FOLDER_HIERARCHY';
'repository/SET_PAGE';
// Selection Actions
'repository/SELECT_FILE';
'repository/SELECT_MULTIPLE';
'repository/CLEAR_SELECTION';7.2 State Update Patterns
7.2.1 Direct State Updates
Used for synchronous operations like UI state changes:
case 'repository/SET_ACTIVE_TAB':
return {
...state,
activeTab: action.payload,
page: 1, // Reset pagination
selectedFileIds: new Set(), // Clear selection
};7.2.2 Immutable Updates
For complex data structures:
case 'repository/UPDATE_FILE_SECTION':
return {
...state,
fileSections: {
...state.fileSections,
[action.payload.date]: action.payload.files
}
};7.3 Side Effects Management
The module handles side effects through custom hooks that abstract async operations:
- Data Fetching
- Managed by
useRepositoryDatahook - Handles loading states automatically
- Implements caching and invalidation
- File Operations
useRepositoryhook for CRUD operations- Optimistic updates for better UX
- Error handling with rollback
- Upload Management
useRepositoryUploadfor file uploads- Progress tracking
- Batch upload support
7.4 State Persistence
Certain state properties are persisted across sessions:
const persistedState = {
viewType: LmsViewType.TILE,
sortBy: RepositorySortByOptionsEnum.LAST_MODIFIED,
sortType: 'desc',
gridSize: 6,
};7.5 Performance Considerations
- Normalized Data Structure
- Files and folders stored separately
- References by ID for relationships
- Efficient lookups and updates
- Index-based access patterns
- Selective Re-renders
- Component connections minimized
- Use of React.memo for expensive components
- Granular subscriptions to state slices
- Memoized selectors with reselect
- Batch Updates
- Multiple state changes batched
- Reduces re-render cycles
- Improves performance for bulk operations
- Debounced API calls
7.6 Redux Middleware Configuration
The repository module uses custom middleware:
// API Middleware
const apiMiddleware = (store) => (next) => (action) => {
if (action.meta?.api) {
// Attach auth token
// Handle loading states
// Process errors
// Log analytics
}
return next(action);
};
// Analytics Middleware
const analyticsMiddleware = (store) => (next) => (action) => {
if (action.meta?.track) {
analytics.track(action.type, {
...action.payload,
timestamp: Date.now(),
});
}
return next(action);
};
// Persistence Middleware
const persistenceMiddleware = (store) => (next) => (action) => {
const result = next(action);
if (PERSISTED_ACTIONS.includes(action.type)) {
localStorage.setItem(
'repository_prefs',
JSON.stringify({
viewType: store.getState().repository.viewType,
sortBy: store.getState().repository.sortBy,
sortType: store.getState().repository.sortType,
}),
);
}
return result;
};7.7 State Synchronization
The module implements state synchronization across tabs:
// Broadcast channel for cross-tab communication
const channel = new BroadcastChannel('repository_sync');
// Listen for changes
channel.addEventListener('message', (event) => {
if (event.data.type === 'STATE_UPDATE') {
store.dispatch(syncState(event.data.payload));
}
});
// Broadcast changes
const broadcastMiddleware = (store) => (next) => (action) => {
const result = next(action);
if (BROADCAST_ACTIONS.includes(action.type)) {
channel.postMessage({
type: 'STATE_UPDATE',
payload: store.getState().repository,
});
}
return result;
};8. Dependencies
The Repository module leverages various external libraries and internal packages to provide its functionality:
8.1 Core Dependencies
| Package | Version | Purpose |
|---|---|---|
| react | 16.13.1 | Core React library |
| react-redux | 7.2.0 | Redux React bindings |
| redux | 4.0.5 | State management |
| typesafe-actions | 5.1.0 | Type-safe Redux actions |
| @loadable/component | 5.14.1 | Lazy loading for route splitting |
8.2 UI & Styling
| Package | Purpose |
|---|---|
| styled-components | CSS-in-JS styling solution |
| react-icons | Icon library (MdOutlineCloud, FiHardDrive) |
| @radix-ui/** | UI primitive components |
| react-toastify | Toast notifications |
8.3 Utility Libraries
| Package | Purpose |
|---|---|
| lodash | Utility functions (cloneDeep, debounce) |
| dayjs | Date manipulation and formatting |
| uuid | Unique ID generation for uploads |
| query-string | URL query parameter handling |
| copy-to-clipboard | Clipboard operations |
8.4 Internal Packages
8.4.1 @nimbly-technologies/nimbly-common (v1.95.3)
Provides shared types and utilities:
Types & Interfaces:
GetRepositoryItemsResponsePaginatedRepositoryItemsCreateRepositoryItemRequestUpdateRepositoryItemRequestAttachmentGalleryResponseFilterAttachmentsResult
Enumerators:
RepositoryListEnum- Tab navigation typesRepositorySortByOptionsEnum- Sorting optionsRepositoryItemOperations- CRUD operationsKind- File/Folder types
Utilities:
- MIME type mappings
- File type detection
- Common validation functions
8.5 Integration Points
The module integrates with:
- Firebase Auth - Token-based API authentication
- Cloud Storage - File upload/download via signed URLs
- Redux DevTools - Development debugging
- React Router - Navigation and routing
- i18next - Internationalization support
9. User Flows
The Repository module supports various user workflows for file management:
9.1 File Upload Flow
graph LR A[User clicks Upload] --> B{Select Type} B -->|Files| C[File Picker] B -->|Folder| D[Folder Picker] C --> E[Validate Files] D --> F[Validate Folder] E --> G[Get Signed URLs] F --> G G --> H[Upload to Cloud] H --> I[Create DB Entry] I --> J[Update UI] J --> K[Show Success]
Steps:
- User clicks “Add New” button in header
- Selects between file or folder upload
- System validates selection (size limits, file types)
- Requests signed URLs from backend
- Uploads files directly to cloud storage
- Creates repository entries in database
- Updates local state optimistically
- Shows upload progress and completion
9.2 File Search Flow
stateDiagram-v2 [*] --> Idle Idle --> Typing: User types Typing --> Debouncing: Wait 300ms Debouncing --> Searching: Trigger search Searching --> DisplayResults: Results found Searching --> NoResults: No matches DisplayResults --> [*] NoResults --> [*]
Features:
- Real-time search with debouncing
- Search across file names, folders, and metadata
- Highlights matching terms
- Groups results by category
9.3 File Sharing Flow
sequenceDiagram participant U as User participant M as ShareModal participant A as API participant R as Recipients U->>M: Select files & click Share M->>U: Show user selector U->>M: Select recipients M->>A: Update permissions A->>R: Send notifications A-->>M: Confirm shared M-->>U: Show success
Process:
- User selects files/folders to share
- Opens share modal
- Searches and selects recipients
- Sets permission levels
- System updates access control
- Recipients receive notification
- Files appear in “Shared with Me”
9.4 Folder Navigation Flow
graph TD A[Root Folder] --> B{User Action} B -->|Click Folder| C[Enter Folder] B -->|Breadcrumb| D[Navigate Up] C --> E[Load Contents] D --> F[Load Parent] E --> G[Update URL] F --> G G --> H[Update View]
Navigation Features:
- Click folders to navigate down
- Use breadcrumbs to navigate up
- URL updates reflect current location
- Back/forward browser buttons work
- Folder hierarchy maintained in state
9.5 Bulk Operations Flow
graph LR A[Select Mode] --> B[Choose Items] B --> C{Action} C -->|Download| D[Zip & Download] C -->|Delete| E[Move to Trash] C -->|Share| F[Bulk Share] C -->|Move| G[Select Destination] D --> H[Complete] E --> H F --> H G --> I[Move Items] I --> H
Bulk Actions:
- Select multiple items via checkboxes
- Floating action menu appears
- Supports download, delete, share, move
- Progress tracking for large operations
- Undo capability for some actions
9.6 File Preview Flow
stateDiagram-v2 [*] --> Thumbnail: File displayed Thumbnail --> Preview: User clicks Preview --> Loading: Fetch file Loading --> Display: Show content Display --> Actions: User interacts Actions --> Download: Download file Actions --> Share: Share file Actions --> Close: Close preview Close --> [*]
Preview Capabilities:
- Images: Full resolution view
- Documents: Embedded viewer
- Videos: Inline player
- Other files: Download prompt
- Navigation between files in preview
9.7 Storage Management Flow
graph TD A[Dashboard Tab] --> B[Load Usage Data] B --> C[Organization Stats] B --> D[User List] C --> E[Show Breakdown] D --> F[Paginated Table] E --> G[Repository vs LMS] F --> H[Sort by Usage]
Dashboard Features:
- Organization storage overview
- Per-user usage breakdown
- Storage type distribution
- Sort users by consumption
- Export usage reports
10. Technical Implementation
This section covers key technical implementation details and patterns used in the Repository module:
10.1 File Upload Implementation
The file upload process uses signed URLs for secure direct uploads to cloud storage:
// 1. Get signed URL
const signedUrl = await getRepositorySignedUrl(queryParams);
// 2. Upload file directly
await fetch(signedUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type,
},
});
// 3. Create repository entry
await createRepositoryItem({
entityInfo: { [fileName]: fileMetadata },
parentID: currentFolderId,
});10.2 Folder Structure Management
Folders are managed hierarchically with efficient navigation:
interface FolderHierarchy {
id: string;
name: string;
path: string;
parentID: string | null;
}
// Navigation maintains breadcrumb trail
const navigateToFolder = (folderId: string) => {
const hierarchy = buildHierarchy(folderId);
dispatch(setFolderHierarchy(hierarchy));
history.push(`/repository/folder/${folderId}`);
};10.3 Search Implementation
Search functionality uses debouncing and intelligent result grouping:
const useSearch = () => {
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 300);
useEffect(() => {
if (debouncedQuery) {
searchRepository({
search: debouncedQuery,
...filters,
});
}
}, [debouncedQuery]);
};10.4 File Type Detection
The module uses MIME types and extensions for file type identification:
const getFileType = (file: File): RepositoryFileType => {
const mimeType = file.type;
const extension = file.name.split('.').pop()?.toLowerCase();
if (mimeType.startsWith('image/')) return RepositoryFileType.IMAGE;
if (mimeType.startsWith('video/')) return RepositoryFileType.VIDEO;
if (DOCUMENT_EXTENSIONS.includes(extension)) return RepositoryFileType.DOCUMENT;
return RepositoryFileType.OTHER;
};10.5 Permission Management
File permissions are managed at the item level:
interface ItemPermissions {
canView: boolean;
canEdit: boolean;
canDelete: boolean;
canShare: boolean;
sharedWith: string[]; // User IDs
}10.6 Error Handling Patterns
Comprehensive error handling with user-friendly messages:
try {
await updateRepositoryItem(payload);
toast.success('File updated successfully');
} catch (error) {
console.error('Update failed:', error);
toast.error(getErrorMessage(error));
// Rollback optimistic update
dispatch(revertUpdate(itemId));
}10.7 Caching Strategy
The module implements intelligent caching:
- API Response Caching
- Cache folder lists for navigation
- Cache file metadata for quick access
- Invalidate on modifications
- Preview Caching
- Cache generated thumbnails
- Lazy load preview images
- Memory management for large files
10.8 Security Considerations
- Authentication
- Firebase token validation
- Automatic token refresh
- Secure API endpoints
- Authorization
- Feature flag validation
- Role-based access control
- Per-item permissions
- Data Validation
- File type restrictions
- Size limitations
- Name sanitization
10.9 Performance Optimizations
-
Lazy Loading
const RepositoryPage = loadable(() => import('./pages/repository/RepositoryPage')); -
Virtual Scrolling
- For large file lists
- Renders only visible items
- Smooth scroll performance
- Batch Operations
const batchDelete = async (itemIds: string[]) => { const chunks = chunk(itemIds, 50); // Process in chunks await Promise.all(chunks.map(deleteChunk)); };
10.10 Testing Strategies
- Unit Tests
- Redux reducers
- Utility functions
- API services
- Integration Tests
- Component interactions
- API communication
- State management
- E2E Tests
- File upload flows
- Search functionality
- Permission validation
10.11 Monitoring and Analytics
The module tracks key metrics:
// Track file operations
analytics.track('file_uploaded', {
fileType: file.type,
fileSize: file.size,
uploadDuration: duration,
});
// Monitor performance
performance.mark('repository_load_start');
// ... load data
performance.mark('repository_load_end');
performance.measure('repository_load', 'repository_load_start', 'repository_load_end');Planned improvements for the module:
- Advanced Features
- Version control for files
- Collaborative editing
- Advanced search filters
- File tagging system
- Performance
- Service worker caching
- Progressive web app features
- Optimized bundle splitting
- Integration
- Third-party storage providers
- External collaboration tools
- Advanced analytics dashboard
11. Integration Patterns
11.1 Integration with Other Modules
The Repository module integrates seamlessly with other parts of the application:
11.1.1 Issues Module Integration
Files can be attached to issues for documentation:
// Issue attachment flow
const attachFileToIssue = async (issueId: string, fileId: string) => {
// Get file from repository
const file = await getRepositoryItem(fileId);
// Create attachment reference
await createIssueAttachment({
issueId,
fileId,
fileName: file.name,
fileSize: file.size,
uploadedBy: currentUser.id,
});
};11.1.2 Reports Module Integration
Reports can reference repository files:
// Report file inclusion
const includeFileInReport = (reportId: string, fileIds: string[]) => {
return updateReport(reportId, {
attachments: fileIds,
lastModified: new Date(),
});
};11.1.3 Gallery Module Integration
Shared image handling between modules:
// Shared image viewer
const openImagePreview = (imageId: string, source: 'repository' | 'gallery') => {
dispatch(
openPreviewModal({
imageId,
source,
navigation: source === 'repository' ? getRepositoryNavigation() : getGalleryNavigation(),
}),
);
};11.2 Event-Driven Architecture
The module uses events for loose coupling:
// Event emitter for repository events
class RepositoryEventEmitter extends EventEmitter {
emitFileUploaded(file: GetRepositoryItemsResponse) {
this.emit('file:uploaded', file);
}
emitFileDeleted(fileId: string) {
this.emit('file:deleted', fileId);
}
emitStorageUpdated(usage: StorageUsage) {
this.emit('storage:updated', usage);
}
}
// Other modules can listen
repositoryEvents.on('file:uploaded', (file) => {
// Update related data
// Send notifications
// Trigger workflows
});12. Troubleshooting Guide
12.1 Common Issues and Solutions
- Upload Failures
- Check network connectivity
- Verify storage quota
- Validate file size limits
- Check file type restrictions
- Performance Issues
- Enable React DevTools Profiler
- Check for unnecessary re-renders
- Verify API response times
- Monitor bundle size
- State Inconsistencies
- Check Redux DevTools
- Verify action dispatching
- Look for race conditions
- Check middleware order
12.2 Debug Utilities
// Debug logger for development
const debugLog = (action: string, data: any) => {
if (process.env.NODE_ENV === 'development') {
console.group(`[Repository] ${action}`);
console.log('Data:', data);
console.log('State:', store.getState().repository);
console.groupEnd();
}
};
// Performance monitor
const measurePerformance = (operation: string, fn: () => void) => {
const start = performance.now();
fn();
const end = performance.now();
console.log(`${operation} took ${end - start}ms`);
};13. Summary
The File Repository Module is a comprehensive file management solution within the Nimbly audit administration platform. It provides:
13.1 Key Capabilities
- Centralized Storage: Single source of truth for all audit-related files
- Hierarchical Organization: Folder-based structure with breadcrumb navigation
- Advanced Search: Full-text search across file names and metadata
- [Access Control](../Settings/Access control/AccessControlOverview.md): Feature flag protection and user-based [permissions](../Settings/Access control/AccessControlOverview.md)
- Storage Management: Organization and user-level quota tracking
- Multiple Views: Tile and table layouts with customizable sorting
- [Bulk Operationss](../Bulk Operation/BulkOperationOverview.md): Efficient handling of multiple file operations
13.2 Technical Highlights
- React-Redux Architecture: Clean separation of concerns with predictable state management
- TypeScript: Full type safety across components and APIs
- Performance Optimized: Lazy loading, memoization, and virtual scrolling
- Cloud Integration: Direct uploads to cloud storage with signed URLs
- Responsive Design: Mobile-friendly interface with adaptive layouts
13.3 Module Statistics
- Components: 40+ specialized React components
- Custom Hooks: 15+ reusable hooks for business logic
- API Endpoints: 10+ RESTful endpoints
- State Slices: 4 Redux reducers for different aspects
- File Types: Support for images, videos, documents, and more
The module exemplifies modern web development practices with a focus on user experience, performance, and maintainability. It serves as a critical component in the Nimbly ecosystem, enabling efficient file management for audit workflows.
For questions or contributions, please refer to the GitHub repository.