Файловый менеджер в admin-панели

21.05.2026
Файловый менеджер в admin-панели

До этого, чтобы посмотреть или поправить конфигурационный файл внутри контейнера, нужно было делать docker exec -it container_name bash и работать в терминале. Для одного файла — терпимо. Для нескольких, или когда нужно что-то скопировать между директориями, загрузить новый конфиг или посмотреть что лежит в папке с логами — это уже раздражает. Я сделал файловый менеджер прямо в admin-панели.


Браузер файловой системы

Интерфейс разделён на две панели. Левая — список файлов и папок в текущей директории, правая — содержимое выбранного файла. Сверху — панель инструментов с хлебными крошками и кнопками действий.

Хлебные крошки показывают текущий путь в виде кликабельных сегментов: root / app / config. Каждый сегмент — это кнопка, клик по которой сразу переходит на этот уровень. Последний сегмент не кликабелен — это текущее местоположение.

Список файлов отсортирован: сначала идут папки, затем файлы, внутри каждой группы — по алфавиту. Это поведение, к которому привыкаешь за годы работы с любым файловым менеджером — папки всегда наверху. У каждой строки три колонки: имя с иконкой, дата последнего изменения и размер. У папок размер не отображается — только прочерк, потому что для директории размер метаданных не несёт смысла. У файлов размер адаптируется: байты, KB или MB в зависимости от порядка числа.

Корнем файловой системы служит переменная окружения FILES_ROOT — по умолчанию /app. Именно здесь начинается файловый менеджер, никакой другой части файловой системы хоста он не видит. Все пути передаются относительными от этого корня — абсолютные пути на клиент никогда не уходят.


Безопасность: path traversal

Все операции с файлами на бэкенде проходят через единую валидацию пути. Входящий путь нормализуется: убираются .., лишние слеши и прочие артефакты. Затем строится абсолютный путь и проверяется, что он находится строго внутри FILES_ROOT. Если нет — запрос отклоняется с кодом 403.

Любая попытка выйти за пределы разрешённой директории через ../../etc/passwd, //root/ или процентное кодирование — не проходит. Проверка выполняется на каждом эндпоинте, в том числе для пути назначения при копировании и переносе.


Просмотр файлов

Клик по файлу в списке открывает его содержимое в правой панели. Два ограничения. Первое: если файл весит больше 5 МБ — показывается сообщение об ошибке. Текстовый редактор для полугигабайтного лога — плохая идея. Второе: бинарные файлы — .png, .zip, скомпилированные бинари — не открываются как текст; вместо этого отображается сообщение «Binary file — cannot display as text». Отображать байты как текст бессмысленно.

В шапке правой панели — имя файла, бейдж с расширением и три кнопки: «Скачать», «Редактировать», «Удалить». Кнопка «Редактировать» не отображается для графических файлов — редактировать изображение как текст не имеет смысла.


Просмотр изображений

Если выбранный файл — изображение (jpg, jpeg, png, gif, webp, svg, bmp, ico, tif, tiff, avif), в правой панели вместо текстового редактора показывается само изображение.

Загрузка изображения проходит с авторизацией — скачать файл напрямую через URL без токена нельзя. Изображение запрашивается как двоичный поток с нужным заголовком авторизации, после чего браузер показывает его внутри интерфейса. При переключении на другой файл или переходе в другую директорию ресурсы освобождаются.

Изображение показывается с сохранением пропорций — вписывается в доступное пространство правой панели.


Редактирование файлов

По кнопке «Редактировать» правая панель переходит в режим редактирования. Это переключение с визуальным сигналом: шапка меняет фоновый цвет, появляется бейдж «Редактирование» с иконкой карандаша, под шапкой добавляется тонкая цветная полоса — акцентный цвет темы. Кнопки меняются: вместо «Редактировать» появляются «Сохранить» и «Отменить».

«Отменить» не делает никакого запроса — просто восстанавливает последнее загруженное содержимое файла и закрывает режим редактирования. «Сохранить» записывает изменения на диск. Если сохранение прошло успешно, режим редактирования закрывается.


CodeMirror 6

