# CLAUDE.md - TakeID Browser Extension Ce fichier guide Claude Code pour le développement de l'extension TakeID. ## Objectif Extension navigateur (Chrome + Firefox) qui récupère les **IDs internes (GUIDs)** des éléments sélectionnés dans les vues SmartUI du WMS Mecalux EasyWMS, et les copie dans le presse-papier. ## Contexte SmartUI est l'interface web du WMS EasyWMS (Mecalux). Elle affiche des listes d'entités (articles, commandes, conteneurs...) dans des grilles. Quand l'utilisateur sélectionne des lignes via les checkboxes, il n'y a **aucun moyen visible** de récupérer l'ID interne (GUID) de ces éléments - il n'est pas dans le DOM. Cependant, l'investigation réseau a révélé que SmartUI charge les données via un appel XHR `POST getDataViewList` dont la réponse contient les IDs de chaque ligne. ## Architecture ### Principe 1. L'extension intercepte les réponses XHR `getDataViewList` de SmartUI 2. Elle extrait et met en cache le mapping `code -> GUID` pour chaque page 3. Quand l'utilisateur clique sur le bouton de l'extension, elle lit les lignes sélectionnées dans le DOM 4. Elle résout les GUIDs via le cache et les copie dans le presse-papier (un par ligne) ### Structure des fichiers ``` takeid-extension/ manifest.json # Manifest V3 (Chrome) compatible Firefox popup/ popup.html # UI du popup (bouton copier, liste des IDs) popup.js # Logique du popup popup.css # Styles du popup content/ content-script.js # Content script - pont entre injected.js et popup injected.js # Script injecté dans le contexte page - intercepte les XHR icons/ icon-16.png icon-32.png icon-48.png icon-128.png CLAUDE.md # Ce fichier ``` ### Flux de données ``` [Page SmartUI] | v SmartUI fait XHR POST vers getDataViewList | v injected.js intercepte la réponse (monkey-patch XMLHttpRequest) | Parse JSON -> extrait datos[].id.value et datos[].code.value | v (window.postMessage) content-script.js reçoit le mapping et le stocke en mémoire | v (quand l'utilisateur clique sur l'icône de l'extension) popup.js demande les IDs sélectionnés au content-script (chrome.tabs.sendMessage) | v content-script.js lit le DOM pour identifier les lignes cochées | Extrait le code de chaque ligne sélectionnée | Résout code -> GUID via le cache | v popup.js reçoit les GUIDs et les copie dans le presse-papier ``` ## Données techniques SmartUI ### URL Pattern Les vues SmartUI ont cette forme d'URL : ``` https:///SmartUI/smartui?viewname=|&viewtype=ViewList ``` Exemples : - `https://10.255.255.2/SmartUI/smartui?viewname=CustomApplication|ProductsVList&viewtype=ViewList` - Le host peut varier (IP interne, domaine...) ### Endpoint intercepté : getDataViewList **Requête :** POST vers une URL contenant `getDataViewList` (L'URL exacte est relative au SmartUI Hub, ex: `https:///SmartUI/smartuihubcore?...` via SignalR ou direct XHR) **Réponse JSON :** ```json { "datos": [ { "id": { "isResource": false, "keyResource": null, "value": "add2a893-5364-4c8e-8683-6a611a475ad6", "cssClass": "None", "applicationBase": null }, "code": { "url": "viewname=CustomApplication|ProductsVList&viewtype=ViewList&selectedKey=code&selectedValue=*000007713009750", "isDataObjectUrl": 1, "isResource": false, "keyResource": null, "value": "*000007713009750", "cssClass": "None", "applicationBase": null }, "description": { "value": "sous-table Halo mela 1 niv L1400 2 tiroirs double" } } ], "file": null, "count": 0 } ``` **Points clés :** - `datos` est un tableau de lignes (50 par page) - Chaque champ est un objet avec une propriété `value` - L'ID est dans `datos[i].id.value` (GUID, ex: `add2a893-5364-4c8e-8683-6a611a475ad6`) - Le code est dans `datos[i].code.value` (ex: `*000007713009750`) - Certains champs simples sont des scalaires directs (pas d'objet wrapper) - Le champ `id` n'est pas toujours un objet - il peut être un scalaire string directement ### Endpoint de métadonnées : view La réponse `view` (POST) fournit les métadonnées de la vue : ```json { "primaryKeyName": "id", "entity": { "tableName": "ProductViewV2", "pluralName": "Articles", "properties": [...] }, "viewGrid": { "viewFields": [...] }, "name": "ProductsVList", "applicationName": "CustomApplication", "title": "Articles" } ``` **Utilité :** `primaryKeyName` confirme le nom du champ PK (toujours "id" pour les vues standard). L'extension peut intercepter ce call pour connaître le `primaryKeyName` dynamiquement. ### Structure DOM de la grille SmartUI **IMPORTANT : La structure DOM exacte doit être vérifiée pendant le développement.** Indices connus : - SmartUI utilise un framework JavaScript (probablement Knockout.js ou similaire) - Les lignes sélectionnées ont des checkboxes cochées - Le compteur "Sélectionné:3" est visible en haut de la grille - Les codes sont des liens cliquables dans la première colonne de données - La grille a des colonnes : checkbox, Code, Description courte, UdM de base, Type, Profil logistique, Classification... **Stratégie de détection des lignes sélectionnées :** L'approche recommandée est d'inspecter le DOM pour trouver les lignes sélectionnées. Chercher : 1. Des `` ou `
` avec une classe comme `selected`, `checked`, `active`, `k-state-selected` 2. Des `` cochés dans la colonne de sélection 3. Des attributs `aria-selected="true"` Puis extraire le code depuis la même ligne (première colonne de lien, ou cellule avec le texte du code). **Approche alternative (plus robuste) :** Au lieu de lire le code depuis le DOM, l'extension peut utiliser l'**index de la ligne** dans la grille pour le mapper aux données du cache `getDataViewList`. L'ordre des lignes dans le DOM correspond à l'ordre des éléments dans `datos[]`. ## Compatibilité Chrome + Firefox ### Manifest V3 Le `manifest.json` doit être compatible Chrome ET Firefox : ```json { "manifest_version": 3, "name": "TakeID - WMS SmartUI ID Grabber", "version": "1.0.0", "description": "Copie les IDs internes des éléments sélectionnés dans les vues SmartUI du WMS EasyWMS", "permissions": ["activeTab", "clipboardWrite", "scripting"], "host_permissions": ["*://*/*"], "action": { "default_popup": "popup/popup.html", "default_icon": { "16": "icons/icon-16.png", "32": "icons/icon-32.png", "48": "icons/icon-48.png", "128": "icons/icon-128.png" } }, "content_scripts": [ { "matches": ["*://*/*SmartUI/*"], "js": ["content/content-script.js"], "run_at": "document_start" } ], "icons": { "16": "icons/icon-16.png", "32": "icons/icon-32.png", "48": "icons/icon-48.png", "128": "icons/icon-128.png" }, "browser_specific_settings": { "gecko": { "id": "takeid@mecalux.local", "strict_min_version": "109.0" } } } ``` ### Différences Chrome vs Firefox - **API namespace :** Utiliser `browser` (Firefox natif) avec fallback sur `chrome` (Chrome). Ajouter un polyfill en haut de chaque script : ```javascript const browser = globalThis.browser || globalThis.chrome; ``` - **Manifest V3 :** Firefox supporte MV3 depuis v109. La clé `browser_specific_settings.gecko` est requise pour Firefox. - **clipboardWrite :** Fonctionne dans les deux navigateurs via l'API `navigator.clipboard.writeText()` dans le popup (qui a un contexte sécurisé). - **Content script injection :** `world: "MAIN"` n'est pas supporté partout sur Firefox. Utiliser l'injection via `