
Привет!
Я Настя, системный аналитик, и ооочень давно ничего не писала сюда... Пора исправляться!
В этой статье хочу поделиться способом создания диаграмм последовательности, на которых пользователь может сам изменять степень детализации отображаемой информации:

Атакже рассказать историю, как я пришла к такому варианту «оживления» диаграмм последовательности.
Спойлер: на самом деле я рассказывала про эти диаграммы на Analyst Days 20, поэтому если видео‑формат вам нравится больше, то можно посмотреть тут:)
А для тех, кто не против и прочитать — погнали!
Постановка задачи
Исходная задача: задокументировать работу метода API, связанного с созданием заказа.
Когда выяснили, что этот метод внутри себя вызывает с десяток других методов (нужно проверить, что пользователь существует и активен, если при создании заказа указали промокод — проверить и его, и тому подобное), то появилось пожелание и логику этих методов также описать каким‑либо способом.
Достаточно хорошо под описываемую задачу подходит диаграмма последовательности (sequence diagram) из нотации UML.
Какие варианты создания такой диаграммы у нас есть для решения обозначенной задачи?
Отрисовать AS IS: полностью и логику основного метода, и порядок работы всех «вложенных» методов.
Однако, такая диаграмма будет очень большой. Изучать ее будет, мягко говоря, сложно. Скорее всего, к такой диаграмме обратятся пару‑тройку раз, а потом будут обходить стороной.Сделать несколько диаграмм: одна для основного метода и несколько для «вложенных» + сделать между ними навигацию для пользователя.
Вариант уже более рабочий, но, по долгу службы, я часто сталкиваюсь с тем, что, если напишешь «подробнее см. в разделе таком‑то» — очень часто к этому разделу никто не переходит. Это видно по вопросам, которые задают после прочтения.
А что если... скрывать и раскрывать части диаграммы по желанию того, кто на нее смотрит? Если кому‑то актуальна только логика основного метода — он посмотрит только ее. Если кто‑то хочет больше подробностей про вызываемые внутри методы — откроет более детальную информацию о них.
Идея, конечно, интересная, но совершенно не очевидно, как сделать ее реальностью :)
Ограничения для реализации
При воплощении идеи выше в реальность мне необходимо было учитывать следующие ограничения:
В идеале, итоговую диаграмму должно быть можно разместить в Confluence.
А он, как принято, корпоративный, за семью печатями, доступен только под VPN. Следовательно, могут быть проблемы, если надо использовать какие‑то «внешние» ресурсы.Нет варианта «написать свой backend», чтобы он работал над генерацией картинки.
Так как будет сложно обосновать необходимость развертывания этого сервиса ради пусть и очень классной, но пока что одной диаграммы.Если необходимо будет использовать какой‑то язык программирования, то я умею только в Python.
И то вопрос, что такое «умею»:)Хоть и предлагаемая идея очень интересная, но никто не готов ждать ее воплощения слишком долго.
Документация по методу нужна сейчас, а не через полгода.
Собираем решение
#1 Оживляем диаграмму
Сначала надо было придумать, как «оживить» диаграммы, то есть как изменять их вид в зависимости от чего‑то такого, на что может повлиять изучающий диаграмму.
Началось все с гугления, но запросы вида «динамические UML‑диаграммы» и их англоязычные аналоги ничего интересного не дали. Затем я попробовала описать знакомым frontend‑разработчикам, что я хочу получить. Тоже не помогло. Изучила draw.io, так как уже делала с его помощью динамические диаграммы. Тоже мимо.
Пошла на второй круг с Google. Не помню точно, каким именно запросом, но вышла на препроцессинг в PlantUML.
Лучше посмотреть все его возможности непосредственно по ссылке. Кратко могу суммировать, что PlantUML позволяет использовать в своих диаграммах:
переменные (в том числе выполнять с ними арифметические операции и прочее);
условия, например посредством конструкции if — else if — else;
циклы;
функции, в том числе имеет набор стандартных;
.. и еще много всего интересного.
Меня же заинтересовали переменные и условия. Стало понятно, что, скомбинировав их, можно добиться того, что нужно: показывать или не показывать часть диаграммы в зависимости от значения переменной.
Вот так:

