From 78511a1321f0b12de4cd5d016553944634fbfc8a Mon Sep 17 00:00:00 2001 From: Kouji Takao Date: Thu, 1 Jan 2026 22:37:38 +0900 Subject: [PATCH 1/5] feat: display expiry time in meshV2 connected message - Added formatExpiresAt method to Scratch3MeshV2Blocks - Updated connectedMessage to include EXPIRES_AT placeholder - Helps users know when their mesh connection will expire Co-Authored-By: Gemini --- src/extensions/scratch3_mesh_v2/index.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/extensions/scratch3_mesh_v2/index.js b/src/extensions/scratch3_mesh_v2/index.js index 6d6d5494b3..fc8fe891b5 100644 --- a/src/extensions/scratch3_mesh_v2/index.js +++ b/src/extensions/scratch3_mesh_v2/index.js @@ -299,25 +299,38 @@ class Scratch3MeshV2Blocks { return !!(this.meshService && this.meshService.groupId); } + formatExpiresAt (expiresAt) { + if (!expiresAt) return ''; + const date = new Date(expiresAt); + const h = String(date.getHours()).padStart(2, '0'); + const m = String(date.getMinutes()).padStart(2, '0'); + return `${h}:${m}`; + } + /* istanbul ignore next */ connectedMessage () { if (this.meshService && this.meshService.groupId) { const meshIdLabel = this.makeMeshIdLabel(this.meshService.groupName); + const expiresAt = this.formatExpiresAt(this.meshService.expiresAt); if (this.meshService.isHost) { return formatMessage({ id: 'mesh.registeredHost', - default: 'Registered Host Mesh [{ MESH_ID }]', + default: 'Registered Host Mesh [{ MESH_ID }] ({ EXPIRES_AT })', description: 'label for registered Host Mesh in connect modal for Mesh extension' }, { - MESH_ID: meshIdLabel + MESH_ID: meshIdLabel, + EXPIRES_AT: expiresAt }); } return formatMessage({ id: 'mesh.joinedMesh', - default: 'Joined Mesh [{ MESH_ID }]', + default: 'Joined Mesh [{ MESH_ID }] ({ EXPIRES_AT })', description: 'label for joined Mesh in connect modal for Mesh extension' - }, {MESH_ID: meshIdLabel}); + }, { + MESH_ID: meshIdLabel, + EXPIRES_AT: expiresAt + }); } return formatMessage({ id: 'mesh.notConnected', From f7b183d8a5002a07a3a99f9f8f111aea94a7db49 Mon Sep 17 00:00:00 2001 From: Kouji Takao Date: Thu, 1 Jan 2026 23:18:06 +0900 Subject: [PATCH 2/5] feat: add concise menuMessage for meshV2 connection status - Reverted connectedMessage to its original detailed format - Added menuMessage for concise display in the menu bar - Ensures connection modal maintains detailed status messages Co-Authored-By: Gemini --- src/extensions/scratch3_mesh_v2/index.js | 41 ++++++++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/extensions/scratch3_mesh_v2/index.js b/src/extensions/scratch3_mesh_v2/index.js index fc8fe891b5..5f02c718ad 100644 --- a/src/extensions/scratch3_mesh_v2/index.js +++ b/src/extensions/scratch3_mesh_v2/index.js @@ -311,31 +311,58 @@ class Scratch3MeshV2Blocks { connectedMessage () { if (this.meshService && this.meshService.groupId) { const meshIdLabel = this.makeMeshIdLabel(this.meshService.groupName); - const expiresAt = this.formatExpiresAt(this.meshService.expiresAt); if (this.meshService.isHost) { return formatMessage({ id: 'mesh.registeredHost', - default: 'Registered Host Mesh [{ MESH_ID }] ({ EXPIRES_AT })', + default: 'Registered Host Mesh [{ MESH_ID }]', description: 'label for registered Host Mesh in connect modal for Mesh extension' }, { - MESH_ID: meshIdLabel, - EXPIRES_AT: expiresAt + MESH_ID: meshIdLabel }); } return formatMessage({ id: 'mesh.joinedMesh', - default: 'Joined Mesh [{ MESH_ID }] ({ EXPIRES_AT })', + default: 'Joined Mesh [{ MESH_ID }]', description: 'label for joined Mesh in connect modal for Mesh extension' + }, {MESH_ID: meshIdLabel}); + } + return formatMessage({ + id: 'mesh.notConnected', + default: 'Not connected', + description: 'label for not connected in connect modal for Mesh extension' + }); + } + + /* istanbul ignore next */ + menuMessage () { + if (this.meshService && this.meshService.groupId) { + const meshIdLabel = this.makeMeshIdLabel(this.meshService.groupName); + const expiresAt = this.formatExpiresAt(this.meshService.expiresAt); + + if (this.meshService.isHost) { + return formatMessage({ + id: 'mesh.registeredHostMenu', + default: '{ MESH_ID } ({ EXPIRES_AT })', + description: 'concise label for registered Host Mesh in menu bar' + }, { + MESH_ID: meshIdLabel, + EXPIRES_AT: expiresAt + }); + } + return formatMessage({ + id: 'mesh.joinedMeshMenu', + default: '{ MESH_ID } ({ EXPIRES_AT })', + description: 'concise label for joined Mesh in menu bar' }, { MESH_ID: meshIdLabel, EXPIRES_AT: expiresAt }); } return formatMessage({ - id: 'mesh.notConnected', + id: 'mesh.notConnectedMenu', default: 'Not connected', - description: 'label for not connected in connect modal for Mesh extension' + description: 'concise label for not connected in menu bar' }); } From 5b52882b5a31b669bf6fdeb26d3d13468cabbd32 Mon Sep 17 00:00:00 2001 From: Kouji Takao Date: Thu, 1 Jan 2026 23:51:31 +0900 Subject: [PATCH 3/5] fix: add debug log to Scratch3MeshV2Blocks constructor --- src/extensions/scratch3_mesh_v2/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/extensions/scratch3_mesh_v2/index.js b/src/extensions/scratch3_mesh_v2/index.js index 5f02c718ad..14924c558a 100644 --- a/src/extensions/scratch3_mesh_v2/index.js +++ b/src/extensions/scratch3_mesh_v2/index.js @@ -77,6 +77,7 @@ class Scratch3MeshV2Blocks { } this.runtime.registerPeripheralExtension(Scratch3MeshV2Blocks.EXTENSION_ID, this); + console.log('Scratch3MeshV2Blocks: constructor finished, registered as:', Scratch3MeshV2Blocks.EXTENSION_ID); } makeMeshIdLabel (meshId) { From 139d5d47236b7fe2e814851501c9da67145691f2 Mon Sep 17 00:00:00 2001 From: Kouji Takao Date: Fri, 2 Jan 2026 11:12:49 +0900 Subject: [PATCH 4/5] chore: remove debug log from meshV2 constructor --- src/extensions/scratch3_mesh_v2/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/extensions/scratch3_mesh_v2/index.js b/src/extensions/scratch3_mesh_v2/index.js index 14924c558a..5f02c718ad 100644 --- a/src/extensions/scratch3_mesh_v2/index.js +++ b/src/extensions/scratch3_mesh_v2/index.js @@ -77,7 +77,6 @@ class Scratch3MeshV2Blocks { } this.runtime.registerPeripheralExtension(Scratch3MeshV2Blocks.EXTENSION_ID, this); - console.log('Scratch3MeshV2Blocks: constructor finished, registered as:', Scratch3MeshV2Blocks.EXTENSION_ID); } makeMeshIdLabel (meshId) { From d4e9c64668371761368f3c51dced17e72fe68db7 Mon Sep 17 00:00:00 2001 From: Kouji Takao Date: Fri, 2 Jan 2026 11:35:43 +0900 Subject: [PATCH 5/5] feat: request expiresAt field in JOIN_GROUP mutation --- src/extensions/scratch3_mesh_v2/gql-operations.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/extensions/scratch3_mesh_v2/gql-operations.js b/src/extensions/scratch3_mesh_v2/gql-operations.js index 8c82f7ec0d..6287cbe9e4 100644 --- a/src/extensions/scratch3_mesh_v2/gql-operations.js +++ b/src/extensions/scratch3_mesh_v2/gql-operations.js @@ -42,6 +42,7 @@ const JOIN_GROUP = gql` name groupId domain + expiresAt heartbeatIntervalSeconds } }