From 9113d539f0975d5ba78fdbd999097ccca9cabd32 Mon Sep 17 00:00:00 2001 From: Gregoo Date: Sat, 25 Jan 2025 19:43:16 +0100 Subject: [PATCH 1/8] Split the JS socket with a generic part and one dedicated to load Rebrickable sets --- static/scripts/socket/set.js | 244 ++++++++++++++++++++++++++ static/scripts/{ => socket}/socket.js | 207 +--------------------- templates/base.html | 3 +- templates/set/socket.html | 2 +- 4 files changed, 249 insertions(+), 207 deletions(-) create mode 100644 static/scripts/socket/set.js rename static/scripts/{ => socket}/socket.js (54%) diff --git a/static/scripts/socket/set.js b/static/scripts/socket/set.js new file mode 100644 index 0000000..60a2244 --- /dev/null +++ b/static/scripts/socket/set.js @@ -0,0 +1,244 @@ +// Set Socket class +class BrickSetSocket extends BrickSocket { + constructor(id, path, namespace, messages, bulk=false) { + super(id, path, namespace, messages, bulk); + + // Listeners + this.add_listener = undefined; + this.confirm_listener = undefined; + + // Form elements (built based on the initial id) + this.html_button = document.getElementById(id); + this.html_input = document.getElementById(`${id}-set`); + this.html_no_confim = document.getElementById(`${id}-no-confirm`); + + // Card elements + this.html_card = document.getElementById(`${id}-card`); + this.html_card_set = document.getElementById(`${id}-card-set`); + this.html_card_name = document.getElementById(`${id}-card-name`); + this.html_card_image_container = document.getElementById(`${id}-card-image-container`); + this.html_card_image = document.getElementById(`${id}-card-image`); + this.html_card_footer = document.getElementById(`${id}-card-footer`); + this.html_card_confirm = document.getElementById(`${id}-card-confirm`); + this.html_card_dismiss = document.getElementById(`${id}-card-dismiss`); + + if (this.html_button) { + this.add_listener = ((bricksocket) => (e) => { + if (!bricksocket.disabled && bricksocket.socket !== undefined && bricksocket.socket.connected) { + bricksocket.toggle(false); + + // Split and save the list if bulk + if (bricksocket.bulk) { + bricksocket.read_set_list() + } + + if (bricksocket.bulk || (bricksocket.html_no_confim && bricksocket.html_no_confim.checked)) { + bricksocket.import_set(true); + } else { + bricksocket.load_set(); + } + } + })(this); + + this.html_button.addEventListener("click", this.add_listener); + } + + if (this.html_card_dismiss && this.html_card) { + this.html_card_dismiss.addEventListener("click", ((card) => (e) => { + card.classList.add("d-none"); + })(this.html_card)); + } + + // Setup the socket + this.setup(); + } + + // Clear form + clear() { + super.clear(); + + if (this.html_card) { + this.html_card.classList.add("d-none"); + } + + if (this.html_card_footer) { + this.html_card_footer.classList.add("d-none"); + + if (this.html_card_confirm) { + this.html_card_footer.classList.add("d-none"); + } + } + } + + // Upon receiving a complete message + complete(data) { + super.complete(data); + + if (this.bulk) { + // Import the next set + this.import_set(true, undefined, true); + } + } + + // Upon receiving a fail message + fail(data) { + super.fail(data); + + if (this.bulk && this.html_input) { + if (this.set_list_last_set !== undefined) { + this.set_list.unshift(this.set_list_last_set); + this.set_list_last_set = undefined; + } + + this.html_input.value = this.set_list.join(', '); + } + } + + // Import a set + import_set(no_confirm, set, from_complete=false) { + if (this.html_input) { + if (!this.bulk || !from_complete) { + // Reset the progress + if (no_confirm) { + this.clear(); + } else { + this.clear_status(); + } + } + + // Grab from the list if bulk + if (this.bulk) { + set = this.set_list.shift() + + // Abort if nothing left to process + if (set === undefined) { + // Clear the input + this.html_input.value = ""; + + // Settle the form + this.spinner(false); + this.toggle(true); + + return; + } + + // Save the pulled set + this.set_list_last_set = set; + } + + this.spinner(true); + + this.socket.emit(this.messages.IMPORT_SET, { + set: (set !== undefined) ? set : this.html_input.value, + }); + } else { + this.fail("Could not find the input field for the set number"); + } + } + + // Load a set + load_set() { + if (this.html_input) { + // Reset the progress + this.clear() + this.spinner(true); + + this.socket.emit(this.messages.LOAD_SET, { + set: this.html_input.value + }); + } else { + this.fail("Could not find the input field for the set number"); + } + } + + // Bulk: read the input as a list + read_set_list() { + this.set_list = []; + + if (this.html_input) { + const value = this.html_input.value; + this.set_list = value.split(",").map((el) => el.trim()) + } + } + + // Set is loaded + set_loaded(data) { + if (this.html_card) { + this.html_card.classList.remove("d-none"); + + if (this.html_card_set) { + this.html_card_set.textContent = data["set"]; + } + + if (this.html_card_name) { + this.html_card_name.textContent = data["name"]; + } + + if (this.html_card_image_container) { + this.html_card_image_container.setAttribute("style", `background-image: url(${data["image"]})`); + } + + if (this.html_card_image) { + this.html_card_image.setAttribute("src", data["image"]); + this.html_card_image.setAttribute("alt", data["set"]); + } + + if (this.html_card_footer) { + this.html_card_footer.classList.add("d-none"); + + if (!data.download) { + this.html_card_footer.classList.remove("d-none"); + + if (this.html_card_confirm) { + if (this.confirm_listener !== undefined) { + this.html_card_confirm.removeEventListener("click", this.confirm_listener); + } + + this.confirm_listener = ((bricksocket, set) => (e) => { + if (!bricksocket.disabled) { + bricksocket.toggle(false); + bricksocket.import_set(false, set); + } + })(this, data["set"]); + + this.html_card_confirm.addEventListener("click", this.confirm_listener); + } + } + } + } + } + + // Setup the actual socket + setup() { + super.setup(); + + if (this.socket !== undefined) { + // Set loaded + this.socket.on(this.messages.SET_LOADED, ((bricksocket) => (data) => { + bricksocket.set_loaded(data); + })(this)); + } + } + + + // Toggle clicking on the button, or sending events + toggle(enabled) { + super.toggle(enabled); + + if (this.html_button) { + this.html_button.disabled = !enabled; + } + + if (this.html_input) { + this.html_input.disabled = !enabled; + } + + if (this.html_card_confirm) { + this.html_card_confirm.disabled = !enabled; + } + + if (this.html_card_dismiss) { + this.html_card_dismiss.disabled = !enabled; + } + } +} diff --git a/static/scripts/socket.js b/static/scripts/socket/socket.js similarity index 54% rename from static/scripts/socket.js rename to static/scripts/socket/socket.js index 5a24d06..1a34056 100644 --- a/static/scripts/socket.js +++ b/static/scripts/socket/socket.js @@ -5,22 +5,17 @@ class BrickSocket { this.path = path; this.namespace = namespace; this.messages = messages; - this.bulk = bulk; this.disabled = false; this.socket = undefined; - // Listeners - this.add_listener = undefined; - this.confirm_listener = undefined; + // Bulk mode + this.bulk = bulk; // Form elements (built based on the initial id) - this.html_button = document.getElementById(id); this.html_complete = document.getElementById(`${id}-complete`); this.html_count = document.getElementById(`${id}-count`); this.html_fail = document.getElementById(`${id}-fail`); - this.html_input = document.getElementById(`${id}-set`); - this.html_no_confim = document.getElementById(`${id}-no-confirm`); this.html_progress = document.getElementById(`${id}-progress`); this.html_progress_bar = document.getElementById(`${id}-progress-bar`); this.html_progress_message = document.getElementById(`${id}-progress-message`); @@ -28,50 +23,10 @@ class BrickSocket { this.html_status = document.getElementById(`${id}-status`); this.html_status_icon = document.getElementById(`${id}-status-icon`); - // Card elements - this.html_card = document.getElementById(`${id}-card`); - this.html_card_set = document.getElementById(`${id}-card-set`); - this.html_card_name = document.getElementById(`${id}-card-name`); - this.html_card_image_container = document.getElementById(`${id}-card-image-container`); - this.html_card_image = document.getElementById(`${id}-card-image`); - this.html_card_footer = document.getElementById(`${id}-card-footer`); - this.html_card_confirm = document.getElementById(`${id}-card-confirm`); - this.html_card_dismiss = document.getElementById(`${id}-card-dismiss`); - - if (this.html_button) { - this.add_listener = ((bricksocket) => (e) => { - if (!bricksocket.disabled && bricksocket.socket !== undefined && bricksocket.socket.connected) { - bricksocket.toggle(false); - - // Split and save the list if bulk - if (bricksocket.bulk) { - bricksocket.read_set_list() - } - - if (bricksocket.bulk || (bricksocket.html_no_confim && bricksocket.html_no_confim.checked)) { - bricksocket.import_set(true); - } else { - bricksocket.load_set(); - } - } - })(this); - - this.html_button.addEventListener("click", this.add_listener); - } - - if (this.html_card_dismiss && this.html_card) { - this.html_card_dismiss.addEventListener("click", ((card) => (e) => { - card.classList.add("d-none"); - })(this.html_card)); - } - // Socket status window.setInterval(((bricksocket) => () => { bricksocket.status(); })(this), 500); - - // Setup the socket - this.setup(); } // Clear form @@ -89,18 +44,6 @@ class BrickSocket { } this.spinner(false); - - if (this.html_card) { - this.html_card.classList.add("d-none"); - } - - if (this.html_card_footer) { - this.html_card_footer.classList.add("d-none"); - - if (this.html_card_confirm) { - this.html_card_footer.classList.add("d-none"); - } - } } // Clear status message @@ -141,9 +84,6 @@ class BrickSocket { this.html_complete.append(success) } - - // Import the next set - this.import_set(true, undefined, true); } else { this.spinner(false); @@ -188,73 +128,8 @@ class BrickSocket { if (this.html_progress_bar) { this.html_progress_bar.classList.remove("progress-bar-animated"); } - - if (this.bulk && this.html_input) { - if (this.set_list_last_set !== undefined) { - this.set_list.unshift(this.set_list_last_set); - this.set_list_last_set = undefined; - } - - this.html_input.value = this.set_list.join(', '); - } } - // Import a set - import_set(no_confirm, set, from_complete=false) { - if (this.html_input) { - if (!this.bulk || !from_complete) { - // Reset the progress - if (no_confirm) { - this.clear(); - } else { - this.clear_status(); - } - } - - // Grab from the list if bulk - if (this.bulk) { - set = this.set_list.shift() - - // Abort if nothing left to process - if (set === undefined) { - // Clear the input - this.html_input.value = ""; - - // Settle the form - this.spinner(false); - this.toggle(true); - - return; - } - - // Save the pulled set - this.set_list_last_set = set; - } - - this.spinner(true); - - this.socket.emit(this.messages.IMPORT_SET, { - set: (set !== undefined) ? set : this.html_input.value, - }); - } else { - this.fail("Could not find the input field for the set number"); - } - } - - // Load a set - load_set() { - if (this.html_input) { - // Reset the progress - this.clear() - this.spinner(true); - - this.socket.emit(this.messages.LOAD_SET, { - set: this.html_input.value - }); - } else { - this.fail("Could not find the input field for the set number"); - } - } // Update the progress progress(data={}) { @@ -304,63 +179,6 @@ class BrickSocket { } } - // Bulk: read the input as a list - read_set_list() { - this.set_list = []; - - if (this.html_input) { - const value = this.html_input.value; - this.set_list = value.split(",").map((el) => el.trim()) - } - } - - // Set is loaded - set_loaded(data) { - if (this.html_card) { - this.html_card.classList.remove("d-none"); - - if (this.html_card_set) { - this.html_card_set.textContent = data["set"]; - } - - if (this.html_card_name) { - this.html_card_name.textContent = data["name"]; - } - - if (this.html_card_image_container) { - this.html_card_image_container.setAttribute("style", `background-image: url(${data["image"]})`); - } - - if (this.html_card_image) { - this.html_card_image.setAttribute("src", data["image"]); - this.html_card_image.setAttribute("alt", data["set"]); - } - - if (this.html_card_footer) { - this.html_card_footer.classList.add("d-none"); - - if (!data.download) { - this.html_card_footer.classList.remove("d-none"); - - if (this.html_card_confirm) { - if (this.confirm_listener !== undefined) { - this.html_card_confirm.removeEventListener("click", this.confirm_listener); - } - - this.confirm_listener = ((bricksocket, set) => (e) => { - if (!bricksocket.disabled) { - bricksocket.toggle(false); - bricksocket.import_set(false, set); - } - })(this, data["set"]); - - this.html_card_confirm.addEventListener("click", this.confirm_listener); - } - } - } - } - } - // Setup the actual socket setup() { if (this.socket === undefined) { @@ -387,11 +205,6 @@ class BrickSocket { this.socket.on(this.messages.PROGRESS, ((bricksocket) => (data) => { bricksocket.progress(data); })(this)); - - // Set loaded - this.socket.on(this.messages.SET_LOADED, ((bricksocket) => (data) => { - bricksocket.set_loaded(data); - })(this)); } } @@ -434,21 +247,5 @@ class BrickSocket { // Toggle clicking on the button, or sending events toggle(enabled) { this.disabled = !enabled; - - if (this.html_button) { - this.html_button.disabled = !enabled; - } - - if (this.html_input) { - this.html_input.disabled = !enabled; - } - - if (this.html_card_confirm) { - this.html_card_confirm.disabled = !enabled; - } - - if (this.html_card_dismiss) { - this.html_card_dismiss.disabled = !enabled; - } } } diff --git a/templates/base.html b/templates/base.html index 1132f2b..12c4afa 100644 --- a/templates/base.html +++ b/templates/base.html @@ -82,7 +82,8 @@ - + + + -- 2.45.2 From 9b5774555f6abed4033722c400ddd261e9dbe58e Mon Sep 17 00:00:00 2001 From: Gregoo Date: Sat, 25 Jan 2025 22:43:35 +0100 Subject: [PATCH 3/8] Increase the socket status polling interval to 1s --- static/scripts/socket/socket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/scripts/socket/socket.js b/static/scripts/socket/socket.js index 1a34056..30364ad 100644 --- a/static/scripts/socket/socket.js +++ b/static/scripts/socket/socket.js @@ -26,7 +26,7 @@ class BrickSocket { // Socket status window.setInterval(((bricksocket) => () => { bricksocket.status(); - })(this), 500); + })(this), 1000); } // Clear form -- 2.45.2 From cf9e716d1cd660d6a38bf672d1dafe34754cd36b Mon Sep 17 00:00:00 2001 From: Gregoo Date: Sat, 25 Jan 2025 22:43:54 +0100 Subject: [PATCH 4/8] Remove unused 'ADD_SET' socket message --- bricktracker/socket.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bricktracker/socket.py b/bricktracker/socket.py index 1db6947..c7215ae 100644 --- a/bricktracker/socket.py +++ b/bricktracker/socket.py @@ -15,7 +15,6 @@ logger = logging.getLogger(__name__) # Messages valid through the socket MESSAGES: Final[dict[str, str]] = { - 'ADD_SET': 'add_set', 'COMPLETE': 'complete', 'CONNECT': 'connect', 'DISCONNECT': 'disconnect', -- 2.45.2 From 48ad7b5f02db8007434d06d75608e441f9098208 Mon Sep 17 00:00:00 2001 From: Gregoo Date: Sat, 25 Jan 2025 22:48:10 +0100 Subject: [PATCH 5/8] Trim the url in the progress message to make it more legible --- bricktracker/instructions.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bricktracker/instructions.py b/bricktracker/instructions.py index 5f91836..cc5cee7 100644 --- a/bricktracker/instructions.py +++ b/bricktracker/instructions.py @@ -111,11 +111,14 @@ class BrickInstructions(object): url = current_app.config['REBRICKABLE_LINK_INSTRUCTIONS_PATTERN'].format( # noqa: E501 path=path ) + trimmed_url = current_app.config['REBRICKABLE_LINK_INSTRUCTIONS_PATTERN'].format( # noqa: E501 + path=path.partition('/')[0] + ) # Request the file self.socket.progress( message='Requesting {url}'.format( - url=url, + url=trimmed_url, ) ) @@ -133,7 +136,7 @@ class BrickInstructions(object): # Downloading the file self.socket.progress( message='Downloading {url} ({size})'.format( - url=url, + url=trimmed_url, size=self.human_size(), ) ) -- 2.45.2 From acebf6efd69c61c09f912dc1f5c30b9d68548f85 Mon Sep 17 00:00:00 2001 From: Gregoo Date: Sat, 25 Jan 2025 23:05:21 +0100 Subject: [PATCH 6/8] Clear the progress message when clear() --- static/scripts/socket/socket.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/static/scripts/socket/socket.js b/static/scripts/socket/socket.js index 30364ad..2e213db 100644 --- a/static/scripts/socket/socket.js +++ b/static/scripts/socket/socket.js @@ -43,6 +43,8 @@ class BrickSocket { this.html_progress_bar.textContent = ""; } + this.progress_message(""); + this.spinner(false); } -- 2.45.2 From 19750d13657e7a8b261f66dd09fb092f0ad93094 Mon Sep 17 00:00:00 2001 From: Gregoo Date: Sat, 25 Jan 2025 23:05:39 +0100 Subject: [PATCH 7/8] Fix a bug when normalizing total in progress() --- static/scripts/socket/socket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/scripts/socket/socket.js b/static/scripts/socket/socket.js index 2e213db..cb08889 100644 --- a/static/scripts/socket/socket.js +++ b/static/scripts/socket/socket.js @@ -139,7 +139,7 @@ class BrickSocket { let count = data["count"] // Fix the total if bogus - if (!total || isNaN(total) || total <= 1) { + if (!total || isNaN(total) || total <= 0) { total = 0; } -- 2.45.2 From 2db0c1c2eb8c4984e4757449058f7c948e2b735b Mon Sep 17 00:00:00 2001 From: Gregoo Date: Sat, 25 Jan 2025 23:06:00 +0100 Subject: [PATCH 8/8] Clear the socket when clicking the button --- static/scripts/socket/instructions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/scripts/socket/instructions.js b/static/scripts/socket/instructions.js index 6a1fdc2..271c0c3 100644 --- a/static/scripts/socket/instructions.js +++ b/static/scripts/socket/instructions.js @@ -64,7 +64,7 @@ class BrickInstructionsSocket extends BrickSocket { if (!from_complete) { this.total = this.get_files(true).length; this.current = 0; - this.clear_status(); + this.clear(); } // Find the next checkbox -- 2.45.2