Осталось дать возможность управлять этими переменными тому, кто изучает диаграмму. И, желательно, чтобы это управление было не прямым исправлением текста диаграммы :)
#2 Ищем способы справиться с ограничениями
Рассмотрим ограничения 1 и 2: размещение в Confluence и то, что backend'а для реализации, по крайней мере какого‑то самописного, лучше не иметь.
Тут идеи пришли быстрее — в Confluence есть макросы для вставки HTML‑страниц, а там, где HTML, там где‑то рядом и JavaScript, который может исполняться прямо в браузере.
Используя HTML + JavaScript можно создать что‑то типа переключателей с выпадающими списками (или подобное), где пользователь будет выбирать, показать или нет ему часть диаграммы. Выбранное будет влиять на переменные, заложенные в текст диаграммы (что обсуждали на предыдущем шаге). Изменение выбранного значения в переключателе будет вызывать перестройку диаграммы с новыми значениями переменных.
Успех?
Если бы. Есть еще ограничение 3 — я умею только в Python. И времени, чтобы понять HTML + JS, даже для такого простого случая, у меня нет (см. ограничение 4).
Штош... Эти ограничения можно попробовать закрыть с ИИ.
Спойлер: это было не слишком просто. В конце статьи добавлю мини‑раздел о своем взаимодействии с ИИ по этой задаче. А пока идем дальше.
#3 Учимся генерировать саму диаграмму
Все здорово, какая‑то часть функционала будет исполняться на лету в браузере, backend для нее не нужен. Но как же создание самой диаграммы из текста?
Тут меня осенило еще быстрее — PlantUML же сам как‑то картинку строит. Возможно, у него есть что‑то вроде API?...
Есть. Подробнее можно почитать тут — про взаимодействие с сервером PlantUML, и тут — про кодирование текста диаграммы.
Для того, чтобы получить картинку‑диаграмму из текста, нужно обратиться к URL вида:
http(s)://<адрес_сервера_PlantUML>/plantuml/<формат_изображения>/<закодированный_текст_диаграммы> <-- пример --> https://www.plantuml.com/plantuml/png/SoWkIImgAStDuRemySA-2niLTEqKBaouiFl2ZekD5pOeM2bSc7-nuSAE2vikRBtOfCZba9gN0bGC0000
Адрес сервера можно указать свой — например, если у вас в организации развернут свой сервер PlantUML.
Форматы выходного изображения: png, svg, ASCII art (не совсем формат, но тоже доступен). Для моих целей достаточно png.
C кодированием текста диаграммы PlantUML предлагает два варианта: простой и сложный.
Простой: берем текст диаграммы, убеждаемся, что он в UTF-8, и переводим его в hex, ставим префикс ~h (чтобы PlantUML отличил, что c ним хотят поговорить на hex).
Плюсы: просто и сердито. Минус — текст не проходит сжатие, а значит его влезет меньше в URL, так как длина этого URL лимитирована (как именно — указала ниже в разделе про ограничения). Следовательно, пригодно для диаграмм с меньшим числом символов исходного текста.
Сложный:
Убедиться, что текст в UTF-8.
Сжать текст алгоритмом deflate.
Получившуюся абракадабру привести к ASCII через кастомный base64 (описан по ссылке выше).
Итоговую абракадабру подставить в ссылку.
Плюс — влезет гораздо бОльшая по числу символов диаграмма, т.к. есть сжатие текста. Минусы: сложнее в реализации, и, скорее всего, потребуется импорт алгоритма deflate извне (альтернатива — написать вставить его на JS в мою HTML-страничку с переключателями — меня не слишком привлекала).
#4 Финализируемся
Препроцессинг PlantUML + PlantUML «API» + HTML + JS = Profit! (но это не точно :) ).
Реализация решения
WARNING: код, который вы увидите ниже, результат моего общения с ИИ. Я лишь довела его до работоспособности (т.к. то, что выдавал ИИ, не нравилось в части кодирования текста серверу PlantUML). Фактически, это мой первый опыт использования JS и HTML, поэтому, если вы видите, как этот код можно сделать прекраснее — расскажите мне об этом в комментариях, я буду только рада :)
Первое — создаем саму диаграмму (со всеми переменными и условиями).
Необходимо написать полный текст всей диаграммы, от и до. Затем вставить в нее желаемые переменные и условия, зависящие от этих переменных.
Текст диаграммы до вставки переменных:
participant Алиса as a b -> a: Привет! activate a a->a: О боже, он мне написал! a->a: Что делать,как быть.. create participant Лиза as l a -> l: Мне Боб написал, как быть? activate l l -> a: Просто ответь ему, Боже deactivate l a->b: Привет! deactivate a activate b b->b: Она ответила о_О b->a: Эээм...Как дела? deactivate b
Текст диаграммы после вставки переменных и условий:
participant Боб as b participant Алиса as a !$aliceThoughts = "Нет" <-- переменная раз !$bobThoughts = "Нет" <-- переменная два b -> a: Привет! !if ($aliceThoughts == "Да") <-- условие для первой переменной activate a a->a: О боже, он мне написал! a->a: Что делать,как быть.. create participant Лиза as l a -> l: Мне Боб написал, как быть? activate l l -> a: Просто ответь ему, Боже deactivate l !endif <-- конец условия для первой переменной a->b: Привет! deactivate a !if ($bobThoughts == "Да") <-- условие для второй переменной activate b b->b: Она ответила о_О !endif <-- конец условия для второй переменной b->a: Эээм...Как дела? deactivate b
Второе — создать код для переключателей, с которыми будет взаимодействовать пользователь.
Код для переключателей
<form> <label for="aliceThoughts">Показать мысли Алисы:</label> <select id="aliceThoughts" name="aliceThoughts"> <option value="no">Нет</option> <option value="yes">Да</option> </select> </form> <form> <label for="bobThoughts">Показать мысли Боба:</label> <select id="bobThoughts" name="bobThoughts"> <option value="no">Нет</option> <option value="yes">Да</option> </select> </form>
Третье (опциональное) — написать encoder для текста диаграммы. Можно простой, с hex, можно сложный, с deflate. Опционально, т.к. можно его вообще не писать, можно импортировать извне готовый.
Вариант с hex:
function toHex(uml) { const umlFormatted = `@startuml\r\n${uml}\r\n@enduml` const utf8 = unescape(encodeURIComponent(umlFormatted)) var result = ''; for (var i=0; i<utf8.length; i++) { result += utf8.charCodeAt(i).toString(16).padStart(2, '0'); console.log() } return `https://www.plantuml.com/plantuml/png/~h${result}`; }
Вариант с deflate:
+ не забыть импортировать сам deflate в итоговом html!
// Кастомный base64 по правилам PlantUML function encodePlantUml(data) { const base64Map = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_'; let result = ''; for (let i = 0; i < data.length; i += 3) { const b1 = data[i]; const b2 = i + 1 < data.length ? data[i + 1] : 0; const b3 = i + 2 < data.length ? data[i + 2] : 0; result += base64Map[b1 >> 2]; result += base64Map[((b1 & 3) << 4) | (b2 >> 4)]; result += base64Map[((b2 & 15) << 2) | (b3 >> 6)]; result += base64Map[b3 & 63]; } return result } // Сам encoder function compressAndGenerateURL(uml) { const umlFormatted = `@startuml\r\n${uml}\r\n@enduml`; const compressed = pako.deflateRaw(umlFormatted, {level: 9, to: 'string' }); const byteArray = new Uint8Array(compressed.length); for (let i = 0; i < compressed.length; i++) { byteArray[i] = compressed.charCodeAt(i); } const encoded = encodePlantUml(byteArray); return `https://www.plantuml.com/plantuml/png/${encoded}`; }
Четвертое — объединить это все в единый работающий код:
Разместить переключатели и само изображение с диаграммой на страничке.
Добавить текст диаграммы.
«Внедрить» значения из переключателей в текст диаграммы.
За счет этого при изменении выбранного значения будет меняться непосредственно текст диаграммы (в части значений переменных).При изменении выбранного значения в переключателе заново кодировать текст диаграммы и инициировать запрос нового изображения у сервера PlantUML.
Отображать пользователю новое изображение.
Далее — 3 варианта итогового скрипта для диаграммы с минимальными комментариями.
В конце раздела дам ссылку на примеры с максимально подробными комментариями, которые у меня получилось сделать — на их основании можно попробовать создать собственные диаграммы.
Вариант с encoder'ом в hex:
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Первый разговор</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } #image-container { margin-top: 20px; } </style> </head> <body> <h2>Первый разговор</h2> <! -- Создание переключателей --> <form> <label for="aliceThoughts">Показать мысли Алисы:</label> <select id="aliceThoughts" name="aliceThoughts"> <option value="no">Нет</option> <option value="yes">Да</option> </select> </form> </br> <form> <label for="bobThoughts">Показать мысли Боба:</label> <select id="bobThoughts" name="bobThoughts"> <option value="no">Нет</option> <option value="yes">Да</option> </select> </form> </br> <! -- Контейнер для выводимого изображения --> <div id="image-container"> <img id="dynamic-image" src="" alt="Selected option image" style="display: none;"> </div> <! -- Скрипт для обработки состояния переключателей, кодирования текста диаграммы и вывода изображения--> <script> // Определение элемента "переключатель" const aliceThoughtsSelect = document.getElementById('aliceThoughts'); const bobThoughtsSelect = document.getElementById('bobThoughts'); // Определение элемента "изображение" const imageElement = document.getElementById('dynamic-image'); // Первичный вывод изображения при открытии файла refreshImage(); // Настройка триггера на изменение состояния переключателей - обновляет изображение, если в выпадающих списках выбрали новый вариант aliceThoughtsSelect.addEventListener('change', function() { refreshImage(); }); bobThoughtsSelect.addEventListener('change', function() { refreshImage(); }); // Функция обновления изображения function refreshImage () { // Получение выбранного в переключателе значения const aliceThoughtsShow = aliceThoughtsSelect.value; const bobThoughtsShow = bobThoughtsSelect.value; // Создание текста UML-диаграммы с внедренными в нее значениями переключателей const umlSS = umlFullString (aliceThoughtsShow, bobThoughtsShow); // Кодирование строки UML-диаграммы и получение URL изображения const imageUrl = toHex(umlSS); // Вывод изображения по URL imageElement.src = imageUrl; imageElement.style.display = 'block' } // Функция для создания строки с текстом диаграммы и включенными в него значениями переключателей function umlFullString (const1, const2) { // Строка с текстом диаграммы const umlString = 'participant Боб as b\nparticipant Алиса as a\n!$aliceThoughts = "'+ const1 +'"\n!$bobThoughts = "'+ const2 +'"\nb -> a: Привет!\n!if ($aliceThoughts == "yes")\nactivate a\na->a: О боже, он мне написал!\na->a: Что делать,как быть..\ncreate participant Лиза as l\na -> l: Мне Боб написал, как быть?\nactivate l\nl -> a: Просто ответь ему, Боже\ndeactivate l\n!endif\na->b: Привет!\ndeactivate a\n!if ($bobThoughts == "yes")\nactivate b\nb->b: Она ответила о_О\n!endif\nb->a: Эээм...Как дела?\ndeactivate b'; return umlString } // Функция перевода текста диаграммы в hex и генерации URL для получения изображения function toHex(uml) { const umlFormatted = `@startuml\r\n${uml}\r\n@enduml` const utf8 = unescape(encodeURIComponent(umlFormatted)) var result = ''; for (var i=0; i<utf8.length; i++) { result += utf8.charCodeAt(i).toString(16).padStart(2, '0'); console.log() } return `https://www.plantuml.com/plantuml/png/~h${result}`; } </script> </body> </html>
Вариант с самописным encoder'ом с deflate:
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Первый разговор</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } #image-container { margin-top: 20px; } </style> </head> <body> <h2>Первый разговор</h2> <! -- Создание переключателей --> <form> <label for="aliceThoughts">Показать мысли Алисы:</label> <select id="aliceThoughts" name="aliceThoughts"> <option value="no">Нет</option> <option value="yes">Да</option> </select> </form> </br> <form> <label for="bobThoughts">Показать мысли Боба:</label> <select id="bobThoughts" name="bobThoughts"> <option value="no">Нет</option> <option value="yes">Да</option> </select> </form> </br> <! -- Контейнер для выводимого изображения --> <div id="image-container"> <img id="dynamic-image" src="" alt="Selected option image" style="display: none;"> </div> <!-- Импорт скрипта с алгоритмом сжатия deflate--> <script src="https://cdnjs.cloudflare.com/ajax/libs/pako/1.0.11/pako.min.js"></script> <! -- Скрипт для обработки состояния переключателей, кодирования текста диаграммы и вывода изображения--> <script> // Определение элемента "переключатель" const aliceThoughtsSelect = document.getElementById('aliceThoughts'); const bobThoughtsSelect = document.getElementById('bobThoughts'); // Определение элемента "изображение" const imageElement = document.getElementById('dynamic-image'); // Первичный вывод изображения при открытии файла refreshImage(); // Настройка триггера на изменение состояния переключателей - обновляет изображение, если в выпадающих списках выбрали новый вариант aliceThoughtsSelect.addEventListener('change', function() { refreshImage(); }); bobThoughtsSelect.addEventListener('change', function() { refreshImage(); }); // Функция обновления изображения function refreshImage () { // Получение выбранного в переключателе значения const aliceThoughtsShow = aliceThoughtsSelect.value; const bobThoughtsShow = bobThoughtsSelect.value; // Создание текста UML-диаграммы с внедренными в нее значениями переключателей const umlSS = umlFullString (aliceThoughtsShow, bobThoughtsShow); // Кодирование строки UML-диаграммы и получение URL изображения const imageUrl = compressAndGenerateURL(umlSS); // Вывод изображения по URL imageElement.src = imageUrl; imageElement.style.display = 'block' } // Функция для создания строки с текстом диаграммы и включенными в него значениями переключателей function umlFullString (const1, const2) { // Строка с текстом диаграммы const umlString = 'participant Боб as b\nparticipant Алиса as a\n!$aliceThoughts = "'+ const1 +'"\n!$bobThoughts = "'+ const2 +'"\nb -> a: Привет!\n!if ($aliceThoughts == "yes")\nactivate a\na->a: О боже, он мне написал!\na->a: Что делать,как быть..\ncreate participant Лиза as l\na -> l: Мне Боб написал, как быть?\nactivate l\nl -> a: Просто ответь ему, Боже\ndeactivate l\n!endif\na->b: Привет!\ndeactivate a\n!if ($bobThoughts == "yes")\nactivate b\nb->b: Она ответила о_О\n!endif\nb->a: Эээм...Как дела?\ndeactivate b'; return umlString } // Функция реализации кастомного base64, используемого PlantUML function encodePlantUml(data) { const base64Map = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'; let result = ''; for (let i = 0; i < data.length; i += 3) { const b1 = data[i]; const b2 = i + 1 < data.length ? data[i + 1] : 0; const b3 = i + 2 < data.length ? data[i + 2] : 0; result += base64Map[b1 >> 2]; result += base64Map[((b1 & 3) << 4) | (b2 >> 4)]; result += base64Map[((b2 & 15) << 2) | (b3 >> 6)]; result += base64Map[b3 & 63]; } return result } // Функция кодирования текста диаграммы с алгоритмом deflate function compressAndGenerateURL(uml) { const umlFormatted = `@startuml\r\n${uml}\r\n@enduml`; const compressed = pako.deflateRaw(umlFormatted, {level: 9, to: 'string' }); const byteArray = new Uint8Array(compressed.length); for (let i = 0; i < compressed.length; i++) { byteArray[i] = compressed.charCodeAt(i); } const encoded = encodePlantUml(byteArray); return `https://www.plantuml.com/plantuml/png/${encoded}`; } </script> </body> </html>
Вариант с импортированным готовым encoder'ом с deflate:
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Первый разговор</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } #image-container { margin-top: 20px; } </style> </head> <body> <h2>Первый разговор</h2> <! -- Создание переключателей --> <form> <label for="aliceThoughts">Показать мысли Алисы:</label> <select id="aliceThoughts" name="aliceThoughts"> <option value="no">Нет</option> <option value="yes">Да</option> </select> </form> </br> <form> <label for="bobThoughts">Показать мысли Боба:</label> <select id="bobThoughts" name="bobThoughts"> <option value="no">Нет</option> <option value="yes">Да</option> </select> </form> </br> <! -- Контейнер для выводимого изображения --> <div id="image-container"> <img id="dynamic-image" src="" alt="Selected option image" style="display: none;"> </div> <!-- Импорт скрипта с алгоритмом сжатия deflate--> <script src="https://cdnjs.cloudflare.com/ajax/libs/pako/1.0.11/pako.min.js"></script> <! -- Скрипт для обработки состояния переключателей, кодирования текста диаграммы и вывода изображения--> <!-- Импорт скрипта с encoder для PlantUML--> <script src="https://cdn.jsdelivr.net/npm/plantuml-encoder@1.4.0/dist/plantuml-encoder.min.js"></script> <script> // Определение элемента "переключатель" const aliceThoughtsSelect = document.getElementById('aliceThoughts'); const bobThoughtsSelect = document.getElementById('bobThoughts'); // Определение элемента "изображение" const imageElement = document.getElementById('dynamic-image'); // Первичный вывод изображения при открытии файла refreshImage(); // Настройка триггера на изменение состояния переключателей - обновляет изображение, если в выпадающих списках выбрали новый вариант aliceThoughtsSelect.addEventListener('change', function() { refreshImage(); }); bobThoughtsSelect.addEventListener('change', function() { refreshImage(); }); // Функция обновления изображения function refreshImage () { // Получение выбранного в переключателе значения const aliceThoughtsShow = aliceThoughtsSelect.value; const bobThoughtsShow = bobThoughtsSelect.value; // Создание текста UML-диаграммы с внедренными в нее значениями переключателей const umlSS = umlFullString (aliceThoughtsShow, bobThoughtsShow); // Кодирование строки UML-диаграммы и получение URL изображения const encoded = plantumlEncoder.encode(umlSS) const imageUrl = `https://www.plantuml.com/plantuml/png/${encoded}`; // Вывод изображения по URL imageElement.src = imageUrl; imageElement.style.display = 'block' } // Функция для создания строки с текстом диаграммы и включенными в него значениями переключателей function umlFullString (const1, const2) { // Строка с текстом диаграммы const umlString = 'participant Боб as b\nparticipant Алиса as a\n!$aliceThoughts = "'+ const1 +'"\n!$bobThoughts = "'+ const2 +'"\nb -> a: Привет!\n!if ($aliceThoughts == "yes")\nactivate a\na->a: О боже, он мне написал!\na->a: Что делать,как быть..\ncreate participant Лиза as l\na -> l: Мне Боб написал, как быть?\nactivate l\nl -> a: Просто ответь ему, Боже\ndeactivate l\n!endif\na->b: Привет!\ndeactivate a\n!if ($bobThoughts == "yes")\nactivate b\nb->b: Она ответила о_О\n!endif\nb->a: Эээм...Как дела?\ndeactivate b'; return umlString } </script> </body> </html>
Пятое — либо обернуть это в файлик с расширением .html и радостно раздать коллегам, либо вставить это в Confluence, предварительно разместив на страничке макрос для HTML.
Вот здесь размещены примеры с максимально подробными комментариями, что я составляла для Analyst Days. Там те же три примера с разными encoder'ами, но несколько другая диаграмма.
Дополнительно выложила доказательство, что все работает в Confluence :-)
Про вклад ИИ
Для ИИ я разделила задачу на два кусочка:
Реализовать на JS + HTML страничку, на которой сверху — переключатели с выпадающим списком возможных значений, снизу — картинка. При выборе нового значения в переключателе должна инициироваться смена картинки.
Написать encoder по правилам PlantUML (для сложного случая с deflate).
С первой задачей он справился легко и просто.
Со второй... Со второй проигнорировал информацию про кастомный base64, но даже после исправления этого момента закодированную строку сервер PlantUML отвергал. ИИ не помогло ни сообщение ошибки от PlantUML, ни ссылки на работающий encoder с просьбой сделать «как в нем», ни явная информация, как правильно должна выглядеть закодированная строка.
Вот сообщение ему правильного вида строки выстрелило мне в ногу. Так как, когда я решила подебажить, начав с просьбы вывести результат каждого шага его же кода — в конце он начал выводить правильный ответ, который запомнил с моих слов.
Я в браузере по его коду получаю некорректную для PlantUML строку, а ИИ мне говорит на голубом глазу: «Ты что, вот результат работы моего кода!», и выводит правильную. Пока до меня дошло, что он просто запомнил, я почти уверилась, что с моей кукушечкой что-то не то, и я не способна даже нормально перенести код в файлик и открыть его в браузере :)
Посражавшись с ним несколько часов, я пошла глазками сравнивать код работающего encoder'а с Github и код от ИИ. Буквально в режиме обезьянки — что-то понимаю, но не до конца, но сравнить могу. Полчаса у меня ушло на то, чтобы найти один параметр, который надо было исправить при работе с deflate, чтобы все заработало.
Итого считаю, что со второй задачей справиться у него не вышло.
ИИ мне помог. Но... Как будто самой могло быть и проще :)
Ограничения решения
Как всегда, есть ряд но:
Количество символов в диаграмме лимитировано длиной URL, которую может обработать PlantUML.
Максимум символов в подставляемой в URL сжатой/преобразованной в hex строке на момент моих исследований — 6935.
Однозначно из этой цифры нельзя сказать, насколько большая диаграмма у вас получится. Какой-то текст сжимается лучше, какой-то хуже. С deflate у меня получилось около 20 000 символов в тексте исходной диаграммы, с hex — что-то около 4 000.В Confluence могут быть ограничения, из-за чего получится использовать только hex-вариант.
Так как может не получиться импортировать внешние JS-скрипты (с deflate, с encoder'ом).
У меня была возможность поработать с «менее закрытым» Confluence, чем описанный в исходной задаче. В нем работали все варианты.Некоторые HTML-макросы Confluence занимают весь контент страницы.
Иными словами, у вас будет просто одна диаграмма на странице, и ничего больше.
Опять же, зависит от макроса. Находила и такие, где хоть 5 таких диаграмм на страницу вставь, между ними текст и вообще что угодно.HTML-макросы могут быть запрещены к установке в корпоративном Confluence.
В одной организации у меня он был, в другой — нет. Тогда только прикладывать файлики диаграмм в html.Заметила проблемы с Safari, ругался на ряд конструкций JS. Погуглила. Насколько смогла понять, есть некоторые конструкции языка, которые не работают в старых версиях Safari.
Каждый раз под новую диаграмму надо править код в файликах вручную.
В целом, это можно решить созданием утилитки, которая будет иметь дружелюбный интерфейс и на выходе выдавать нужный .html. И я целый год обещаю, в том числе сама себе, этим заняться :-)
Спасибо за прочтение :) Буду рада ответить на вопросы, а также идеям по улучшению описанного подхода, как здесь, так и в Telegram.
А еще я тут завела себе Telegram‑канал, пока ищу «свои» рубрики, но, в том числе, планирую там освещать свою дальнейшую работу по таким динамическим диаграммам — как по созданию утилитки, так и по расширению подхода на другие типы UML‑диаграмм. Да‑да, мессенджер блокируют, а я — пора!
Еще там точно будет саппортовое (я же выходец из технической поддержки), про то, где ИИ «не так хорош как мог бы», что‑то на системно‑аналитическом и... про использование коня для прокачки навыков анализа :D
