* Added Quantity Field
✅ Completed Changes
1. HTML Forms
Added quantity input fields to both asset and sub-asset forms
Fields default to value="1" with min="1" validation
Positioned after price fields for logical flow
2. Modal Manager (Frontend)
Updated form data collection to capture quantity values
Added quantity to form population for editing existing assets
Ensures quantity defaults to 1 if not provided
3. Asset Details Display
Added quantity field to asset info display in assetRenderer.js
Shows "Quantity: X" in the asset details section
Includes fallback to 1 for backwards compatibility
4. Server-side Backwards Compatibility
Asset Creation: Ensures quantity defaults to 1 if not provided
Asset Updates: Preserves existing quantity or defaults to 1
Sub-asset Creation: Ensures quantity defaults to 1 if not provided
Sub-asset Updates: Preserves existing quantity or defaults to 1
Data Loading: All assets and sub-assets get quantity field when loaded from API
5. Import Functionality
Added quantity column mapping option in import modal
Updated server-side import logic to handle quantity with default of 1
Updated template CSV download to include quantity example
Added auto-mapping for "quantity" and "qty" column headers
🔒 Backwards Compatibility
The implementation ensures that:
Existing assets without quantity will automatically show quantity: 1
All API endpoints handle missing quantity gracefully
Import functionality works with or without quantity columns
No data migration is required - compatibility is handled at runtime
* Add "Total Value" to asset details
✅ Total Value Field Features
Conditional Display
Only shows when quantity > 1
Only shows when there's a valid price (either price or purchasePrice)
Calculation
Calculates: price × quantity = total value
Uses the same currency formatting as other price fields
Handles both asset.price and asset.purchasePrice (for backwards compatibility)
* Updated Dashboard Value Calculation logic
Updated Calculation Logic to account for quantity
Assets:
price × quantity for each asset
Defaults to quantity = 1 for backwards compatibility
Sub-Assets:
purchasePrice × quantity for each sub-asset
Defaults to quantity = 1 for backwards compatibility
- Add CURRENCY_CODE and CURRENCY_LOCALE environment variables in server.js
- Inject currency configuration into frontend via dynamic config.js endpoint
- Update formatCurrency() function to use global app config for dynamic currency formatting
- Support any ISO 4217 currency code with proper locale-specific formatting
- Add comprehensive currency configuration documentation (CURRENCY_CONFIG.md)
- Update README.md with currency environment variables and collapsible configuration guide
- Include Docker/Docker Compose configuration examples for currency settings
- Maintain backward compatibility with USD/en-US defaults
Supported currencies include USD, EUR, GBP, CAD, AUD, JPY, and any valid ISO 4217 code.
Currency formatting respects locale-specific conventions (e.g., €1.234,56 for de-DE).
add docs folder
Stringify currency object and update docs
Adding responsive card values to wrap large values
* Added Multi-file uploads
Allows users to upload multiple files for each file type.
Reworked cascading deletion logic to ensure Deleting an asset deletes all attachments as well as sub and sub sub assets and applicable attachments.
* Added file names as file-label
change file label to be file name, limited to 15 characters then cuts off.
* Fix removed features
Fixed Issues:
1. Asset Update Endpoint (PUT /api/assets/:id)
✅ Added name validation: Now validates that updatedAssetData.name exists before proceeding
✅ Added edit notification logic: Checks notificationSettings.notifyEdit and sends notifications when assets are edited
✅ Added debug logging: Logs asset update events when DEBUG mode is enabled
2. Sub-asset Update Endpoint (PUT /api/subassets/:id)
✅ Added name validation: Now validates that updatedSubAssetData.name exists before proceeding
✅ Added edit notification logic: Checks notificationSettings.notifyEdit and sends notifications when sub-assets are edited
✅ Added debug logging: Logs sub-asset update events when DEBUG mode is enabled
3. Asset Delete Endpoint (DELETE /api/asset/:id)
✅ Added delete notification logic: Checks notificationSettings.notifyDelete and sends notifications when assets are deleted
✅ Added debug logging: Logs notification attempts when DEBUG mode is enabled
4. Sub-asset Delete Endpoint (DELETE /api/subasset/:id)
✅ Added delete notification logic: Checks notificationSettings.notifyDelete and sends notifications when sub-assets are deleted
✅ Added debug logging: Logs notification attempts when DEBUG mode is enabled
Key Features Restored:
Data Integrity: Name field validation prevents saving assets/sub-assets without names
Notification System: Complete notification support for edit and delete operations
Consistent API: All endpoints now follow the same pattern as the create endpoints
Error Handling: Proper error handling for notification failures (won't break the main operation)
Debug Support: Comprehensive logging for troubleshooting when DEBUG=TRUE
* Reworked file label and preview grid formatting
* Fix file duplication on drag and drop
There are two separate drag and drop implementations that both trigger when files are dropped:
First implementation: In setupFileInputPreview() (lines ~105-140) - this sets up drag and drop for each individual upload box
Second implementation: In setupDragAndDrop() (lines ~300-389) - this also sets up drag and drop for all upload boxes
Both functions are being called, and they're both adding event listeners to the same elements, causing files to be processed twice. The fix is to remove the duplicate drag and drop code from setupFileInputPreview() since setupDragAndDrop() handles it more comprehensively.
* Fix file duplication on second drag & drop
The Solution:
Added file tracking: Each setupFileInputPreview() function now maintains a processedFiles Set that tracks which files have already been processed using a unique identifier.
Unique file identification: Each file is identified by ${file.name}-${file.size}-${file.lastModified}, which creates a unique fingerprint for each file.
Skip already processed files: Before creating a preview, the handler checks if the file has already been processed and skips it if so.
Clean up on deletion: When a file is deleted, its ID is removed from the processedFiles Set so it can be re-added later if needed.
* feat: completely rework file upload system to prevent duplicates and fix state issues
- Add comprehensive file state tracking with allFiles, newFilesSet, and filePreviewMap
- Implement additive file selection behavior for both drag-and-drop and file input
- Add deduplication logic to prevent duplicate files across multiple selections
- Create distinction between new files (for upload) vs existing files (preview only)
- Add reset() functionality to prevent state contamination between modal operations
- Fix existing file preview display by using server paths instead of mock File objects
- Fix individual file deletion by integrating with filesToDelete system using deletion markers
- Update handleFileUploads to only upload truly new files, preventing re-upload of existing files
- Add setupExistingFilePreview() for proper existing file integration with new helpers
- Update modal manager to use new helper functions and proper state clearing
- Add robust error handling and backward compatibility fallbacks
Fixes:
- File duplication when editing existing assets
- Missing image previews for existing files in edit modal
- Broken individual file deletions
- State persistence contamination between different asset operations
- Inconsistent behavior between drag-and-drop and file input selection
The file upload system now properly handles all edge cases while maintaining
a clean, predictable state across different operations.
* Add logic for import file drag and drop and restricting to single file
remove single attribute
adding self reference to eventlisteners for drag and drop
simplifying resetfileupload per file input
---------
Co-authored-by: gitmotion <43588713+gitmotion@users.noreply.github.com>
Fix save subasset child modal and delete approriate files for those subassets and subassetchildren
Refactor and simply delete and update logic for assets and subassets
update import for url example
add resetImportForm to window from importmanager instead of script.js
update subasset file attachment expand/collapse to before showing the modal
match accepted file types from frontend to backend for manuals
update deleteAssetFileAsync with early return and to work with starting "/" or without
initialize settings with default and copy over settings to always make sure all properties are included
remove unused async from createWarrantyDashboard function
Summary of Changes
I've successfully added a "Lifetime" column to the import modal that maps to the isLifetime property in the asset warranty object. Here's what was implemented:
1. Frontend Changes (HTML)
Added a new "Lifetime" column mapping row in the import modal (public/index.html)
Positioned it logically after "Warranty Expiration" and before "2nd Warranty Scope"
2. Frontend Changes (JavaScript)
public/managers/import.js:
Added lifetimeColumn to the column selection dropdowns
Added lifetime to the mappings object for form data collection
Added auto-mapping rules for common lifetime column names: ["lifetime", "lifetime warranty", "is lifetime", "islifetime", "permanent"]
Updated the CSV template to include the "Lifetime" column
Added sample data generation for the lifetime column (defaults to false)
Added lifetimeColumn to the reset form function
3. Backend Changes (Server)
server.js:
Added parsing logic for the lifetime column that accepts multiple formats:
true, 1, yes (case-insensitive) → true
Everything else → false
When isLifetime is true, the warranty expiration date is automatically set to null
The isLifetime property is properly set in the warranty object
Key Features
Flexible Input: Accepts true/false, 1/0, yes/no (case-insensitive)
Auto-mapping: Automatically detects common column names for lifetime warranties
Template Generation: Downloads include the Lifetime column with sample data
Data Validation: Properly handles the boolean conversion and warranty logic
Updated the formatNotification function in appriseNotifier.js to:
Include detailed asset information specifically for deletion events
Format each field with a clear label
Handle warranty information with both scope and expiration date
Keep the original format for other notification types
Updated the server code to pass all the required asset information when sending the deletion notification:
Asset Name
Model Number
Serial Number
Purchase Date
Price
Warranty information (scope and expiration date)
Server-Side Static File Serving: Added Express routes to serve uploaded files from the data directories:
Client-Side File Path Handling: Added a helper function to format file paths:
Updated Asset Rendering: Modified the asset rendering logic to use the new formatFilePath function for all image and file paths.
updated security and relying on cors for now
clean up header actions buttons
Updated helmet config, responsive styling, icons fixes, and reordering
update header title to left side and actions on right
Unify modal styling
fix login styling
adding paths for saving/editing to public paths for now to restore functionality. we should refactor this to pass pin/session for any request
Bump cache version
remove post install script
Update PIN logic for firefox compatibility and securely handle redirects
Unify add component section/modal
Unifying file uploaders, modal title styles, add collapsible sections for file uploaders