Skip to content

Commit 9e20ef7

Browse files
fix: trim whitespace for secrete name and file paths in UI; deterministic duration formatting
1 parent 1875486 commit 9e20ef7

File tree

2 files changed

+58
-14
lines changed

2 files changed

+58
-14
lines changed

front/assets/js/insights/util/formatter.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,33 @@ export const Formatter = {
3232
return `N/A`;
3333
}
3434

35-
if (secs >= 3600 * 24) {
36-
const fullDays = Math.floor(secs / (3600 * 24));
37-
return moment.unix(secs).format(`${fullDays}[d] H[h] m[m] s[s]`);
38-
} else if (secs >= 3600) {
39-
const duration = moment.duration(secs, `seconds`);
40-
return `${duration.hours()}h ${duration.minutes()}m ${duration.seconds()}s`;
41-
} else if (secs >= 60) {
42-
return moment.unix(secs).format(`m[m] s[s]`);
43-
} else {
44-
return moment.unix(secs).format(`s[s]`);
35+
// Use arithmetic-based formatting (days/hours/minutes/seconds) to avoid
36+
// timezone-dependent behavior of `moment.unix(...).format(...)`.
37+
const secondsInDay = 24 * 3600;
38+
const secondsInHour = 3600;
39+
const secondsInMinute = 60;
40+
41+
let remaining = Math.floor(secs);
42+
const days = Math.floor(remaining / secondsInDay);
43+
remaining = remaining % secondsInDay;
44+
const hours = Math.floor(remaining / secondsInHour);
45+
remaining = remaining % secondsInHour;
46+
const minutes = Math.floor(remaining / secondsInMinute);
47+
const seconds = remaining % secondsInMinute;
48+
49+
if (days > 0) {
50+
return `${days}d ${hours}h ${minutes}m ${seconds}s`;
4551
}
52+
53+
if (hours > 0) {
54+
return `${hours}h ${minutes}m ${seconds}s`;
55+
}
56+
57+
if (minutes > 0) {
58+
return `${minutes}m ${seconds}s`;
59+
}
60+
61+
return `${seconds}s`;
4662
},
4763

4864
percentage: (percentage: number): string => {

front/assets/js/manage_secret.js

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ export var ManageSecret = {
142142
secretEditor.browseFilesOnClick(fileUploadLink, fileUpload);
143143
secretEditor.formatUploadedFile(fileUpload, fileContent, fileDiv, fileInput, fileDeleteLink, fileMd5PresentId, fileImageId);
144144
secretEditor.activateFilesDeleteLink(fileDeleteLink, fileDiv, fileInput, fileContent, md5Id);
145+
// Attach trimming handler for the file path input
146+
secretEditor.attachFilePathTrimmer(fileInput);
145147
});
146148
},
147149

@@ -152,12 +154,16 @@ export var ManageSecret = {
152154

153155
let envVarIndex = secretEditor.envVars.length - 1;
154156
let envVar = secretEditor.envVars[envVarIndex];
155-
let [element, envVarDiv, envVarDeleteLink, envVarInput, md5Id] =
157+
// envVarElement returns [element, envVarNameId, envVarDivId, envVarDeleteLink, envVarValueId, envVarMd5Id]
158+
let [element, envVarNameId, envVarDiv, envVarDeleteLink, envVarInput, md5Id] =
156159
secretEditor.envVarElement(envVar, envVarIndex);
157160

158161
document.getElementById("env-vars-input").insertAdjacentHTML("beforeend", element);
159162
secretEditor.activateEnvVarDeleteLink(envVarDeleteLink, envVarDiv, envVarInput, md5Id);
160163

164+
// ensure validation/trim is attached for the newly created input
165+
secretEditor.activateEnvVarValidation(envVarNameId);
166+
161167
return false;
162168
});
163169
},
@@ -177,23 +183,45 @@ export var ManageSecret = {
177183
secretEditor.browseFilesOnClick(fileUploadLink, fileUpload);
178184
secretEditor.formatUploadedFile(fileUpload, fileContent, fileDiv, fileInput, fileDeleteLink, fileMd5PresentId, fileImageId);
179185
secretEditor.activateFilesDeleteLink(fileDeleteLink, fileDiv, fileInput, fileContent, md5Id);
186+
// Attach trimming handler for newly cloned file path input
187+
secretEditor.attachFilePathTrimmer(fileInput);
180188

181189
return false;
182190
});
183191
},
184192

193+
attachFilePathTrimmer: function(fileInputId) {
194+
// fileInputId is the id of the visible text input for the file path (e.g. files_0_path)
195+
$("body").on("change blur input", "#" + fileInputId, function() {
196+
let raw = $(this).val();
197+
let trimmed = raw !== undefined && raw !== null ? raw.trim() : raw;
198+
if (raw !== trimmed) {
199+
$(this).val(trimmed);
200+
}
201+
});
202+
},
203+
185204
activateEnvVarValidation: function (selector) {
186205
let secretEditor = this;
187-
$("body").on("change textInput input", "#" + selector, function () {
188-
valid_name_regex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
189-
let name = $(this).val();
206+
// Validate on input and change, but always validate the trimmed value.
207+
$("body").on("change textInput input blur", "#" + selector, function () {
208+
const valid_name_regex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
209+
// Trim whitespace from the input value (leading/trailing) and update the field on blur/change
210+
let raw = $(this).val();
211+
let name = raw !== undefined && raw !== null ? raw.trim() : raw;
212+
190213
if (name.match(valid_name_regex)) {
191214
$(this).next(".error-message").remove(); // removes existing error message
192215
}
193216
else {
194217
$(this).next(".error-message").remove(); // removes existing error message
195218
$(this).after('<p class="f6 fw5 mt1 mb0 red error-message">Invalid variable name!</p>');
196219
}
220+
221+
// If the visible value differs from trimmed, update it on blur/change
222+
if (raw !== name) {
223+
$(this).val(name);
224+
}
197225
});
198226
},
199227

0 commit comments

Comments
 (0)