Текстовый просмотр и редактирование реализованы через CodeMirror 6 — один из самых зрелых редакторов кода для браузера. В нём работает весь набор функций, к которому привыкаешь в десктопных IDE.

Редактор включает номера строк, гаттер для сворачивания блоков кода, историю изменений с отменой и повтором, подсветку парных скобок, автозакрытие скобок, автодополнение, подсветку активной строки, подсветку всех вхождений выделенного текста и перенос длинных строк. Поиск по файлу — стандартным сочетанием Ctrl+F. Tab вставляет отступ.

Маркеры сворачивания блоков

Маркеры в гаттере — SVG-шевроны вместо текстовых символов. Открытый блок — шеврон вниз, свёрнутый — шеврон вправо. Выглядит аккуратно и работает независимо от высоты строки.

Определение языка

Язык для подсветки синтаксиса определяется автоматически по расширению файла. Поддерживаются: JavaScript и TypeScript во всех вариантах (js, mjs, cjs, ts, jsx, tsx), CSS и препроцессоры (css, scss, less), разметка (html, vue, htm), форматы данных (json, jsonc, yaml, yml), документация (md), Python, SQL, XML и SVG. Файлы с неизвестным расширением открываются без подсветки — просто текст.


Операции с файлами

Копирование и вырезание

Кнопки «Копировать» и «Вырезать» доступны через контекстное меню правой кнопкой мыши. После выбора операции файл или папка попадает во внутренний буфер обмена.

Как только буфер не пуст, в панели инструментов появляется кнопка «Вставить» с указанием режима: «Вставить (копия)» или «Вставить (перемещение)». Кнопка цветная — выделяется на фоне остальных инструментов, чтобы напомнить, что буфер обмена активен.

При наведении на кнопку «Вставить» появляется тултип с деталями: режим операции, имя файла и полный путь. Если в буфере несколько объектов — имена перечислены через запятую.

Рядом с текстом кнопки — крестик для сброса буфера. Передумал — нажал крестик, буфер очищается, кнопка исчезает. Без этой кнопки единственный способ сбросить операцию — выполнить вставку куда попало.

Вставка

Клик «Вставить» копирует или переносит все объекты из буфера в текущую директорию. Копирование работает для файлов и папок с любой глубиной вложенности. Перенос сохраняет структуру, а при попытке перенести между разными файловыми системами — автоматически переключается на копирование с удалением оригинала.

После вставки буфер обмена обнуляется и директория перезагружается.

Переименование

Кнопка «Переименовать» открывает модальное окно с полем ввода, предзаполненным текущим именем файла или папки. Enter подтверждает, Escape закрывает. Кнопка подтверждения заблокирована, пока поле пустое. Работает одинаково и для файлов, и для папок.

Удаление

Перед удалением показывается модальное окно с подтверждением. Для одиночного файла — его имя и предупреждение о необратимости. Для папки добавляется предупреждение: «Папка и всё её содержимое будут удалены». При групповом удалении в окне отображается список всех выбранных элементов с иконками.

Никакого браузерного confirm() — диалог встроен в интерфейс. Это принципиально: браузерный диалог выглядит инородно и не позволяет показать детали операции. Папка удаляется рекурсивно со всем содержимым в один запрос.


Создание файлов и папок

Новый файл

Кнопка «Новый файл» в панели инструментов открывает модальное окно с полем ввода имени. Подсказка в поле — «например, index.js» — намекает, что расширение влияет на подсветку синтаксиса. Enter создаёт файл, Escape закрывает.

После создания файл сразу открывается в правой панели в режиме редактирования — ждать дополнительного клика не нужно. Не нужно сначала создавать файл, потом искать его в списке и только потом нажимать «Редактировать».

Новая папка

Кнопка «Новая папка» — аналогичное модальное окно с одним полем для имени. После создания директория перезагружается.


Скачивание файла

«Скачать» в шапке правой панели загружает текущий файл. Скачивание проходит с авторизацией — напрямую через URL без токена файл не скачать. Браузер сохраняет файл с правильным именем и не пытается его открыть во вкладке.


Загрузка файлов

