Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion public/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ document.addEventListener('DOMContentLoaded', () => {
const chartManager = new ChartManager({ formatDate });

// Acts as constructor for the app
// will be called at the very end of the file
/**
* Initializes the DumbAssets application, setting up integrations, managers, UI components, event listeners, and loading initial data.
*
* This function bootstraps the entire app, including loading integrations for dynamic features, initializing all core managers and modules, configuring UI event handlers, and rendering the initial dashboard or asset view based on URL parameters.
*/
async function initialize() {
// Display demo banner if in demo mode
if (window.appConfig?.demoMode) {
Expand Down
38 changes: 31 additions & 7 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -918,10 +918,13 @@ async function createSubAssetDuplicate(source, index, selectedProperties, allSub
}

/**
* Handles file duplication for assets and sub-assets
* @param {Object} source - The source asset/sub-asset
* @param {Object} duplicate - The duplicate asset/sub-asset
* @param {Object} selectedProperties - Which properties to copy
* Duplicates file references and associated metadata for asset or sub-asset objects, handling both local and external files.
*
* For each selected property (photos, receipts, manuals), copies local files to new locations and updates file info, while external files (identified by integration ID or external path) are referenced as-is in the duplicate object.
*
* @param {Object} source - The original asset or sub-asset containing file references and metadata.
* @param {Object} duplicate - The duplicate asset or sub-asset object to populate with duplicated file references and metadata.
* @param {Object} selectedProperties - An object indicating which file properties (photoPath, receiptPath, manualPath) should be duplicated.
*/
async function handleFileDuplication(source, duplicate, selectedProperties) {
// Initialize file arrays and paths
Expand All @@ -935,7 +938,13 @@ async function handleFileDuplication(source, duplicate, selectedProperties) {
duplicate.receiptPath = null;
duplicate.manualPath = null;

// Helper to check if a file is external (integrationId or /external/ path)
/**
* Determines whether a file is considered external based on its path or associated file information.
* A file is external if its file info contains an `integrationId` or its path includes `/external/`.
* @param {string} filePath - The file path to check.
* @param {Object} fileInfo - Optional file information object.
* @return {boolean} True if the file is external; otherwise, false.
*/
function isExternalFile(filePath, fileInfo) {
if (!filePath && !fileInfo) return false;
if (fileInfo && fileInfo.integrationId) return true;
Expand Down Expand Up @@ -2057,6 +2066,10 @@ function parseExcelDate(value) {
return '';
}

/**
* Retrieves the current application settings, merging saved configuration from disk with default settings.
* @returns {Object} The combined application settings object.
*/
function getAppSettings() {
const configPath = path.join(DATA_DIR, 'config.json');
// Return default settings if config does not exist
Expand All @@ -2068,7 +2081,13 @@ function getAppSettings() {
return config;
}

// Use before sending settings to frontend
/**
* Returns a copy of the application settings with sensitive integration tokens removed from integration configurations.
*
* Uses the integration manager to sanitize each integration's settings before exposing them to the frontend.
* @param {Object} appSettings - The full application settings object.
* @return {Object} The sanitized settings object safe for frontend use.
*/
function stripIntegrationTokens(appSettings) {
const sanitizedSettings = { ...appSettings };

Expand All @@ -2084,7 +2103,12 @@ function stripIntegrationTokens(appSettings) {
return sanitizedSettings;
}

// Use integration manager for validation and sensitive data handling
/**
* Validates and applies integration settings to the server configuration using the integration manager.
* @param {object} serverConfig - The current server configuration.
* @param {object} updatedConfig - The updated configuration containing new integration settings.
* @return {object} The result of applying and validating the integration settings.
*/
function applyIntegrationSettings(serverConfig, updatedConfig) {
return integrationManager.applyIntegrationSettings(serverConfig, updatedConfig);
}
Expand Down
21 changes: 15 additions & 6 deletions src/services/render/assetRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,19 @@ let subAssetContainer;
let integrationsManager;

/**
* Get the appropriate integration badge HTML based on integration ID
* @param {string} integrationId - The integration identifier
* @returns {string} - The badge HTML
* Returns the HTML for an integration badge corresponding to the given integration ID.
* If the integrations manager provides a badge, it is used; otherwise, a generic badge is returned.
* @param {string} integrationId - The unique identifier for the integration.
* @returns {string} HTML string representing the integration badge.
*/
function getIntegrationBadge(integrationId) {
return integrationsManager?.getIntegrationBadge(integrationId) || `<div class="integration-badge generic-badge"><span title="From ${integrationId}">${integrationId}</span></div>`;
}

/**
* Initialize the renderer with required dependencies
*
* @param {Object} config Configuration object with dependencies
* Initializes the asset renderer service with external dependencies and configuration.
*
* @param {Object} config - Object containing utility functions, module methods, global state, DOM references, and an integrations manager required for rendering assets and sub-assets.
*/
function initRenderer(config) {
// Store references to utility functions
Expand Down Expand Up @@ -271,6 +272,14 @@ function formatDisplayFileName(fileName, maxLength = 15) {
return nameWithoutExt.substring(0, availableSpace) + '...' + extension;
}

/**
* Generates HTML markup for displaying asset-related files, including photos, receipts, and manuals, with integration badges and file labels.
*
* Supports both multiple and single file paths for backward compatibility. Integration-specific CSS classes and badges are applied when integration information is present. For photos, uses a preview URL if provided by an integration.
*
* @param {Object} asset - The asset object containing file paths and metadata.
* @returns {string} HTML string representing the file grid, or a comment if no files are available.
*/
function generateFileGridHTML(asset) {
let html = '';

Expand Down
66 changes: 39 additions & 27 deletions src/services/render/previewRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
let integrationsManager;

/**
* Create a photo preview element
*
* @param {string} filePath - Path to the photo file
* @param {Function} onDeleteCallback - Callback function when delete button is clicked
* @return {HTMLElement} The created preview element
* Creates an HTML element displaying a photo file preview, including an optional integration badge and delete button.
*
* @param {string} filePath - The path to the photo file.
* @param {Function} onDeleteCallback - Function to call when the delete button is clicked.
* @param {string|null} [fileName=null] - Optional display name for the file; extracted from the path if not provided.
* @param {number|null} [fileSize=null] - Optional file size (unused in preview rendering).
* @param {string|null} [integrationId=null] - Optional integration ID to display an associated badge.
* @return {HTMLElement} The constructed photo preview element.
*/
export function createPhotoPreview(filePath, onDeleteCallback, fileName = null, fileSize = null, integrationId = null) {
const previewItem = document.createElement('div');
Expand Down Expand Up @@ -54,12 +57,17 @@ export function createPhotoPreview(filePath, onDeleteCallback, fileName = null,
}

/**
* Create a document preview element (receipt or manual)
*
* @param {string} type - Type of document ('receipt', 'manual', or 'image')
* @param {string} filePath - Path to the document file
* @param {Function} onDeleteCallback - Callback function when delete button is clicked
* @return {HTMLElement} The created preview element
* Creates an HTML element representing a document preview, including icon, file name, and optional integration badge.
*
* Supports document types such as 'receipt', 'manual', 'import', 'image', and defaults to 'document'. The preview includes a type-specific icon, a delete button, and displays the file name. If an integration ID is provided, an integration badge is shown.
*
* @param {string} type - The type of document ('receipt', 'manual', 'import', 'image', or other).
* @param {string} filePath - The path to the document file.
* @param {Function} onDeleteCallback - Callback invoked when the delete button is clicked.
* @param {string|null} [fileName=null] - Optional file name to display; extracted from filePath if not provided.
* @param {number|null} [fileSize=null] - Optional file size (not displayed in the preview).
* @param {string|null} [integrationId=null] - Optional integration ID for displaying an integration badge.
* @return {HTMLElement} The constructed document preview element.
*/
export function createDocumentPreview(type, filePath, onDeleteCallback, fileName = null, fileSize = null, integrationId = null) {
const previewItem = document.createElement('div');
Expand Down Expand Up @@ -187,17 +195,19 @@ export function setupFilePreview(container, type, displayPath, originalPath, fil
}

/**
* Add existing file preview using the new file upload helpers (prevents re-upload duplication)
*
* @param {Element} container - The container element to add preview to
* @param {string} type - Type of preview ('photo', 'receipt', or 'manual')
* @param {string} displayPath - Path to the file for display (e.g., with base URL)
* @param {string} originalPath - Original path of the file as stored on the server
* @param {Element} fileInput - The file input element
* @param {Object} modalManager - The instance of the modal manager to update delete flags
* @param {string} fileName - The name of the file
* @param {string} fileSize - The size of the file (in bytes)
* @param {Object} fileInfo - Additional file information (e.g., integrationId)
* Adds a preview element for an existing file to a container, supporting integration badges and preventing duplicate uploads.
*
* For files linked to integrations, displays the appropriate badge and uses a preview URL if available. Handles special cases for Paperless integration images by rendering a document preview with an image icon. When a file is deleted, updates the modal manager's deletion list and, if file upload helpers are present, adds a marker file to track the deletion.
*
* @param {Element} container - The container to which the preview element will be appended.
* @param {string} type - The type of file preview ('photo', 'receipt', 'manual', 'import', 'image', or other document types).
* @param {string} displayPath - The display path or URL for the file.
* @param {string} originalPath - The original server-side path of the file.
* @param {Element} fileInput - The file input element associated with the upload.
* @param {Object} modalManager - The modal manager instance used to track files marked for deletion.
* @param {string} [fileName=null] - The file's name; if not provided, it is extracted from the display path.
* @param {string} [fileSize=null] - The file's size in bytes.
* @param {Object} [fileInfo={}] - Additional file metadata, such as integrationId, previewUrl, or mimeType.
*/
export function setupExistingFilePreview(container, type, displayPath, originalPath, fileInput, modalManager, fileName = null, fileSize = null, fileInfo = {}) {
if (!container || !displayPath || !fileInput) return;
Expand Down Expand Up @@ -271,17 +281,19 @@ export function setupExistingFilePreview(container, type, displayPath, originalP
}

/**
* Get the appropriate integration badge HTML based on integration ID
* @param {string} integrationId - The integration identifier
* @returns {string} - The badge HTML
* Returns the HTML string for an integration badge corresponding to the given integration ID.
* If a badge is not available from the integrations manager, a generic badge is returned.
* @param {string} integrationId - The unique identifier for the integration.
* @returns {string} The HTML markup for the integration badge.
*/
function getIntegrationBadge(integrationId) {
return integrationsManager?.getIntegrationBadge(integrationId) || `<div class="integration-badge generic-badge"><span title="From ${integrationId}">${integrationId}</span></div>`;
}

/**
* Initialize the preview renderer with required dependencies
* @param {Object} config Configuration object with dependencies
* Initializes the preview renderer with external dependencies.
*
* Sets up required services such as the integrations manager for use in file preview rendering functions.
*/
export function initPreviewRenderer(config) {
integrationsManager = config.integrationsManager;
Expand Down