From 6e9f612c1131df589b223d73db0ecb3ef8b22728 Mon Sep 17 00:00:00 2001 From: grvwy Date: Tue, 20 May 2025 00:02:36 +0200 Subject: [PATCH 01/18] feat: support for adding multiple tags at once I got tired of having to manually add tags one by one so I made changes to be able to add multiple tags in one go --- .gitignore | 1 + src/components/TagsManager.vue | 300 ++++++++++++++++++++++----------- src/lang/en.json | 10 +- 3 files changed, 215 insertions(+), 96 deletions(-) diff --git a/.gitignore b/.gitignore index b11a79354..b205b57fa 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ dist-ssr /extra/healthcheck.exe /extra/healthcheck /extra/healthcheck-armv7 +/studies extra/exe-builder/bin extra/exe-builder/obj diff --git a/src/components/TagsManager.vue b/src/components/TagsManager.vue index aa8f93a83..ae39b70d4 100644 --- a/src/components/TagsManager.vue +++ b/src/components/TagsManager.vue @@ -24,6 +24,18 @@ @@ -132,6 +156,8 @@ diff --git a/src/lang/en.json b/src/lang/en.json index c8555bf12..24826fd87 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -191,6 +191,10 @@ "Add New below or Select...": "Add New below or Select…", "Tag with this name already exist.": "Tag with this name already exists.", "Tag with this value already exist.": "Tag with this value already exists.", + "tagAlreadyOnMonitor": "This tag (name + value) is already on this monitor.", + "tagAlreadyStaged": "This tag (name + value) is already staged for this batch.", + "tagLimitReached": "Cannot stage more than {limit} new system tags in a single batch.", + "tagNameExists": "A system tag with this name already exists. Select it from the list or use a different name.", "color": "Color", "value (optional)": "value (optional)", "Gray": "Gray", @@ -1074,7 +1078,7 @@ "rabbitmqHelpText": "To use the monitor, you will need to enable the Management Plugin in your RabbitMQ setup. For more information, please consult the {rabitmq_documentation}.", "SendGrid API Key": "SendGrid API Key", "Separate multiple email addresses with commas": "Separate multiple email addresses with commas", - "smtpHelpText": "“SMTPS” tests that SMTP/TLS is working; “Ignore TLS” connects over plaintext; “STARTTLS” connects, issues a STARTTLS command and verifies the server certificate. None of these send an email.", + "smtpHelpText": "SMTPS tests that SMTP/TLS is working; Ignore TLS connects over plaintext; STARTTLS connects, issues a STARTTLS command and verifies the server certificate. None of these send an email.", "Custom URL": "Custom URL", "customUrlDescription": "Will be used as the clickable URL instead of the monitor's one.", "OneChatAccessToken": "OneChat Access Token", @@ -1098,5 +1102,7 @@ "Phone numbers": "Phone numbers", "Sender name": "Sender name", "smsplanetNeedToApproveName": "Needs to be approved in the client panel", - "Disable URL in Notification": "Disable URL in Notification" + "Disable URL in Notification": "Disable URL in Notification", + "Add Another Tag": "Add Another Tag", + "Staged Tags for Batch Add": "Staged Tags for Batch Add" } From 1cf88c9dbd3bdf97f5a94487a8bdf7e8941991ed Mon Sep 17 00:00:00 2001 From: grvwy Date: Tue, 20 May 2025 00:47:09 +0200 Subject: [PATCH 02/18] logic fixes making sure the logic works and added a clear form for UX --- src/components/TagsManager.vue | 85 +++++++++++++++++++--------------- src/lang/en.json | 8 ++-- 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/components/TagsManager.vue b/src/components/TagsManager.vue index ae39b70d4..6f1f2df96 100644 --- a/src/components/TagsManager.vue +++ b/src/components/TagsManager.vue @@ -126,27 +126,21 @@ - -
- -
- {{ $t(validateDraftTag.messageKey, validateDraftTag.messageParams) }} -
- +
+ {{ $t(validateDraftTag.messageKey, validateDraftTag.messageParams) }} +
@@ -281,12 +275,13 @@ export default { return { invalid: true, messageKey: "tagAlreadyOnMonitor", messageParams: null }; } - // If an existing tag is selected and has no value, it's valid (value is optional) - if (this.newDraftTag.select != null && draftTagValue === "") { - return { invalid: false, messageKey: null, messageParams: null }; + // If an existing tag is selected at this point, it has passed all relevant checks + if (this.newDraftTag.select != null) { + return { invalid: false, messageKey: null, messageParams: null }; } - // If none of the above, invalid: false + // If it's a new tag definition, and it passed its specific checks, it's valid. + // (This also serves as a final default to valid if other logic paths were missed, though ideally covered above) return { invalid: false, messageKey: null, messageParams: null }; }, }, @@ -554,7 +549,26 @@ export default { * @returns {void} */ confirmAndCommitStagedTags() { + // Phase 1: If there's a currently valid newDraftTag that hasn't been staged yet, + // (e.g. user typed a full tag and directly clicked the footer "Add"), then stage it now. + // stageCurrentTag has its own check for validateDraftTag.invalid and will clear the draft. + if (!this.validateDraftTag.invalid) { + // Check if newDraftTag actually has content, to avoid staging an empty cleared draft. + // A valid draft implies it has content, but double-checking select or name is safer. + if (this.newDraftTag.select || (this.newDraftTag.name && this.newDraftTag.color)) { + this.stageCurrentTag(); + } + } + + // Phase 2: Process everything that is now in stagedForBatchAdd. + if (this.stagedForBatchAdd.length === 0) { + this.clearDraftTag(); // Ensure draft is clear even if nothing was committed + this.modal.hide(); + return; + } + for (const sTag of this.stagedForBatchAdd) { + let isAnUndo = false; // Flag to track if this was an undo // Check if it's an "undo delete" if (sTag.systemTagId) { // Only existing system tags can be an undo delete const undoDeleteIndex = this.deleteTags.findIndex( @@ -562,30 +576,27 @@ export default { ); if (undoDeleteIndex > -1) { this.deleteTags.splice(undoDeleteIndex, 1); - // If it was an undo, we don't need to add it to newTags again, as it's already in preSelectedTags or newTags from a previous session effectively - // However, the plan implies adding to newTags regardless. Let's stick to the plan. - // If this tag was previously in preSelectedTags and then deleted (in deleteTags), - // removing it from deleteTags makes it active again via selectedTags computed prop. - // If it was newly added in this session, then deleted, then re-staged, it would be in newTags. - // For simplicity and to align with the plan V.4 which says "Push this object to this.newTags": + isAnUndo = true; } } - // Create tag object for this.newTags - // The `new: true` flag indicates it's part of this transaction for the monitor. - // It does not strictly mean it is a new system tag. - const tagObjectForNewTags = { - id: sTag.systemTagId, // This will be null for brand new system tags - color: sTag.color, - name: sTag.name, - value: sTag.value, - new: true, // As per plan, signals new to this monitor transaction - }; - this.newTags.push(tagObjectForNewTags); + // Only add to newTags if it's not an "undo delete" operation. + // An "undo delete" means the tag is now considered active again from its previous state. + if (!isAnUndo) { + const tagObjectForNewTags = { + id: sTag.systemTagId, // This will be null for brand new system tags + color: sTag.color, + name: sTag.name, + value: sTag.value, + new: true, // As per plan, signals new to this monitor transaction + }; + this.newTags.push(tagObjectForNewTags); + } } - this.stagedForBatchAdd = []; - this.clearDraftTag(); // Resets input fields + // newDraftTag should have been cleared if stageCurrentTag ran in Phase 1, or earlier. + // Call clearDraftTag again to be certain the form is reset before closing. + this.clearDraftTag(); this.modal.hide(); }, }, diff --git a/src/lang/en.json b/src/lang/en.json index 24826fd87..08dc3eaba 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -191,8 +191,8 @@ "Add New below or Select...": "Add New below or Select…", "Tag with this name already exist.": "Tag with this name already exists.", "Tag with this value already exist.": "Tag with this value already exists.", - "tagAlreadyOnMonitor": "This tag (name + value) is already on this monitor.", - "tagAlreadyStaged": "This tag (name + value) is already staged for this batch.", + "tagAlreadyOnMonitor": "This tag (name and value) is already on the monitor or pending addition.", + "tagAlreadyStaged": "This tag (name and value) is already staged for this batch.", "tagLimitReached": "Cannot stage more than {limit} new system tags in a single batch.", "tagNameExists": "A system tag with this name already exists. Select it from the list or use a different name.", "color": "Color", @@ -1104,5 +1104,7 @@ "smsplanetNeedToApproveName": "Needs to be approved in the client panel", "Disable URL in Notification": "Disable URL in Notification", "Add Another Tag": "Add Another Tag", - "Staged Tags for Batch Add": "Staged Tags for Batch Add" + "Staged Tags for Batch Add": "Staged Tags for Batch Add", + "Clear Form": "Clear Form", + "pause": "Pause" } From d694ec65b035bdd553391c94eb8961b359c836a9 Mon Sep 17 00:00:00 2001 From: grvwy Date: Tue, 20 May 2025 01:06:34 +0200 Subject: [PATCH 03/18] Update TagsManager.vue --- src/components/TagsManager.vue | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/TagsManager.vue b/src/components/TagsManager.vue index 6f1f2df96..3378ad58c 100644 --- a/src/components/TagsManager.vue +++ b/src/components/TagsManager.vue @@ -24,7 +24,7 @@ From 30ee561b66e753855b12c2db4cd762d6bc265591 Mon Sep 17 00:00:00 2001 From: grvwy Date: Tue, 20 May 2025 01:23:16 +0200 Subject: [PATCH 04/18] fixed linter errors and e2e test --- src/components/TagsManager.vue | 55 ++++++++++++++++++++++-------- test/e2e/specs/status-page.spec.js | 2 +- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/components/TagsManager.vue b/src/components/TagsManager.vue index 3378ad58c..957ad9c8a 100644 --- a/src/components/TagsManager.vue +++ b/src/components/TagsManager.vue @@ -128,8 +128,8 @@
- {{ $t("Clear Form") }} -
@@ -140,7 +140,7 @@ @@ -197,7 +197,7 @@ export default { /** @type {Tag[]} */ deleteTags: [], /** - * @type {Array} Holds tag objects staged for addition. + * @type {Array} Holds tag objects staged for addition. * Each object: { name, color, value, isNewSystemTag, systemTagId, keyForList } */ stagedForBatchAdd: [], @@ -224,17 +224,21 @@ export default { return this.preSelectedTags.concat(this.newTags).filter(tag => !this.deleteTags.find(monitorTag => monitorTag.tag_id === tag.tag_id)); }, /** - * @returns {boolean} True if more new system tags can be staged. + * @returns {boolean} True if more new system tags can be staged, false otherwise. */ canStageMoreNewSystemTags() { return this.stagedForBatchAdd.filter(t => t.isNewSystemTag).length < MAX_NEW_SYSTEM_TAGS_PER_BATCH; }, + /** + * Provides the color options for the tag color selector. + * @returns {Array} Array of color options. + */ colorOptions() { return colorOptions(this); }, /** * Validates the current draft tag based on several conditions. - * @returns {{invalid: boolean, messageKey: string|null, messageParams: object|null}} + * @returns {{invalid: boolean, messageKey: string|null, messageParams: object|null}} Object indicating validity, and a message key/params if invalid. */ validateDraftTag() { // If defining a new system tag (newDraftTag.select == null) @@ -243,15 +247,23 @@ export default { return { invalid: true, messageKey: "tagLimitReached", - messageParams: { limit: MAX_NEW_SYSTEM_TAGS_PER_BATCH } + messageParams: { limit: MAX_NEW_SYSTEM_TAGS_PER_BATCH }, }; } if (!this.newDraftTag.name || this.newDraftTag.name.trim() === "" || !this.newDraftTag.color) { // Keep button disabled, but don't show the explicit message for this case - return { invalid: true, messageKey: null, messageParams: null }; + return { + invalid: true, + messageKey: null, + messageParams: null, + }; } if (this.tagOptions.find(opt => opt.name.toLowerCase() === this.newDraftTag.name.trim().toLowerCase())) { - return { invalid: true, messageKey: "tagNameExists", messageParams: null }; + return { + invalid: true, + messageKey: "tagNameExists", + messageParams: null, + }; } } @@ -261,7 +273,11 @@ export default { // Check if (name + value) combination already exists in this.stagedForBatchAdd if (this.stagedForBatchAdd.find(staged => staged.name === draftTagName && staged.value === draftTagValue)) { - return { invalid: true, messageKey: "tagAlreadyStaged", messageParams: null }; + return { + invalid: true, + messageKey: "tagAlreadyStaged", + messageParams: null, + }; } // Check if (name + value) combination already exists in this.selectedTags (final list on monitor) @@ -272,17 +288,28 @@ export default { ); if (!isUndoDelete && this.selectedTags.find(sTag => sTag.name === draftTagName && sTag.value === draftTagValue)) { - return { invalid: true, messageKey: "tagAlreadyOnMonitor", messageParams: null }; + return { + invalid: true, + messageKey: "tagAlreadyOnMonitor", + messageParams: null, + }; } - // If an existing tag is selected at this point, it has passed all relevant checks if (this.newDraftTag.select != null) { - return { invalid: false, messageKey: null, messageParams: null }; + return { + invalid: false, + messageKey: null, + messageParams: null, + }; } // If it's a new tag definition, and it passed its specific checks, it's valid. // (This also serves as a final default to valid if other logic paths were missed, though ideally covered above) - return { invalid: false, messageKey: null, messageParams: null }; + return { + invalid: false, + messageKey: null, + messageParams: null, + }; }, }, mounted() { diff --git a/test/e2e/specs/status-page.spec.js b/test/e2e/specs/status-page.spec.js index 0231aa225..ebe0b2c8b 100644 --- a/test/e2e/specs/status-page.spec.js +++ b/test/e2e/specs/status-page.spec.js @@ -38,7 +38,7 @@ test.describe("Status Page", () => { await page.getByTestId("tag-value-input").fill(tagValue); await page.getByTestId("tag-color-select").click(); // Vue-Multiselect component await page.getByTestId("tag-color-select").getByRole("option", { name: "Orange" }).click(); - await page.getByTestId("tag-submit-button").click(); + await page.getByTestId("tag-final-add-button").click(); await page.getByTestId("save-button").click(); await page.waitForURL("/dashboard/*"); // wait for the monitor to be created From f0ebc0405c45be047e6ed044c89b235a45216f70 Mon Sep 17 00:00:00 2001 From: grvwy <147989282+grvwy@users.noreply.github.com> Date: Tue, 20 May 2025 21:27:35 +0200 Subject: [PATCH 05/18] Update src/components/TagsManager.vue Co-authored-by: Frank Elsinga --- src/components/TagsManager.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/TagsManager.vue b/src/components/TagsManager.vue index 957ad9c8a..b3546e571 100644 --- a/src/components/TagsManager.vue +++ b/src/components/TagsManager.vue @@ -206,7 +206,6 @@ export default { select: null, color: null, value: "", - // invalid: true, // Initial validation will be handled by computed prop }, }; }, From 12b5ca57509621fcf9ee593b7c406949429d906b Mon Sep 17 00:00:00 2001 From: grvwy Date: Tue, 20 May 2025 23:47:17 +0200 Subject: [PATCH 06/18] Updates Fixed "error Expected linebreaks to be 'LF' but found 'CRLF' " by running eslint --fix on them hence the change to @api-router.js UI updates to @Tagsmanager.vue writing multi-tag tests in @status-page.spec.js --- src/components/TagsManager.vue | 17 +++++------ test/e2e/specs/status-page.spec.js | 45 ++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/components/TagsManager.vue b/src/components/TagsManager.vue index b3546e571..ab881ce52 100644 --- a/src/components/TagsManager.vue +++ b/src/components/TagsManager.vue @@ -25,7 +25,7 @@ From 28e036e9234596806a49f9b5fd8a4f5ff04892a1 Mon Sep 17 00:00:00 2001 From: grvwy Date: Thu, 22 May 2025 23:42:06 +0200 Subject: [PATCH 09/18] fixing position and tests fixed position of "add another tag" and rewrote the tests to fit in with sequential tests --- src/components/TagsManager.vue | 16 ++------- test/e2e/specs/status-page.spec.js | 55 +++++++++--------------------- 2 files changed, 19 insertions(+), 52 deletions(-) diff --git a/src/components/TagsManager.vue b/src/components/TagsManager.vue index 61ece079e..254c4244f 100644 --- a/src/components/TagsManager.vue +++ b/src/components/TagsManager.vue @@ -121,7 +121,7 @@ -
+
{{ $t(validateDraftTag.messageKey, validateDraftTag.messageParams) }}
@@ -131,9 +131,6 @@ -
- {{ $t(validateDraftTag.messageKey, validateDraftTag.messageParams) }} -