diff --git a/frontend/help-ru.html b/frontend/help-ru.html
index 5b14eeb..b9d3243 100644
--- a/frontend/help-ru.html
+++ b/frontend/help-ru.html
@@ -498,7 +498,7 @@
Для eUICC (SGP.22/SGP.32) подвкладка «eSIM» читает чип и управляет установленными профилями через локальный интерфейс ES10 (через pySim, без обращения к SM-DP+):
- Чип — EID, EUICCInfo1/2 со всеми декодированными полями (версия профиля, SVN, прошивка, расширенные ресурсы карты — число установленных приложений и свободная энергонезависимая/энергозависимая память —, битовые списки возможностей UICC и RSP, идентификаторы CI PKI, категория, запрещённые PPR, версия PP, номер аккредитации SS, данные сертификации), настроенные адреса SM-DP+ по умолчанию / корневого DS и таблица авторизации правил (ES10b GetRat: идентификаторы PPR, разрешённые операторы, флаг согласия). Неизвестные TLV сохраняются как сырой hex. Поля сгруппированы в блоки — EID, EUICCInfo1, адреса и таблица авторизации правил слева, более крупный EUICCInfo2 в правом блоке (на узких экранах — одна колонка); короткие поля в блоке EUICCInfo2 располагаются в две колонки, длинные значения занимают всю ширину.
- - Профили — все профили с состоянием (включён/отключён), ником, оператором, именем, ICCID, ISD-P AID, классом, владельцем и типом значка — сам значок показывается в натуральную величину рядом с метаданными, а строка Icon содержит его тип и размер данных в байтах. Кнопки «Включить»/«Отключить» переключают профиль; карта обычно сначала отправляет REFRESH (виден в журнале проактивных команд) — терминальный ответ завершает переключение, после чего сессия карты переинициализируется как при equip: ICCID, сетевое состояние и все кэшированные данные перечитываются, а запрошенное состояние проверяется по перечитанному списку профилей.
+ - Профили — все профили с состоянием (включён/отключён), ником, оператором, именем, ICCID, ISD-P AID, классом, владельцем и типом значка; в заголовке карточки показываются оператор, а затем ник (или имя профиля). Сам значок показывается в натуральную величину рядом с метаданными, а строка Icon содержит его тип и размер данных в байтах. Кнопки «Включить»/«Отключить» переключают профиль; карта обычно сначала отправляет REFRESH (виден в журнале проактивных команд) — терминальный ответ завершает переключение, после чего сессия карты переинициализируется как при equip: ICCID, сетевое состояние и все кэшированные данные перечитываются, а запрошенное состояние проверяется по перечитанному списку профилей.
- Уведомления — список ожидающих уведомлений только для чтения (номер последовательности, операция, адрес, ICCID); ничего не обрабатывается и не удаляется.
Никаких загрузок профилей, обработки уведомлений и взаимодействия с SM-DP+ — используются только локальные функции ES10a/b/c. Если карта не eUICC, подвкладка сообщает об этом.
diff --git a/frontend/help.html b/frontend/help.html
index 4c67929..bceb846 100644
--- a/frontend/help.html
+++ b/frontend/help.html
@@ -498,7 +498,7 @@
For an eUICC (SGP.22/SGP.32) the eSIM pill reads the chip and manages the installed profiles through the local ES10 interface (via pySim, no SM-DP+ contact):
- Chip — EID, EUICCInfo1/2 with every field decoded (profile version, SVN, firmware, extended card resource — installed applications and free non-volatile/volatile memory —, UICC and RSP capability bit lists, CI PKI identifiers, category, forbidden profile policy rules, PP version, SS accreditation number, certification data), the configured default SM-DP+ / root DS addresses, and the rules authorisation table (ES10b GetRat: PPR IDs, allowed operators, consent flag). Unknown TLVs are preserved as raw hex. The fields are grouped into boxes — EID, EUICCInfo1, Addresses and the rules authorisation table on the left, the larger EUICCInfo2 in the right-hand box (a single column on narrow screens); short fields in the EUICCInfo2 box share two columns, long values span the full width.
- - Profiles — every profile with its state (enabled/disabled), nickname, provider, name, ICCID, ISD-P AID, class, owner and icon type — the icon image itself is shown at its natural size next to the metadata, and the Icon row carries its type and data size in bytes. Enable/Disable switches a profile; the card usually sends REFRESH first (logged in the proactive command log) — the terminal response completes the switch and the card session is then re-initialized like an equip, so the ICCID, network state and every cached card view are re-read, and the requested state is verified against the re-read profile list.
+ - Profiles — every profile with its state (enabled/disabled), nickname, provider, name, ICCID, ISD-P AID, class, owner and icon type; the card title shows the provider followed by the nickname (or the profile name). The icon image itself is shown at its natural size next to the metadata, and the Icon row carries its type and data size in bytes. Enable/Disable switches a profile; the card usually sends REFRESH first (logged in the proactive command log) — the terminal response completes the switch and the card session is then re-initialized like an equip, so the ICCID, network state and every cached card view are re-read, and the requested state is verified against the re-read profile list.
- Notifications — read-only list of pending notifications (sequence number, operation, address, ICCID); nothing is processed or removed.
No profile downloads, no notification handling and no SM-DP+ interaction — only the local ES10a/b/c functions are used. The card must be an eUICC; otherwise the pill says so.
diff --git a/frontend/index.html b/frontend/index.html
index 20287c2..d49b445 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -1732,6 +1732,14 @@ function esimRenderChip() {
el.innerHTML = html;
}
+// Profile card title: the provider first (when known), then the nickname or
+// the profile name; falls back to the ICCID.
+function esimProfileTitle(p) {
+ const label = p.nickname || p.name;
+ const title = [p.provider, label].filter(Boolean).join(' ');
+ return title || p.iccid || '?';
+}
+
function esimRenderProfiles() {
const el = document.getElementById('esim-profiles');
if (!el) return;
@@ -1742,7 +1750,7 @@ function esimRenderProfiles() {
let html = '';
for (const p of _esimProfiles) {
const enabled = p.state === 'enabled';
- const title = p.nickname || p.name || p.iccid || '?';
+ const title = esimProfileTitle(p);
html += '';
html += '
' +
'' + (enabled ? '●' : '○') + '' +
diff --git a/frontend/sw.js b/frontend/sw.js
index ae902e2..ba1eef0 100644
--- a/frontend/sw.js
+++ b/frontend/sw.js
@@ -1,4 +1,4 @@
-const CACHE = 'simple-v233';
+const CACHE = 'simple-v234';
const URLS = [
'index.html',
'help.html',
diff --git a/frontend/tests/esim.test.js b/frontend/tests/esim.test.js
index fcfee77..af9ecba 100644
--- a/frontend/tests/esim.test.js
+++ b/frontend/tests/esim.test.js
@@ -24,7 +24,8 @@ function extractFunc(src, name) {
let code = '';
for (const fn of ['esimLabel', 'esimGroupEid', 'esimFieldRows', 'esimResultText',
'esimStateLabel', 'esimOperationsText', 'esimProfileRows', 'esimIconDataUrl',
- 'esimChipSectionRows', 'esimChipValueWide', 'esimChipBox', 'esimSwitchStatus']) {
+ 'esimChipSectionRows', 'esimChipValueWide', 'esimChipBox', 'esimSwitchStatus',
+ 'esimProfileTitle']) {
code += extractFunc(html, fn) + '\n';
}
for (const c of ['ESIM_CHIP_LABELS', 'ESIM_RESULT_KEYS']) {
@@ -148,6 +149,17 @@ test('esimIconDataUrl builds a data URL for png and jpg icons', () => {
assert.strictEqual(esimIconDataUrl(null), '');
});
+test('esimProfileTitle puts the provider in front of the profile label', () => {
+ assert.strictEqual(esimProfileTitle({ provider: 'Alfa', name: '0002' }), 'Alfa 0002');
+ assert.strictEqual(esimProfileTitle({ provider: 'Alfa', nickname: 'Work', name: '0002' }),
+ 'Alfa Work');
+ assert.strictEqual(esimProfileTitle({ name: '0002' }), '0002');
+ assert.strictEqual(esimProfileTitle({ provider: 'Alfa' }), 'Alfa');
+ assert.strictEqual(esimProfileTitle({ iccid: '8970119000004002667' }),
+ '8970119000004002667');
+ assert.strictEqual(esimProfileTitle({}), '?');
+});
+
test('the profile card renders the icon image next to the rows', () => {
const fn = extractFunc(html, 'esimRenderProfiles');
assert.match(fn, /esimIconDataUrl\(p\)/);