feat(roles): add admin store roles page, permission i18n, and menu integration
Some checks failed
CI / ruff (push) Successful in 9s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has started running

- Add admin store roles page with merchant→store cascading for superadmin
  and store-only selection for platform admin
- Add permission catalog API with translated labels/descriptions (en/fr/de/lb)
- Add permission translations to all 15 module locale files (60 files total)
- Add info icon tooltips for permission descriptions in role editor
- Add store roles menu item and admin menu item in module definition
- Fix store-selector.js URL construction bug when apiEndpoint has query params
- Add admin store roles API (CRUD + platform scoping)
- Add integration tests for admin store roles and permission catalog

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 23:31:27 +01:00
parent 2b55e7458b
commit f95db7c0b1
83 changed files with 3491 additions and 513 deletions

View File

@@ -1,87 +1,95 @@
{
"menu": {
"marketplace": "Marktplatz",
"letzshop": "Letzshop",
"products_inventory": "Produkte & Inventar",
"marketplace_import": "Marktplatz Import",
"sales_orders": "Verkäufe & Bestellungen",
"letzshop_orders": "Letzshop Bestellungen"
},
"marketplace": {
"title": "Marktplatz",
"import": "Importieren",
"export": "Exportieren",
"sync": "Synchronisieren",
"source": "Quelle",
"source_url": "Quell-URL",
"import_products": "Produkte importieren",
"start_import": "Import starten",
"importing": "Importiere...",
"import_complete": "Import abgeschlossen",
"import_failed": "Import fehlgeschlagen",
"import_history": "Import-Verlauf",
"job_id": "Auftrags-ID",
"started_at": "Gestartet um",
"completed_at": "Abgeschlossen um",
"duration": "Dauer",
"imported_count": "Importiert",
"error_count": "Fehler",
"total_processed": "Gesamt verarbeitet",
"progress": "Fortschritt",
"no_import_jobs": "Noch keine Imports",
"start_first_import": "Starten Sie Ihren ersten Import mit dem Formular oben"
},
"letzshop": {
"title": "Letzshop-Integration",
"connection": "Verbindung",
"credentials": "Zugangsdaten",
"api_key": "API-Schlüssel",
"api_endpoint": "API-Endpunkt",
"auto_sync": "Auto-Sync",
"sync_interval": "Sync-Intervall",
"every_hour": "Jede Stunde",
"every_day": "Jeden Tag",
"test_connection": "Verbindung testen",
"save_credentials": "Zugangsdaten speichern",
"connection_success": "Verbindung erfolgreich",
"connection_failed": "Verbindung fehlgeschlagen",
"last_sync": "Letzte Synchronisation",
"sync_status": "Sync-Status",
"import_orders": "Bestellungen importieren",
"export_products": "Produkte exportieren",
"no_credentials": "Konfigurieren Sie Ihren API-Schlüssel in den Einstellungen",
"carriers": {
"dhl": "DHL",
"ups": "UPS",
"fedex": "FedEx",
"dpd": "DPD",
"gls": "GLS",
"post_luxembourg": "Post Luxemburg",
"other": "Andere"
"menu": {
"marketplace": "Marktplatz",
"letzshop": "Letzshop",
"products_inventory": "Produkte & Inventar",
"marketplace_import": "Marktplatz Import",
"sales_orders": "Verkäufe & Bestellungen",
"letzshop_orders": "Letzshop Bestellungen"
},
"marketplace": {
"title": "Marktplatz",
"import": "Importieren",
"export": "Exportieren",
"sync": "Synchronisieren",
"source": "Quelle",
"source_url": "Quell-URL",
"import_products": "Produkte importieren",
"start_import": "Import starten",
"importing": "Importiere...",
"import_complete": "Import abgeschlossen",
"import_failed": "Import fehlgeschlagen",
"import_history": "Import-Verlauf",
"job_id": "Auftrags-ID",
"started_at": "Gestartet um",
"completed_at": "Abgeschlossen um",
"duration": "Dauer",
"imported_count": "Importiert",
"error_count": "Fehler",
"total_processed": "Gesamt verarbeitet",
"progress": "Fortschritt",
"no_import_jobs": "Noch keine Imports",
"start_first_import": "Starten Sie Ihren ersten Import mit dem Formular oben"
},
"letzshop": {
"title": "Letzshop-Integration",
"connection": "Verbindung",
"credentials": "Zugangsdaten",
"api_key": "API-Schlüssel",
"api_endpoint": "API-Endpunkt",
"auto_sync": "Auto-Sync",
"sync_interval": "Sync-Intervall",
"every_hour": "Jede Stunde",
"every_day": "Jeden Tag",
"test_connection": "Verbindung testen",
"save_credentials": "Zugangsdaten speichern",
"connection_success": "Verbindung erfolgreich",
"connection_failed": "Verbindung fehlgeschlagen",
"last_sync": "Letzte Synchronisation",
"sync_status": "Sync-Status",
"import_orders": "Bestellungen importieren",
"export_products": "Produkte exportieren",
"no_credentials": "Konfigurieren Sie Ihren API-Schlüssel in den Einstellungen",
"carriers": {
"dhl": "DHL",
"ups": "UPS",
"fedex": "FedEx",
"dpd": "DPD",
"gls": "GLS",
"post_luxembourg": "Post Luxemburg",
"other": "Andere"
}
},
"messages": {
"no_error_details_available": "No error details available",
"failed_to_load_error_details": "Failed to load error details",
"copied_to_clipboard": "Copied to clipboard",
"failed_to_copy_to_clipboard": "Failed to copy to clipboard"
},
"features": {
"letzshop_sync": {
"name": "Lëtzshop-Synchronisation",
"description": "Produkte mit dem Lëtzshop-Marktplatz synchronisieren"
},
"api_access": {
"name": "API-Zugang",
"description": "Zugang zur Plattform-API"
},
"webhooks": {
"name": "Webhooks",
"description": "Echtzeit-Ereignisbenachrichtigungen über Webhooks"
},
"custom_integrations": {
"name": "Eigene Integrationen",
"description": "Eigene Integrationen mit der Plattform erstellen"
}
},
"permissions": {
"view_integration": "Integration anzeigen",
"view_integration_desc": "Marktplatz-Integrationseinstellungen anzeigen",
"manage_integration": "Integration verwalten",
"manage_integration_desc": "Marktplatz-Integration konfigurieren",
"sync_products": "Produkte synchronisieren",
"sync_products_desc": "Produkte mit dem Marktplatz synchronisieren"
}
},
"messages": {
"no_error_details_available": "No error details available",
"failed_to_load_error_details": "Failed to load error details",
"copied_to_clipboard": "Copied to clipboard",
"failed_to_copy_to_clipboard": "Failed to copy to clipboard"
},
"features": {
"letzshop_sync": {
"name": "Lëtzshop-Synchronisation",
"description": "Produkte mit dem Lëtzshop-Marktplatz synchronisieren"
},
"api_access": {
"name": "API-Zugang",
"description": "Zugang zur Plattform-API"
},
"webhooks": {
"name": "Webhooks",
"description": "Echtzeit-Ereignisbenachrichtigungen über Webhooks"
},
"custom_integrations": {
"name": "Eigene Integrationen",
"description": "Eigene Integrationen mit der Plattform erstellen"
}
}
}

View File

@@ -7,6 +7,14 @@
"sales_orders": "Sales & Orders",
"letzshop_orders": "Letzshop Orders"
},
"permissions": {
"view_integration": "View Integration",
"view_integration_desc": "View marketplace integration settings",
"manage_integration": "Manage Integration",
"manage_integration_desc": "Configure marketplace integration",
"sync_products": "Sync Products",
"sync_products_desc": "Synchronize products with marketplace"
},
"marketplace": {
"title": "Marketplace",
"import": "Import",

View File

@@ -1,87 +1,95 @@
{
"menu": {
"marketplace": "Marketplace",
"letzshop": "Letzshop",
"products_inventory": "Produits et Inventaire",
"marketplace_import": "Import Marketplace",
"sales_orders": "Ventes et Commandes",
"letzshop_orders": "Commandes Letzshop"
},
"marketplace": {
"title": "Marketplace",
"import": "Importer",
"export": "Exporter",
"sync": "Synchroniser",
"source": "Source",
"source_url": "URL source",
"import_products": "Importer des produits",
"start_import": "Démarrer l'importation",
"importing": "Importation en cours...",
"import_complete": "Importation terminée",
"import_failed": "Échec de l'importation",
"import_history": "Historique des importations",
"job_id": "ID du travail",
"started_at": "Démarré à",
"completed_at": "Terminé à",
"duration": "Durée",
"imported_count": "Importés",
"error_count": "Erreurs",
"total_processed": "Total traité",
"progress": "Progression",
"no_import_jobs": "Aucune importation pour le moment",
"start_first_import": "Lancez votre première importation avec le formulaire ci-dessus"
},
"letzshop": {
"title": "Intégration Letzshop",
"connection": "Connexion",
"credentials": "Identifiants",
"api_key": "Clé API",
"api_endpoint": "Point d'accès API",
"auto_sync": "Synchronisation automatique",
"sync_interval": "Intervalle de synchronisation",
"every_hour": "Toutes les heures",
"every_day": "Tous les jours",
"test_connection": "Tester la connexion",
"save_credentials": "Enregistrer les identifiants",
"connection_success": "Connexion réussie",
"connection_failed": "Échec de la connexion",
"last_sync": "Dernière synchronisation",
"sync_status": "Statut de synchronisation",
"import_orders": "Importer les commandes",
"export_products": "Exporter les produits",
"no_credentials": "Configurez votre clé API dans les paramètres pour commencer",
"carriers": {
"dhl": "DHL",
"ups": "UPS",
"fedex": "FedEx",
"dpd": "DPD",
"gls": "GLS",
"post_luxembourg": "Post Luxembourg",
"other": "Autre"
"menu": {
"marketplace": "Marketplace",
"letzshop": "Letzshop",
"products_inventory": "Produits et Inventaire",
"marketplace_import": "Import Marketplace",
"sales_orders": "Ventes et Commandes",
"letzshop_orders": "Commandes Letzshop"
},
"marketplace": {
"title": "Marketplace",
"import": "Importer",
"export": "Exporter",
"sync": "Synchroniser",
"source": "Source",
"source_url": "URL source",
"import_products": "Importer des produits",
"start_import": "Démarrer l'importation",
"importing": "Importation en cours...",
"import_complete": "Importation terminée",
"import_failed": "Échec de l'importation",
"import_history": "Historique des importations",
"job_id": "ID du travail",
"started_at": "Démarré à",
"completed_at": "Terminé à",
"duration": "Durée",
"imported_count": "Importés",
"error_count": "Erreurs",
"total_processed": "Total traité",
"progress": "Progression",
"no_import_jobs": "Aucune importation pour le moment",
"start_first_import": "Lancez votre première importation avec le formulaire ci-dessus"
},
"letzshop": {
"title": "Intégration Letzshop",
"connection": "Connexion",
"credentials": "Identifiants",
"api_key": "Clé API",
"api_endpoint": "Point d'accès API",
"auto_sync": "Synchronisation automatique",
"sync_interval": "Intervalle de synchronisation",
"every_hour": "Toutes les heures",
"every_day": "Tous les jours",
"test_connection": "Tester la connexion",
"save_credentials": "Enregistrer les identifiants",
"connection_success": "Connexion réussie",
"connection_failed": "Échec de la connexion",
"last_sync": "Dernière synchronisation",
"sync_status": "Statut de synchronisation",
"import_orders": "Importer les commandes",
"export_products": "Exporter les produits",
"no_credentials": "Configurez votre clé API dans les paramètres pour commencer",
"carriers": {
"dhl": "DHL",
"ups": "UPS",
"fedex": "FedEx",
"dpd": "DPD",
"gls": "GLS",
"post_luxembourg": "Post Luxembourg",
"other": "Autre"
}
},
"messages": {
"no_error_details_available": "No error details available",
"failed_to_load_error_details": "Failed to load error details",
"copied_to_clipboard": "Copied to clipboard",
"failed_to_copy_to_clipboard": "Failed to copy to clipboard"
},
"features": {
"letzshop_sync": {
"name": "Synchronisation Lëtzshop",
"description": "Synchroniser les produits avec la marketplace Lëtzshop"
},
"api_access": {
"name": "Accès API",
"description": "Accès à l'API de la plateforme"
},
"webhooks": {
"name": "Webhooks",
"description": "Notifications d'événements en temps réel via webhooks"
},
"custom_integrations": {
"name": "Intégrations personnalisées",
"description": "Créer des intégrations personnalisées avec la plateforme"
}
},
"permissions": {
"view_integration": "Voir l'intégration",
"view_integration_desc": "Voir les paramètres d'intégration marketplace",
"manage_integration": "Gérer l'intégration",
"manage_integration_desc": "Configurer l'intégration marketplace",
"sync_products": "Synchroniser les produits",
"sync_products_desc": "Synchroniser les produits avec le marketplace"
}
},
"messages": {
"no_error_details_available": "No error details available",
"failed_to_load_error_details": "Failed to load error details",
"copied_to_clipboard": "Copied to clipboard",
"failed_to_copy_to_clipboard": "Failed to copy to clipboard"
},
"features": {
"letzshop_sync": {
"name": "Synchronisation Lëtzshop",
"description": "Synchroniser les produits avec la marketplace Lëtzshop"
},
"api_access": {
"name": "Accès API",
"description": "Accès à l'API de la plateforme"
},
"webhooks": {
"name": "Webhooks",
"description": "Notifications d'événements en temps réel via webhooks"
},
"custom_integrations": {
"name": "Intégrations personnalisées",
"description": "Créer des intégrations personnalisées avec la plateforme"
}
}
}

View File

@@ -1,87 +1,95 @@
{
"menu": {
"marketplace": "Marchéplaz",
"letzshop": "Letzshop",
"products_inventory": "Produkter & Inventar",
"marketplace_import": "Marchéplaz Import",
"sales_orders": "Verkaf & Bestellungen",
"letzshop_orders": "Letzshop Bestellungen"
},
"marketplace": {
"title": "Marchéplaz",
"import": "Import",
"export": "Export",
"sync": "Synchroniséieren",
"source": "Quell",
"source_url": "Quell URL",
"import_products": "Produkter importéieren",
"start_import": "Import starten",
"importing": "Importéieren...",
"import_complete": "Import fäerdeg",
"import_failed": "Import feelgeschloen",
"import_history": "Importgeschicht",
"job_id": "Job ID",
"started_at": "Ugefaang um",
"completed_at": "Fäerdeg um",
"duration": "Dauer",
"imported_count": "Importéiert",
"error_count": "Feeler",
"total_processed": "Total veraarbecht",
"progress": "Fortschrëtt",
"no_import_jobs": "Nach keng Import Jobs",
"start_first_import": "Start Ären éischten Import mat der Form uewendriwwer"
},
"letzshop": {
"title": "Letzshop Integratioun",
"connection": "Verbindung",
"credentials": "Umeldungsdaten",
"api_key": "API Schlëssel",
"api_endpoint": "API Endpunkt",
"auto_sync": "Automatesch Sync",
"sync_interval": "Sync Intervall",
"every_hour": "All Stonn",
"every_day": "All Dag",
"test_connection": "Verbindung testen",
"save_credentials": "Umeldungsdaten späicheren",
"connection_success": "Verbindung erfollegräich",
"connection_failed": "Verbindung feelgeschloen",
"last_sync": "Läschte Sync",
"sync_status": "Sync Status",
"import_orders": "Bestellungen importéieren",
"export_products": "Produkter exportéieren",
"no_credentials": "Konfiguréiert Ären API Schlëssel an den Astellungen fir unzefänken",
"carriers": {
"dhl": "DHL",
"ups": "UPS",
"fedex": "FedEx",
"dpd": "DPD",
"gls": "GLS",
"post_luxembourg": "Post Lëtzebuerg",
"other": "Anerer"
"menu": {
"marketplace": "Marchéplaz",
"letzshop": "Letzshop",
"products_inventory": "Produkter & Inventar",
"marketplace_import": "Marchéplaz Import",
"sales_orders": "Verkaf & Bestellungen",
"letzshop_orders": "Letzshop Bestellungen"
},
"marketplace": {
"title": "Marchéplaz",
"import": "Import",
"export": "Export",
"sync": "Synchroniséieren",
"source": "Quell",
"source_url": "Quell URL",
"import_products": "Produkter importéieren",
"start_import": "Import starten",
"importing": "Importéieren...",
"import_complete": "Import fäerdeg",
"import_failed": "Import feelgeschloen",
"import_history": "Importgeschicht",
"job_id": "Job ID",
"started_at": "Ugefaang um",
"completed_at": "Fäerdeg um",
"duration": "Dauer",
"imported_count": "Importéiert",
"error_count": "Feeler",
"total_processed": "Total veraarbecht",
"progress": "Fortschrëtt",
"no_import_jobs": "Nach keng Import Jobs",
"start_first_import": "Start Ären éischten Import mat der Form uewendriwwer"
},
"letzshop": {
"title": "Letzshop Integratioun",
"connection": "Verbindung",
"credentials": "Umeldungsdaten",
"api_key": "API Schlëssel",
"api_endpoint": "API Endpunkt",
"auto_sync": "Automatesch Sync",
"sync_interval": "Sync Intervall",
"every_hour": "All Stonn",
"every_day": "All Dag",
"test_connection": "Verbindung testen",
"save_credentials": "Umeldungsdaten späicheren",
"connection_success": "Verbindung erfollegräich",
"connection_failed": "Verbindung feelgeschloen",
"last_sync": "Läschte Sync",
"sync_status": "Sync Status",
"import_orders": "Bestellungen importéieren",
"export_products": "Produkter exportéieren",
"no_credentials": "Konfiguréiert Ären API Schlëssel an den Astellungen fir unzefänken",
"carriers": {
"dhl": "DHL",
"ups": "UPS",
"fedex": "FedEx",
"dpd": "DPD",
"gls": "GLS",
"post_luxembourg": "Post Lëtzebuerg",
"other": "Anerer"
}
},
"messages": {
"no_error_details_available": "No error details available",
"failed_to_load_error_details": "Failed to load error details",
"copied_to_clipboard": "Copied to clipboard",
"failed_to_copy_to_clipboard": "Failed to copy to clipboard"
},
"features": {
"letzshop_sync": {
"name": "Lëtzshop-Synchronisatioun",
"description": "Produkter mam Lëtzshop-Marktplaz synchroniséieren"
},
"api_access": {
"name": "API-Zougang",
"description": "Zougang zur Plattform-API"
},
"webhooks": {
"name": "Webhooks",
"description": "Echtzäit-Evenement-Benoriichtegungen iwwer Webhooks"
},
"custom_integrations": {
"name": "Eegen Integratiounen",
"description": "Eegen Integratiounen mat der Plattform erstellen"
}
},
"permissions": {
"view_integration": "Integratioun kucken",
"view_integration_desc": "Marché-Integratiounsastellungen kucken",
"manage_integration": "Integratioun verwalten",
"manage_integration_desc": "Marché-Integratioun konfiguréieren",
"sync_products": "Produiten synchroniséieren",
"sync_products_desc": "Produiten mam Marché synchroniséieren"
}
},
"messages": {
"no_error_details_available": "No error details available",
"failed_to_load_error_details": "Failed to load error details",
"copied_to_clipboard": "Copied to clipboard",
"failed_to_copy_to_clipboard": "Failed to copy to clipboard"
},
"features": {
"letzshop_sync": {
"name": "Lëtzshop-Synchronisatioun",
"description": "Produkter mam Lëtzshop-Marktplaz synchroniséieren"
},
"api_access": {
"name": "API-Zougang",
"description": "Zougang zur Plattform-API"
},
"webhooks": {
"name": "Webhooks",
"description": "Echtzäit-Evenement-Benoriichtegungen iwwer Webhooks"
},
"custom_integrations": {
"name": "Eegen Integratiounen",
"description": "Eegen Integratiounen mat der Plattform erstellen"
}
}
}