160 lines
19 KiB
Markdown
160 lines
19 KiB
Markdown
# LPRA 0.1.3 — рабочее пространство (подпроект 1)
|
|
|
|
Дата: 2026-10-15. Статус: согласовано в обсуждении, ждёт проверки спецификации.
|
|
Подпроект 2 (встроенный ИИ-помощник) — отдельная спецификация, делается после этого.
|
|
|
|
## Цель
|
|
|
|
Работа с несколькими машинами в одном месте, без потери открытых терминалов при переходах по панели.
|
|
Терминалы, файловые менеджеры (своих машин и по SSH) живут во вкладках одного рабочего пространства;
|
|
файлы перетаскиваются между панелями и в терминал.
|
|
|
|
Критерии готовности:
|
|
- переход Машины ↔ Терминал ↔ Настройки не обрывает сессии терминалов и не сбрасывает вкладки;
|
|
- перезагрузка страницы сбрасывает пространство (с предупреждением браузера, если есть живые сессии);
|
|
- файловый менеджер — тип панели во вкладке, в том числе по SSH;
|
|
- перетаскивание файлов: между файловыми панелями (окно «переместить / копировать»), в терминал той же машины (вставка путей), в терминал другой машины — запрет с сообщением.
|
|
|
|
## Решения, принятые в обсуждении
|
|
|
|
| вопрос | решение |
|
|
|---|---|
|
|
| Страницы «Порты», «Статус», «Изменить» | окна поверх текущей страницы |
|
|
| Файлы рядом с терминалами в одной вкладке | да: любая из до 4 панелей — терминал, SSH-терминал, файлы, SSH-файлы |
|
|
| Перезагрузка при живых сессиях | вопрос браузера «Покинуть сайт?» |
|
|
| Архитектура | одностраничная оболочка, остальное — HTML-фрагменты с сервера (вариант A) |
|
|
| Файлы по SSH | без SFTP-библиотеки: команды на хосте через SSH, как у существующей передачи tar |
|
|
| Состояние | одно на вкладку браузера, в памяти страницы; не сохраняется при перезагрузке |
|
|
|
|
## 1. Каркас и маршруты
|
|
|
|
**Оболочка.** Адреса `/`, `/terminal`, `/settings` отдают один шаблон `app.html`: шапка (LPRA, «Машины · Терминал · Настройки» — «Настройки» только администраторам, статус активной панели, аккаунт) и три области `<section data-view="machines|terminal|settings">`.
|
|
Старые адреса `/agents/{id}/terminal` и `/agents/{id}/files` отдают ту же оболочку и при загрузке создают вкладку нужного типа для этой машины (закладки не ломаются).
|
|
|
|
**Роутер** (`static/app.js`, без библиотек):
|
|
- перехватывает клики по внутренним ссылкам и `popstate`; меняет видимую область через `history.pushState`, подсвечивает пункт шапки;
|
|
- область «Терминал» создаётся один раз и потом только скрывается (`hidden`) — сессии, WebSocket и xterm живут, пока жива вкладка браузера;
|
|
- «Машины» и «Настройки» при каждом показе подгружаются заново как фрагмент: `GET /?frag=1`, `GET /settings?frag=1`.
|
|
|
|
**Фрагменты на сервере.** `render()` получает режим фрагмента (параметр `frag=1`): шаблон отдаёт только содержимое, без `<html>`, шапки и подключений. Общая разметка `head` и `topbar`, сейчас скопированная в каждый шаблон, выносится в `{{define}}`-блоки.
|
|
|
|
**Формы во фрагментах** (`app.js`, перехват `submit` внутри областей и окон):
|
|
1. `onsubmit`-обработчики (`confirm(...)`) срабатывают как обычно; отказ — ничего не происходит;
|
|
2. форма отправляется через `fetch` (`redirect: 'follow'`, тело — `FormData`);
|
|
3. итоговый адрес ответа определяет, что перерисовать: тот же фрагмент по этому адресу (сохраняются `?err=...`, `?updated=1`, `#users`);
|
|
4. формы на `/logout` и ссылки наружу работают обычной загрузкой страницы.
|
|
|
|
**Скрипты фрагментов.** Встроенные `<script>` во фрагментах не исполняются. Поведение страниц оформляется модулями с `mount(root)` / `unmount()`, которые вызывает роутер: копирование команд и коды установки (настройки), `users.js`, список машин с опросом присутствия.
|
|
`pin.js`, `scroll.js`, `account.js` подключаются один раз в оболочке.
|
|
|
|
**Предупреждение при уходе.** `beforeunload` спрашивает «Покинуть сайт?», только если в рабочем пространстве есть живая сессия терминала или SSH-терминала.
|
|
|
|
## 2. Рабочее пространство и типы панелей
|
|
|
|
**Модель.** Вкладка содержит 1–4 панели в существующих раскладках (`1`, `h`, `v`, сетка), с изменением размеров и перетаскиванием панелей и вкладок, как сейчас. Тип панели:
|
|
|
|
| тип | что это |
|
|
|---|---|
|
|
| `term` | терминал на машине (как сейчас) |
|
|
| `ssh` | SSH-терминал через машину (как сейчас) |
|
|
| `files` | файловый менеджер на машине |
|
|
| `sshfiles` | файловый менеджер на SSH-хосте через машину |
|
|
|
|
**Разделение кода** (сейчас всё в `terminal.js` и `files.html`):
|
|
- `workspace.js` — вкладки, раскладки, разделение, перетаскивание панелей и вкладок, меню «+». С панелями работает через общий интерфейс: `el`, `kind`, `agent`, `title`, `state` и `text` (точка и строка статуса), `fit()`, `focus()`, `close()`, `acceptsDrop(item)`, `drop(item)`;
|
|
- `termpane.js` — нынешний класс `Session` (терминал и SSH-терминал), вынесенный почти без изменений;
|
|
- `filepane.js` — файловая панель (часть 3);
|
|
- `fileviews.js` — общие окна файлов (просмотр и правка, hex, свойства, перемещение, загрузка, редактор SQLite).
|
|
|
|
**Меню «+»** (на компьютере и телефоне):
|
|
- «Терминал ›» — «здесь (машина)», другие машины в сети, «SSH-хост…»;
|
|
- «Файловый менеджер ›» — «здесь (машина)», другие машины в сети, «SSH-хост…».
|
|
|
|
«SSH-хост…» открывает существующее окно SSH-подключения; тип панели зависит от пункта меню. Последний SSH-хост (без секретов) запоминается, как сейчас.
|
|
|
|
**Из списка машин:** кнопка терминала → новая вкладка-терминал этой машины и переход в «Терминал»; кнопка файлов → новая вкладка «Файлы». Если пространства ещё нет, оно создаётся.
|
|
|
|
**Заголовки.** Вкладка файлов — иконка папки и `машина · папка`, путь обрезается слева, обновляется при смене папки. Переименование двойным кликом — как у терминалов. Точка статуса файловой панели — машина в сети / офлайн / ошибка.
|
|
|
|
**Телефон.** Вкладки и меню те же; разделения и перетаскивания, как и сейчас, только на компьютере.
|
|
|
|
## 3. Файловая панель
|
|
|
|
Содержимое нынешней страницы файлов как компонент `FilePane(source)`: строка пути, «Вверх», «Обновить», «Папка / Файл / Загрузить», таблица с отметками, «В zip», «Удалить выбранное», загрузка перетаскиванием из ОС.
|
|
Состояние (текущая папка, список, отметки) — у экземпляра; элементы ищутся внутри корня панели, без глобальных `id`. Две файловые панели в одной вкладке не мешают друг другу.
|
|
|
|
**Общие окна** (`fileviews.js`) — одно на страницу. При открытии окну передаётся панель-источник: машина или SSH, путь, что обновить после действия.
|
|
|
|
**Источник данных** — один интерфейс (`list`, `read`, `write`, `mkdir`, `delete`, `move`, `copy`, `stat`, `chmod`, `download`, `upload`) с двумя реализациями:
|
|
- машина — существующий `/api/panel/agents/{id}/fs/...`;
|
|
- SSH-хост — новые задачи агента `sshfs.*` (ниже).
|
|
|
|
**Узкие панели** (меньше ~520 px, в разделённой вкладке): прячется колонка «Изменён», кнопки строки сворачиваются в меню «⋯» — как сейчас на телефоне.
|
|
|
|
### Файлы по SSH (`sshfiles`)
|
|
|
|
Агент держит одно SSH-подключение на панель: `sshConnect` и проверка ключа хоста из SSH-терминала. Подключение открывается при создании панели (окно «SSH-хост…»), получает id, закрывается при закрытии панели или через 10 минут простоя. Секреты передаются агенту один раз, панель их не хранит.
|
|
|
|
Операции — команды на хосте, пути в одинарных кавычках (`shq`):
|
|
|
|
| операция | команда |
|
|
|---|---|
|
|
| список | `stat` по содержимому папки; формат выбирается один раз при подключении: GNU/busybox `stat -c`, BSD/macOS `stat -f`; без `stat` — разбор `ls -la` без точного времени |
|
|
| чтение, скачивание | `cat -- 'файл'`, поток через stdout |
|
|
| запись, загрузка | `cat > 'файл.tmp' && mv 'файл.tmp' 'файл'`, поток через stdin |
|
|
| папка, удаление, переименование | `mkdir -p`, `rm -rf`, `mv` |
|
|
| права, владелец | `chmod`, `chown` |
|
|
| копирование, перенос внутри хоста | `cp -a`, `mv` |
|
|
| перенос между хостом и машинами | существующая передача tar по SSH |
|
|
|
|
Новые задачи агента: `sshfs.open` (подключиться, вернуть id и домашнюю папку), `sshfs.close`, `sshfs.list`, `sshfs.read`, `sshfs.write`, `sshfs.mkdir`, `sshfs.delete`, `sshfs.move`, `sshfs.copy`, `sshfs.stat`, `sshfs.chmod`, `sshfs.send` (скачивание через существующие куски `xfer`), `sshfs.put` (загрузка через куски `xfer`).
|
|
Серверу — те же правила доступа, что у файловых операций машины; изменения пишутся в аудит.
|
|
|
|
Не входит: zip и распаковка на SSH-хосте, редактор SQLite по SSH — эти кнопки в `sshfiles` скрыты. Новых зависимостей нет.
|
|
|
|
## 4. Перетаскивание
|
|
|
|
**Что тащится:** строка файла или папки; если строка отмечена — все отмеченные строки панели. У курсора бейдж (имя или «N элементов»).
|
|
Механизм — на `pointer`-событиях внутри страницы, тот же, что уже двигает вкладки и панели; подсказка над целью говорит, что произойдёт.
|
|
|
|
| цель | результат |
|
|
|---|---|
|
|
| другая файловая панель (любая машина или SSH-хост) | небольшое окно у места броска: «Переместить / Копировать / Отмена», куда (папка цели), «если уже есть: сообщить ▾». Внутри машины — `fs.copy`; внутри SSH-хоста — `cp`/`mv`; между разными — существующая передача tar с прогрессом в этом же окне |
|
|
| папка в списке панели | то же, цель — эта папка |
|
|
| терминал той же машины / того же SSH-хоста | пути в одинарных кавычках через пробел вставляются в терминал, без Enter |
|
|
| терминал другой машины | цель подсвечивается красным, подсказка «Нельзя: файл на X, терминал на Y» |
|
|
| заголовок вкладки | через 0,5 с наведения вкладка активируется, бросить можно в её панель |
|
|
| пустое место / Esc | отмена |
|
|
|
|
Правила конфликтов имён — те же, что в окне «Переместить или копировать». Загрузка из ОС перетаскиванием — в любую файловую панель. На телефоне перетаскивания нет; остаётся окно перемещения с выбором машины или SSH.
|
|
|
|
## 5. Окна машины
|
|
|
|
«Порты», «Статус», «Изменить» — нынешние страницы как фрагменты (`?frag=1`) в общем окне `machinedlg` (заголовок «машина · раздел», закрытие; на телефоне — на весь экран).
|
|
Открываются из кнопок строки в списке машин и из меню заголовка вкладки или панели (её машина). Формы — перехватом из части 1; результат (например, обновления клиента) показывается в окне.
|
|
Живые части (графики и опрос статуса, тест скорости, присутствие) — модули `mount` / `unmount`; при закрытии окна останавливаются.
|
|
|
|
## Ошибки и крайние случаи
|
|
|
|
- Машина офлайн: терминал — как сейчас; файловая панель — «машина офлайн» и «повторить», при возвращении машины обновляется сама.
|
|
- Нет доступа (роль «пользователь»): чужих машин нет в меню и списке; если доступ отобран при открытой вкладке — панель показывает «нет доступа».
|
|
- Сессия истекла (401 или редирект на `/login`): сообщение и переход на вход.
|
|
- Агент без `sshfs.*`: пункт «Файлы по SSH» сообщает «обновите агента».
|
|
- Фрагмент не загрузился: ошибка и «повторить» в его области, остальное приложение работает.
|
|
- SSH-подключение файловой панели оборвалось: следующая операция переподключается один раз; не вышло — панель сообщает и предлагает переподключиться.
|
|
|
|
## Проверка
|
|
|
|
На стенде (сервер, агент, тестовый sshd), Chrome на компьютере и в эмуляции телефона:
|
|
1. Переходы Машины ↔ Терминал ↔ Настройки при идущем выводе в терминале — вывод не прерывается; «Назад / Вперёд»; перезагрузка — сброс и «Покинуть сайт?».
|
|
2. Вкладки с терминалом, файлами, SSH-файлами; разделение, изменение размеров, перетаскивание панелей и вкладок.
|
|
3. Файловая панель машины и SSH-хоста: список, просмотр, правка, загрузка, скачивание, создание, удаление, переименование, права.
|
|
4. Перетаскивание: в соседнюю панель (своя машина, SSH), в папку, в терминал той же машины (вставка путей), в терминал чужой (запрет).
|
|
5. Окна машины: формы, обновление клиента, остановка графиков при закрытии.
|
|
6. Роли: обычный пользователь видит в меню и списке только свои машины.
|
|
7. Регрессия: PIN, ключи доступа, установщик, редактор SQLite, перенос на другие машины, прямой адрес.
|
|
|
|
## Версия и документация
|
|
|
|
Версия 0.1.3. README — разделы о рабочем пространстве, файлах по SSH и перетаскивании.
|