From 5bffc4ffa46b1d61148c4b337713eefa6f36caa0 Mon Sep 17 00:00:00 2001 From: srikanth-s2003 Date: Mon, 6 Oct 2025 18:40:01 +0530 Subject: [PATCH 1/3] fix: trim whitespace for secrete name and file paths in UI; deterministic duration formatting --- front/assets/js/insights/util/formatter.ts | 36 ++++++++++++++++------ front/assets/js/manage_secret.js | 36 +++++++++++++++++++--- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/front/assets/js/insights/util/formatter.ts b/front/assets/js/insights/util/formatter.ts index 005874133..539cd539d 100644 --- a/front/assets/js/insights/util/formatter.ts +++ b/front/assets/js/insights/util/formatter.ts @@ -32,17 +32,33 @@ export const Formatter = { return `N/A`; } - if (secs >= 3600 * 24) { - const fullDays = Math.floor(secs / (3600 * 24)); - return moment.unix(secs).format(`${fullDays}[d] H[h] m[m] s[s]`); - } else if (secs >= 3600) { - const duration = moment.duration(secs, `seconds`); - return `${duration.hours()}h ${duration.minutes()}m ${duration.seconds()}s`; - } else if (secs >= 60) { - return moment.unix(secs).format(`m[m] s[s]`); - } else { - return moment.unix(secs).format(`s[s]`); + // Use arithmetic-based formatting (days/hours/minutes/seconds) to avoid + // timezone-dependent behavior of `moment.unix(...).format(...)`. + const secondsInDay = 24 * 3600; + const secondsInHour = 3600; + const secondsInMinute = 60; + + let remaining = Math.floor(secs); + const days = Math.floor(remaining / secondsInDay); + remaining = remaining % secondsInDay; + const hours = Math.floor(remaining / secondsInHour); + remaining = remaining % secondsInHour; + const minutes = Math.floor(remaining / secondsInMinute); + const seconds = remaining % secondsInMinute; + + if (days > 0) { + return `${days}d ${hours}h ${minutes}m ${seconds}s`; } + + if (hours > 0) { + return `${hours}h ${minutes}m ${seconds}s`; + } + + if (minutes > 0) { + return `${minutes}m ${seconds}s`; + } + + return `${seconds}s`; }, percentage: (percentage: number): string => { diff --git a/front/assets/js/manage_secret.js b/front/assets/js/manage_secret.js index 446a94e19..1953e7553 100644 --- a/front/assets/js/manage_secret.js +++ b/front/assets/js/manage_secret.js @@ -142,6 +142,8 @@ export var ManageSecret = { secretEditor.browseFilesOnClick(fileUploadLink, fileUpload); secretEditor.formatUploadedFile(fileUpload, fileContent, fileDiv, fileInput, fileDeleteLink, fileMd5PresentId, fileImageId); secretEditor.activateFilesDeleteLink(fileDeleteLink, fileDiv, fileInput, fileContent, md5Id); + // Attach trimming handler for the file path input + secretEditor.attachFilePathTrimmer(fileInput); }); }, @@ -152,12 +154,16 @@ export var ManageSecret = { let envVarIndex = secretEditor.envVars.length - 1; let envVar = secretEditor.envVars[envVarIndex]; - let [element, envVarDiv, envVarDeleteLink, envVarInput, md5Id] = + // envVarElement returns [element, envVarNameId, envVarDivId, envVarDeleteLink, envVarValueId, envVarMd5Id] + let [element, envVarNameId, envVarDiv, envVarDeleteLink, envVarInput, md5Id] = secretEditor.envVarElement(envVar, envVarIndex); document.getElementById("env-vars-input").insertAdjacentHTML("beforeend", element); secretEditor.activateEnvVarDeleteLink(envVarDeleteLink, envVarDiv, envVarInput, md5Id); + // ensure validation/trim is attached for the newly created input + secretEditor.activateEnvVarValidation(envVarNameId); + return false; }); }, @@ -177,16 +183,33 @@ export var ManageSecret = { secretEditor.browseFilesOnClick(fileUploadLink, fileUpload); secretEditor.formatUploadedFile(fileUpload, fileContent, fileDiv, fileInput, fileDeleteLink, fileMd5PresentId, fileImageId); secretEditor.activateFilesDeleteLink(fileDeleteLink, fileDiv, fileInput, fileContent, md5Id); + // Attach trimming handler for newly cloned file path input + secretEditor.attachFilePathTrimmer(fileInput); return false; }); }, + attachFilePathTrimmer: function(fileInputId) { + // fileInputId is the id of the visible text input for the file path (e.g. files_0_path) + $("body").on("change blur input", "#" + fileInputId, function() { + let raw = $(this).val(); + let trimmed = raw !== undefined && raw !== null ? raw.trim() : raw; + if (raw !== trimmed) { + $(this).val(trimmed); + } + }); + }, + activateEnvVarValidation: function (selector) { let secretEditor = this; - $("body").on("change textInput input", "#" + selector, function () { - valid_name_regex = /^[a-zA-Z_][a-zA-Z0-9_]*$/; - let name = $(this).val(); + // Validate on input and change, but always validate the trimmed value. + $("body").on("change textInput input blur", "#" + selector, function () { + const valid_name_regex = /^[a-zA-Z_][a-zA-Z0-9_]*$/; + // Trim whitespace from the input value (leading/trailing) and update the field on blur/change + let raw = $(this).val(); + let name = raw !== undefined && raw !== null ? raw.trim() : raw; + if (name.match(valid_name_regex)) { $(this).next(".error-message").remove(); // removes existing error message } @@ -194,6 +217,11 @@ export var ManageSecret = { $(this).next(".error-message").remove(); // removes existing error message $(this).after('

Invalid variable name!

'); } + + // If the visible value differs from trimmed, update it on blur/change + if (raw !== name) { + $(this).val(name); + } }); }, From df539cbd22d1b037d8abe4f11a77178a73bb23b6 Mon Sep 17 00:00:00 2001 From: srikanth-s2003 Date: Fri, 10 Oct 2025 19:15:11 +0530 Subject: [PATCH 2/3] fix: apply reviewer feedback - correct file path trimming and remove redundant blur events - Pass correct filePathInput ID to attachFilePathTrimmer instead of container ID - Remove redundant blur events from both env var and file path handlers - Update variable destructuring to match fileElement return values - File path trimming now works correctly for both existing and newly added files --- front/assets/js/manage_secret.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/front/assets/js/manage_secret.js b/front/assets/js/manage_secret.js index 1953e7553..a8d94aaa0 100644 --- a/front/assets/js/manage_secret.js +++ b/front/assets/js/manage_secret.js @@ -111,7 +111,7 @@ export var ManageSecret = { ` - return [element, secretUploadLinkId, secretUploadId, fileContentId, fileDivId, secretInputId, fileDeleteLink, fileMd5Id, fileMd5PresentId, fileImageId]; + return [element, secretUploadLinkId, secretUploadId, fileContentId, fileDivId, secretInputId, fileDeleteLink, fileMd5Id, fileMd5PresentId, fileImageId, filePathId]; }, showEnvVars: function() { @@ -134,16 +134,16 @@ export var ManageSecret = { document.getElementById("files-input").innerHTML = ""; this.files.forEach(function(file, index) { - let [element, fileUploadLink, fileUpload, fileContent, fileDiv, fileInput, fileDeleteLink, md5Id, fileMd5PresentId, fileImageId] = + let [element, fileUploadLink, fileUpload, fileContent, fileDiv, fileInputContainer, fileDeleteLink, md5Id, fileMd5PresentId, fileImageId, filePathInput] = secretEditor.fileElement(file, index); document.getElementById("files-input").insertAdjacentHTML("beforeend", element); secretEditor.browseFilesOnClick(fileUploadLink, fileUpload); - secretEditor.formatUploadedFile(fileUpload, fileContent, fileDiv, fileInput, fileDeleteLink, fileMd5PresentId, fileImageId); - secretEditor.activateFilesDeleteLink(fileDeleteLink, fileDiv, fileInput, fileContent, md5Id); + secretEditor.formatUploadedFile(fileUpload, fileContent, fileDiv, fileInputContainer, fileDeleteLink, fileMd5PresentId, fileImageId); + secretEditor.activateFilesDeleteLink(fileDeleteLink, fileDiv, fileInputContainer, fileContent, md5Id); // Attach trimming handler for the file path input - secretEditor.attachFilePathTrimmer(fileInput); + secretEditor.attachFilePathTrimmer(filePathInput); }); }, @@ -175,16 +175,16 @@ export var ManageSecret = { let fileIndex = secretEditor.files.length - 1; let file = secretEditor.files[fileIndex]; - let [element, fileUploadLink, fileUpload, fileContent, fileDiv, fileInput, fileDeleteLink, md5Id, fileMd5PresentId, fileImageId] = + let [element, fileUploadLink, fileUpload, fileContent, fileDiv, fileInputContainer, fileDeleteLink, md5Id, fileMd5PresentId, fileImageId, filePathInput] = secretEditor.fileElement(file, fileIndex); document.getElementById("files-input").insertAdjacentHTML("beforeend", element); secretEditor.browseFilesOnClick(fileUploadLink, fileUpload); - secretEditor.formatUploadedFile(fileUpload, fileContent, fileDiv, fileInput, fileDeleteLink, fileMd5PresentId, fileImageId); - secretEditor.activateFilesDeleteLink(fileDeleteLink, fileDiv, fileInput, fileContent, md5Id); + secretEditor.formatUploadedFile(fileUpload, fileContent, fileDiv, fileInputContainer, fileDeleteLink, fileMd5PresentId, fileImageId); + secretEditor.activateFilesDeleteLink(fileDeleteLink, fileDiv, fileInputContainer, fileContent, md5Id); // Attach trimming handler for newly cloned file path input - secretEditor.attachFilePathTrimmer(fileInput); + secretEditor.attachFilePathTrimmer(filePathInput); return false; }); @@ -192,7 +192,7 @@ export var ManageSecret = { attachFilePathTrimmer: function(fileInputId) { // fileInputId is the id of the visible text input for the file path (e.g. files_0_path) - $("body").on("change blur input", "#" + fileInputId, function() { + $("body").on("change input", "#" + fileInputId, function() { let raw = $(this).val(); let trimmed = raw !== undefined && raw !== null ? raw.trim() : raw; if (raw !== trimmed) { @@ -204,8 +204,8 @@ export var ManageSecret = { activateEnvVarValidation: function (selector) { let secretEditor = this; // Validate on input and change, but always validate the trimmed value. - $("body").on("change textInput input blur", "#" + selector, function () { - const valid_name_regex = /^[a-zA-Z_][a-zA-Z0-9_]*$/; + $("body").on("change textInput input", "#" + selector, function () { + const valid_name_regex = /^[a-zA-Z_][a-zA-Z0-9_]*$/; // Trim whitespace from the input value (leading/trailing) and update the field on blur/change let raw = $(this).val(); let name = raw !== undefined && raw !== null ? raw.trim() : raw; From d5602da623717948b03d349025338eed8d447dfc Mon Sep 17 00:00:00 2001 From: srikanth-s2003 Date: Fri, 10 Oct 2025 19:18:38 +0530 Subject: [PATCH 3/3] refactor: remove duration formatter changes from trimming PR Moved duration formatter fix to separate PR as requested by reviewer. This PR now focuses solely on secret name and file path trimming functionality. --- front/assets/js/insights/util/formatter.ts | 36 ++++++---------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/front/assets/js/insights/util/formatter.ts b/front/assets/js/insights/util/formatter.ts index 539cd539d..005874133 100644 --- a/front/assets/js/insights/util/formatter.ts +++ b/front/assets/js/insights/util/formatter.ts @@ -32,33 +32,17 @@ export const Formatter = { return `N/A`; } - // Use arithmetic-based formatting (days/hours/minutes/seconds) to avoid - // timezone-dependent behavior of `moment.unix(...).format(...)`. - const secondsInDay = 24 * 3600; - const secondsInHour = 3600; - const secondsInMinute = 60; - - let remaining = Math.floor(secs); - const days = Math.floor(remaining / secondsInDay); - remaining = remaining % secondsInDay; - const hours = Math.floor(remaining / secondsInHour); - remaining = remaining % secondsInHour; - const minutes = Math.floor(remaining / secondsInMinute); - const seconds = remaining % secondsInMinute; - - if (days > 0) { - return `${days}d ${hours}h ${minutes}m ${seconds}s`; + if (secs >= 3600 * 24) { + const fullDays = Math.floor(secs / (3600 * 24)); + return moment.unix(secs).format(`${fullDays}[d] H[h] m[m] s[s]`); + } else if (secs >= 3600) { + const duration = moment.duration(secs, `seconds`); + return `${duration.hours()}h ${duration.minutes()}m ${duration.seconds()}s`; + } else if (secs >= 60) { + return moment.unix(secs).format(`m[m] s[s]`); + } else { + return moment.unix(secs).format(`s[s]`); } - - if (hours > 0) { - return `${hours}h ${minutes}m ${seconds}s`; - } - - if (minutes > 0) { - return `${minutes}m ${seconds}s`; - } - - return `${seconds}s`; }, percentage: (percentage: number): string => {