rc
This commit is contained in:
1 parent
e39ad275b5
commit
3d7e3a88f2
14 files changed
+710
-234
No files matched your search
+55
-23
@@ -1,6 +1,8 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
@@ -9,8 +11,9 @@ func newMenuList() list.Model {
|
||||
items := []list.Item{
|
||||
simpleItem{id: "users", title: "Пользователи", desc: "Создать, заблокировать, удалить учётные записи"},
|
||||
simpleItem{id: "catalog", title: "Хосты и сервисы", desc: "Общий каталог: адреса и порты, один раз на всех, группы просто выбирают из него"},
|
||||
simpleItem{id: "groups", title: "Группы", desc: "Какие хосты из каталога входят в каждую группу"},
|
||||
simpleItem{id: "groups", title: "Группы", desc: "Какие сервисы из каталога входят в каждую группу"},
|
||||
simpleItem{id: "export", title: "Экспорт архивов", desc: "Сгенерировать ключи и .7z архивы для доставки пользователям"},
|
||||
simpleItem{id: "configupdate", title: "Обновить конфиги", desc: "Перевыпустить только config (без ключа) для тех, у кого изменился доступ"},
|
||||
simpleItem{id: "audit", title: "Аудит / кто в сети", desc: "Активные сессии и журнал подключений"},
|
||||
simpleItem{id: "quit", title: "Выход", desc: ""},
|
||||
}
|
||||
@@ -39,6 +42,9 @@ func (m Model) updateMenu(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case "export":
|
||||
m.screen = scrExportSelect
|
||||
m.initExportSelect()
|
||||
case "configupdate":
|
||||
m.screen = scrConfigUpdateSelect
|
||||
m.initConfigUpdateSelect()
|
||||
case "audit":
|
||||
m.screen = scrAudit
|
||||
m.refreshAudit()
|
||||
@@ -55,34 +61,47 @@ func (m Model) updateMenu(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
// viewMenu appends a live summary of pending follow-up work (users with no
|
||||
// key yet, users whose config no longer matches their real access) below
|
||||
// the menu, recomputed on every render — so it can never go stale itself.
|
||||
func (m Model) viewMenu() string {
|
||||
return borderStyle.Render(m.menu.View())
|
||||
body := m.menu.View()
|
||||
neverExported, stale := m.quitWarnings()
|
||||
if len(neverExported) == 0 && len(stale) == 0 {
|
||||
return borderStyle.Render(body)
|
||||
}
|
||||
notice := ""
|
||||
if len(neverExported) > 0 {
|
||||
notice += warnStyle.Render(fmt.Sprintf("Без ключа: %d (см. «Экспорт архивов»)", len(neverExported))) + "\n"
|
||||
}
|
||||
if len(stale) > 0 {
|
||||
notice += warnStyle.Render(fmt.Sprintf("Устаревший конфиг: %d (см. «Обновить конфиги»)", len(stale))) + "\n"
|
||||
}
|
||||
return borderStyle.Render(body + "\n" + notice)
|
||||
}
|
||||
|
||||
// unexportedUsers returns active users who have never had a key issued
|
||||
// (empty PublicKey) — created but forgotten before "Экспорт архивов".
|
||||
func unexportedUsers(m *Model) []string {
|
||||
// quitWarnings splits active users into the two categories worth warning
|
||||
// about before quitting: those who never got a key at all, and those whose
|
||||
// access changed since their last config (full export or config-only
|
||||
// update) — the latter are running with an out-of-date client config that
|
||||
// won't reach everything they're now allowed to.
|
||||
func (m *Model) quitWarnings() (neverExported, stale []string) {
|
||||
st := m.loadState()
|
||||
var out []string
|
||||
for _, u := range st.Users {
|
||||
if u.PublicKey == "" {
|
||||
out = append(out, u.Username)
|
||||
}
|
||||
}
|
||||
return out
|
||||
return st.NeverExportedUsernames(), st.StaleConfigUsernames()
|
||||
}
|
||||
|
||||
// attemptQuit is the only path that actually quits from the menu ("q" or
|
||||
// selecting "Выход"): if there are users created but never exported, it
|
||||
// warns instead of quitting straight away, since it's easy to create a
|
||||
// batch of users, get interrupted, and forget the export step entirely.
|
||||
// ctrl+c bypasses this deliberately, as an always-available hard exit.
|
||||
// selecting "Выход"): if there are users created but never exported, or
|
||||
// users whose config fell out of date, it warns instead of quitting
|
||||
// straight away — both are easy to lose track of mid-session. ctrl+c
|
||||
// bypasses this deliberately, as an always-available hard exit.
|
||||
func (m Model) attemptQuit() (tea.Model, tea.Cmd) {
|
||||
pending := unexportedUsers(&m)
|
||||
if len(pending) == 0 {
|
||||
neverExported, stale := m.quitWarnings()
|
||||
if len(neverExported) == 0 && len(stale) == 0 {
|
||||
return m, tea.Quit
|
||||
}
|
||||
m.quitPending = pending
|
||||
m.quitPending = neverExported
|
||||
m.quitStale = stale
|
||||
m.quitReturnTo = scrMenu
|
||||
m.screen = scrQuitConfirm
|
||||
return m, nil
|
||||
@@ -102,11 +121,24 @@ func (m Model) updateQuitConfirm(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
func (m Model) viewQuitConfirm() string {
|
||||
body := warnStyle.Render("Есть пользователи, для которых ещё не сгенерирован ключ (не были в «Экспорт архивов»):") + "\n\n"
|
||||
for _, u := range m.quitPending {
|
||||
body += " - " + u + "\n"
|
||||
body := ""
|
||||
if len(m.quitPending) > 0 {
|
||||
body += warnStyle.Render("Без выданного ключа (не были в «Экспорт архивов»):") + "\n"
|
||||
for _, u := range m.quitPending {
|
||||
body += " - " + u + "\n"
|
||||
}
|
||||
body += "\n"
|
||||
}
|
||||
body += "\nБез экспорта у них нет ключа и архива для передачи — доступ не работает.\n"
|
||||
if len(m.quitStale) > 0 {
|
||||
body += warnStyle.Render("Доступ изменился, но конфиг у пользователя старый (см. «Обновить конфиги»):") + "\n"
|
||||
for _, u := range m.quitStale {
|
||||
body += " - " + u + "\n"
|
||||
}
|
||||
body += "\n"
|
||||
}
|
||||
body += "Без этого у части пользователей либо нет доступа вообще, либо их текущий\n"
|
||||
body += "config не соответствует реальным правам (не хватает новых сервисов, или\n"
|
||||
body += "остались лишние, которых уже нет).\n"
|
||||
body += "\n[enter/y] выйти всё равно [esc/n] вернуться"
|
||||
return borderStyle.Render(body)
|
||||
}
|
||||
Reference in new issue
Block a user