Динамические названия кнопок #9
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Нужно предусмотреть переименование кнопок в конфигурации фронта. То есть я хочу иметь возможность задать другие имена кнопкам. Если значения не заданы, то должны использоваться текущие по умолчанию. Здесь нужно подумать, как это лучше сделать. Через конфигурацию бекенда и чтобы он возвращал названия кнопок, либо это сделать конфигурацией фронта. Не знаю, предложи решение с плюсами и минусами каждого.
Беру задачу, ветка
feature/9_dynamic_button_labels. Изучаю код и готовлю предложение по вариантам реализации (конфиг бекенда vs конфиг фронта) с плюсами/минусами — опубликую здесь на выбор.Разобрался, как сейчас устроено, и подготовил варианты.
Как сейчас. Кнопки жёстко зашиты во фронте (
web/src/utils/buttons.ts): 5 кнопок (POWER, MOVE_OUT, MOVE_IN, ACK, PU), у каждойmask(протокол),name(внутренний идентификатор, на нём маска/логика),label(отображаемое имя) иkey(хоткей 1–5). Конфигурация системы — единый.envрядом с бинарником бекенда (LINK_PATH,HTTP_ADDR,API_TOKEN, ...). Бекенд раздаёт собранный фронт и APIGET/PUT /api/buttons.Переименовывать нужно именно
label;mask/name/keyтрогать нельзя — на них завязаны протокол и логика. Оба варианта ниже это учитывают; если переопределения не заданы — используются текущие дефолтные имена.Вариант A — конфиг бекенда (рекомендую).
В
.envдобавляются ключи видаBUTTON_LABEL_POWER=Питание,BUTTON_LABEL_MOVE_OUT=Выезди т.д. Бекенд отдаёт их фронту новым эндпоинтомGET /api/configв виде переопределений:{"labels":{"POWER":"Питание", ...}}. Фронт при загрузке мержит их поверх встроенной таблицы кнопок; чего нет или пусто — берётся дефолт.Плюсы:
.envу бинарника, новые ключи ложатся туда же естественно;distработает с любой конфигурацией (правка.env+ рестарт бекенда);Минусы:
/api/configфронт показывает дефолтные подписи (доли секунды при загрузке; можно закрыть заглушкой до завершения загрузки).Вариант B — конфиг фронта.
VITE_BTN_POWER_LABEL=...) — имена зашиваются в бандл при сборке.config.jsonрядом сindex.html, фронт читает его при старте.Плюсы:
Минусы:
distприходится держать синхронно;web/dist), который затирается при каждой пересборке/обновлении фронта — конфигурация разносится по двум точкам, при деплое легко ошибиться;.envрядом с бинарником».Рекомендация: вариант A. Сохраняет единую точку конфигурации, не требует пересборки при переименовании и почти не связывает бекенд с фронтом. Если подтверждаете вариант A (или выбираете другой) — реализую в ветке
feature/9_dynamic_button_labels: ключи.env+GET /api/config+ мерж во фронте с фолбэком на дефолты, тесты на обе стороны (Go-хендлер и мерж во фронте).Хорошо, давай сделаем вариант A. Как можно сделать так, чтобы например пользователь с фронта мог изменить названия кнопок и чтобы они навсегда остались, не важно перезагрузился фронт, бекенд или полностью устройство? Пока не думай о фронте (это реализуем позже), как сделать лучше всего на бекенде?
Ответ на вопрос про хранение: названия кнопок — это пользовательские данные, а не конфигурация развёртывания. Поэтому предлагаю хранить их не в самом
.env, а в отдельном JSON-файле рядом с бинарником;.envостаётся точкой админских значений по умолчанию.Предлагаемая схема (рекомендую):
.env:UI_CONFIG_FILE(по умолчанию —ui_config.jsonрядом с исполняемым файлом).BUTTON_FILE), плюс fsync перед rename — чтобы изменения переживали даже выключение питания:BUTTON_LABEL_*из.env(админские) <ui_config.json(пользовательские). Пустая строка = явный сброс к дефолту (ключ не учитывается)./api/buttons):GET /api/config— отдаёт эффективные переопределения (env, слитый с файлом);PUT /api/config/labels— принимает{"labels": {...}}, валидирует (только известные имена кнопок POWER/MOVE_OUT/MOVE_IN/ACK/PU, трим, ограничение длины), атомарно пишет файл и обновляет копию в памяти.Почему это решает задачу «навсегда»: файл лежит на диске рядом с бинарником — перезагрузка фронта не важна (он просто заново делает GET), рестарт бекенда не важен (файл читается при старте), полное выключение устройства не важно (запись атомарная, с fsync).
Почему не перезаписывать сам
.envиз программы:.envчитаются один раз при старте — изменения из UI требовали бы либо рестарта, либо второй копии «истины» в памяти, разъезжающейся с файлом;.envруками, программа одновременно — из HTTP-хендлера.Рассмотренные альтернативы:
.envбез файла — не позволяет менять имена из UI без перезаписи конфига программой (см. выше).Бонус: тот же
ui_config.jsonдальше примет настройки из задачи #10 (тема, раскладка кнопок, флаг «Журнал») — получится единая точка пользовательских настроек с одним API/api/config.Если подтверждаете схему — реализую в ветке
feature/9_dynamic_button_labels:UI_CONFIG_FILE, загрузка/сохранение с атомарной записью,GET /api/config+PUT /api/config/labels, тесты (валидация, приоритеты источников, переживание рестарта).ui_config.json - делаем. Только обязательно валидируй данные, по размеру, по формату, по безопасности и так далее. Обнови main я туда влил изменения по настройкам
Принято: схема с
ui_config.jsonподтверждена, валидации (формат, размеры, безопасность) — обязательно. Обновляю main с вашими изменениями по настройкам и продолжаю работу в веткеfeature/9_dynamic_button_labels.Готово, PR #12 на ревью, ветка
feature/9_dynamic_button_labels.Реализовано по подтверждённой схеме:
UI_CONFIG_FILE(ui_config.jsonрядом с бинарником, атомарная запись tmp+rename+fsync),BUTTON_LABEL_*в.envкак админские дефолты,GET /api/config+PUT /api/config/labels(bearer-авторизация), фронт применяет переопределения при загрузке. Валидация: только известные имена кнопок, лимиты длины/количества/размера, белый список символов, битый файл не роняет процесс. Подписи — переопределяются, маски/имена/хоткеи — нет. Все тесты зелёные (Go + web), схема проверена живым прогоном: сохранение переживает рестарт процесса.