Загрузка открывается в модальном окне по кнопке «Загрузить» в панели инструментов.

Слоты для файлов

По умолчанию в попапе пять строк — пять слотов для файлов. Каждый слот — кнопка «Выбрать файл...», которая открывает системный диалог выбора файла. После выбора строка показывает имя файла и его размер. Рядом с каждой строкой — кнопка удаления. Если файл передумали загружать — убираем его из списка, не закрывая попап.

Кнопка «+» добавляет ещё один слот. Нажимать можно сколько угодно раз. Это нужно, когда нужно загрузить больше пяти файлов из разных директорий, которые нельзя выбрать одним системным диалогом.

Drag and drop

В верхней части попапа — зона перетаскивания. Перетащить сюда можно как отдельные файлы, так и папку целиком. При наведении с файлом зона меняет стиль — рамка из пунктирной становится сплошной с акцентным цветом, фон чуть светлеет.

Если перетащить папку — она обходится рекурсивно: все вложенные файлы на всех уровнях вложенности добавляются в список загрузки с сохранением структуры поддиректорий. Папка с сотнями файлов и несколькими уровнями вложенности загрузится целиком и воспроизведётся на сервере в точно такой же структуре.

Загрузка

После подбора файлов — кнопка «Загрузить (N)», где N — количество файлов в очереди. Кнопка неактивна, если ни один файл не выбран, и пока идёт загрузка.

Файлы загружаются последовательно. Прогресс отображается полосой и счётчиком «X / N файлов загружено». После завершения окно закрывается, директория перезагружается. Лимит — 100 МБ на файл.


Мульти-селект и групповые операции

Выделение

Обычный клик по файлу или папке открывает его содержимое в правой панели — стандартное поведение. Но можно выделять несколько элементов.

Ctrl+Click (или Cmd+Click на Mac) добавляет элемент к выделению или убирает его, если он уже выделен. Shift+Click выделяет диапазон от последнего кликнутого элемента до текущего — как в любом нормальном файловом менеджере. Каждый элемент в режиме выделения показывает чекбокс слева от имени; в обычном режиме чекбоксы скрыты, но появляются при наведении.

Action bar

Когда выделен хотя бы один элемент, под панелью инструментов появляется action bar. В нём три кнопки: «Копировать», «Вырезать», «Удалить». «Снять выделение» — справа.

«Копировать» и «Вырезать» кладут все выделенные объекты в буфер обмена — с тем же механизмом тултипа, что и для одиночных файлов. Если в буфере несколько элементов, тултип показывает количество: «5 элементов» вместо одного имени.

«Удалить» открывает модальное окно со списком всех выделенных элементов — чтобы было видно, что именно будет удалено. Удаление идёт последовательно для каждого элемента.


Контекстное меню

Правая кнопка мыши на любом файле или папке открывает контекстное меню с четырьмя пунктами: «Копировать», «Вырезать», «Переименовать», «Удалить». Клик в любом другом месте закрывает меню. Меню открывается точно под курсором.

Читать далее

21.05.2026

Терминал в браузере: вкладки, история команд и избранное прямо в admin-панели

Добавил полноценный веб-терминал в admin-панель — интерактивная bash-сессия прямо в браузере, до пяти вкладок одновременно, история и избранное с поиском, состояние сохраняется при переключении между разделами.

Метки
terminaladmin-panelweb-terminalbashdeveloper-tools
22.05.2026

@macrulez/vue-form-schema: реактивные формы из схемы для Vue 3

Написал пакет, который избавляет от бойлерплейта при работе с формами во Vue 3: описываешь поля в виде массива объектов — получаешь готовую валидацию, маскирование, условное отображение и автоматический рендеринг.

Метки
vue3formsvalidationtypescriptcomposable
23.05.2026

vue-virtual-scroller-kit — виртуализация списков для Vue 3 без компромиссов

Написал пакет для виртуализации списков, таблиц, сеток и деревьев во Vue 3 с динамической высотой строк, группировкой, drag-to-reorder и полной поддержкой SSR — без внешних зависимостей.

Метки
vue3virtualizationperformancefrontendopensource