AG Grid Community: таблицы заявок — 9 сценариев и мастерская
Девять сценариев работы с таблицами заявок: поиск, фильтры, редактирование, выбор строк, transactions, страницы, личный вид, CSV и HTTP. Живая мастерская и готовые исходники.

В сервисной компании заявки быстро перестают помещаться в простой список. Нужно найти клиента, сравнить сроки, передать несколько задач исполнителю, исправить бюджет и выгрузить результат. Если для каждого действия открывать отдельную страницу, оператор тратит время на переходы. Рабочая таблица позволяет держать контекст перед глазами и выполнять короткие операции прямо в списке.
AG Grid Community помогает собрать такой интерфейс на JavaScript. Здесь девять работающих сценариев, мини-мастерская со связанными данными, русские подписи и исходники. Вы попробуете фильтры, штатные редакторы ячеек, массовую обработку, транзакции обновления, сохранение представления и CSV. Отдельный пример действительно получает JSON по HTTP, показывает ошибку и восстанавливается после повторной загрузки. Затем разберём подключение к своему приложению, запуск на Windows и Linux и размещение готовых файлов на VPS.
Что такое AG Grid и какую работу она берёт на себя
AG Grid — компонент для работы с табличными данными в браузере. Вы передаёте массив объектов и описание колонок, а библиотека строит строки, управляет сортировкой, фильтрами, фокусом, редакторами и обновлением отображения. В нашем проекте используется обычный JavaScript без обязательного React, Vue или Angular. Поэтому мастерскую можно запустить самостоятельно или встроить в существующий кабинет на PHP.
Полезно сразу разделить обязанности. Таблица знает, как отобразить бюджет, открыть редактор и найти строки по условию. Она не знает, разрешено ли конкретному сотруднику менять договор, принят ли платёж и кто отвечает за конфликт двух одновременных правок. Эти решения принимает ваше приложение. После подключения API библиотека остаётся интерфейсом над данными, а источник достоверного состояния находится на сервере.
При выборе строки можно открыть подробности рядом; после фильтрации увидеть количество найденного; при массовой операции понять, сколько заявок изменится. Такие связи между элементами обычно важнее максимально насыщенной панели инструментов. Начальное подключение описано в официальной документации AG Grid.
Где полезна рабочая таблица и как выбрать инструмент
Подход подходит диспетчерской, обработке обращений, реестру договоров, списку оборудования, складским остаткам и внутреннему каталогу услуг. Общая черта — одинаковая структура записей и регулярные короткие операции над несколькими полями. Пользователь часто возвращается к списку, сравнивает соседние строки и предпочитает клавиатуру долгому открытию карточек.
Для небольшой публичной таблицы может хватить обычного HTML. Для сложной формы с двадцатью взаимозависимыми полями отдельная карточка зачастую понятнее редактирования ячеек. Выбирайте инструмент по сценарию человека: какие данные он сравнивает, что меняет, как часто ошибается и каким должен быть результат действия.
На сайте есть мастерская Tabulator. Здесь фокус другой: очередь заявок с явными идентификаторами, проверкой изменений, состоянием колонок, безопасной выгрузкой и обработкой неудачной загрузки. Сравнивайте инструменты на своей схеме данных и нужной редакции, а не только по внешнему виду демонстрации. Лицензия требуемой функции и стоимость сопровождения собственного renderer тоже влияют на выбор.
Мини-мастерская: девять сценариев на одной странице
Начните с рабочей очереди: введите название клиента «Маяк», нажмите заголовок бюджета и откройте подробности строки. Затем переключитесь на редактирование или массовое действие. Под каждым вариантом есть пояснение применения и короткое задание. Счётчики отражают настоящий набор строк, а журнал показывает выполненные операции человеческим языком.
В основной базе сто восемьдесят вымышленных заявок: разные услуги, исполнители, статусы, приоритеты и бюджеты. Даты закреплены в ноябре 2026 года, чтобы примеры фильтров оставались воспроизводимыми. Сценарий загрузки получает второй набор из шестидесяти строк. Переключение сценария и кнопка сброса возвращают исходные данные; изменения не отправляются в CRM и не сохраняются между посещениями.
На телефоне таблица прокручивается внутри своей рамки. Ниже доступна полная карточка выбранной заявки и крупные элементы управления. Если встроенная область тесна, откройте мастерскую отдельной страницей. После эксперимента можно скачать текущий пример HTML, данные JSON, настройки вида или полный проект — у каждого варианта своё назначение.
Версия, лицензия и граница Community / Enterprise
В проекте зафиксирована AG Grid Community 36.3.0 с лицензией MIT. Официальная русская локаль имеет ту же версию, оформление внешних элементов использует Bootstrap 5.3.8. Браузерные файлы лежат в архиве локально: демонстрация не зависит от загрузки JavaScript с внешнего CDN. Тексты лицензий основных и транзитивных браузерных зависимостей собраны в отдельный файл.
Все девять сценариев используют Community: сортировку, текстовые, числовые и календарные фильтры, штатные редакторы, выбор строк, клиентскую пагинацию, обновления и CSV. Платные возможности не подключены. Важно различать CSV и готовую выгрузку Excel, выбор строк и диапазона ячеек, обычный выпадающий редактор и Rich Select.
Группировка, сводные таблицы, Server-Side Row Model, Set Filter, Advanced Filter, Excel Export и другие Enterprise-возможности требуют отдельной оценки лицензии. В официальных примерах могут встречаться одновременно бесплатные и платные модули. При переносе кода смотрите импорты и отметку редакции возле функции. Границы приведены в сравнении Community и Enterprise.
Минимальное подключение: контейнер и настоящий экземпляр
Готовая браузерная сборка предоставляет объект agGrid. Для новой системы оформления используется вариант noStyle: он не добавляет старые CSS-темы, конфликтующие с Theming API. Контейнеру требуется определённая высота; иначе библиотека получит пустую область, хотя JavaScript уже выполнился. В мастерской высота меняется для мобильного экрана, но остаётся ограниченной.
Маленький пример ниже можно сохранить в public/ полного проекта. Он использует тот же локальный vendor-файл. После создания сохраняйте возвращённый API: через него приложение меняет данные и состояние. При удалении экрана экземпляр необходимо уничтожить, чтобы освободить обработчики и служебные элементы.
Если вы используете сборщик, доступен модульный импорт и регистрация Community-модулей. Архив оставляет простой браузерный вариант: читателю достаточно открыть файлы, понять структуру и запустить локальный HTTP-сервер. Это не мешает позднее перенести конфигурацию в компонент своего приложения. Код и данные таблицы остаются обычными объектами JavaScript.
<div id="grid" style="height:430px"></div>
<script src="./vendor/ag-grid-community.min.noStyle.js"></script>
<script>
const api = agGrid.createGrid(document.querySelector('#grid'), {
theme: agGrid.themeQuartz,
rowData: [{id:'REQ-1001', client:'Маяк', budget:12000}],
columnDefs: [
{field:'client', headerName:'Клиент', filter:true},
{field:'budget', headerName:'Бюджет', filter:'agNumberColumnFilter'}
],
getRowId: params => params.data.id
});
</script>
Данные: постоянный ID, настоящие числа и календарная дата
Строка должна иметь постоянный идентификатор, не зависящий от текущего порядка. После сортировки первая строка станет другой, но заявка останется той же. Поэтому getRowId возвращает поле id. Массовое действие, карточка и точечное обновление обращаются к записи по этому ключу. Индекс массива для такой связи ненадёжен.
Бюджет хранится числом, а знак валюты добавляется при отображении. Если хранить текст «12 000 ₽», фильтрация, суммирование и экспорт потребуют обратного разбора строки. Срок хранится как календарное значение YYYY-MM-DD: это день выполнения, а не момент события в часовом поясе. Для журнала изменений понадобился бы отдельный timestamp с определёнными правилами времени.
Перед загрузкой проверяются структура, уникальность идентификаторов, перечисления статусов и диапазоны. Учебный предел — тысяча строк, бюджет до миллиона рублей, часы до тысячи, прогресс от нуля до ста. Эти числа ограничивают демонстрацию, а не возможности AG Grid. В рабочем проекте ограничения должны следовать договорённостям API.
const row = {
id:'REQ-1001', client:'Маяк', service:'Настройка сайта',
status:'Новая', owner:'Анна', priority:'Высокий',
budget:12000, hours:4, due:'2026-11-12', progress:0
};
const gridOptions = {getRowId: params => params.data.id, rowData:[row]};
Описание колонок: значение, формат и поведение
Описание колонки соединяет поле данных с тем, как человек видит и меняет его. Здесь задаются подпись, ширина, тип фильтра, форматирование и редактор. Не обязательно разрешать редактирование всему реестру: в примере меняются только статус, исполнитель и бюджет. Идентификатор остаётся служебным ключом, остальные поля помогают разобраться в заявке.
Форматирование не должно разрушать исходное значение. Денежная колонка показывает рубли, но внутри сохраняет число. Текстовый renderer статуса создаёт обычный DOM-элемент и записывает значение через textContent. Поэтому внешнее поле не превращается в произвольную HTML-разметку. Если нужны цвет и иконка, добавляйте их явно, оставляя пользовательский текст текстом.
Не уменьшайте все колонки до размера экрана: получаются обрезанные заголовки и непонятные значения. Лучше оставить разумную минимальную ширину, внутреннюю прокрутку и предложить компактный вид или карточку. В мастерской эти способы дополняют друг друга, сохраняя полноценную таблицу для большого монитора.
const budgetColumn = {
field:'budget', headerName:'Бюджет, ₽',
cellDataType:'number', filter:'agNumberColumnFilter',
valueFormatter:p => Number(p.value).toLocaleString('ru-RU') + ' ₽',
useValueFormatterForExport:false, minWidth:140, width:160
};
Сценарий 1: рабочая очередь, поиск и приоритет
Диспетчеру нужно найти обращения одного клиента и понять, какие выполнять первыми. Быстрый поиск сокращает набор, сортировка бюджета или срока помогает сравнить строки, а кнопка приоритетов применяет заранее определённый порядок. Высокий приоритет должен идти раньше обычного и низкого; алфавитная сортировка названий здесь не подходит.
Для приоритета задан собственный comparator. Затем применяется сортировка по приоритету и сроку. Аналогично можно упорядочить стадии согласования, категории срочности или размеры одежды. Храните понятное соответствие значений и не зависите от случайного порядка переведённых подписей.
Быстрый поиск работает с уже полученными данными. Человек видит счётчик остатка и может очистить условия. Карточка связана с текущим набором: если фильтр исключил выбранную заявку, показывается доступная строка, а при пустом результате — объяснение. Это помогает отличить корректное отсутствие совпадений от сбоя приложения. Устройство поиска описано в документации Quick Filter.
api.setGridOption('quickFilterText', 'Маяк');
api.applyColumnState({
state:[{colId:'priority',sort:'asc'},{colId:'due',sort:'asc'}],
defaultState:{sort:null}
});
Сценарий 2: несколько условий без отдельного отчёта
Менеджеру нужны заявки в работе с бюджетом от двадцати тысяч рублей и сроком до середины месяца. Вместо отдельных экранов приложение задаёт модель фильтров. Пользователь видит результат сразу, может добавить текстовый поиск и проверить количество строк. Такая предустановка удобна для регулярной задачи с понятным названием.
Условия разных колонок объединяются. Статус сравнивается как текст, бюджет проходит числовое условие, срок — календарное. Ошибка типа здесь опаснее ошибки цвета: строковое сравнение суммы способно дать правдоподобный, но неверный результат. Поэтому колонкам назначаются подходящие типы, а JSON проверяется до передачи библиотеке.
Попробуйте предустановку бюджета и статуса, затем поиск по клиенту. Пустая таблица может быть корректным результатом. Интерфейс не должен показывать старые строки или сообщение о поломке. Сброс очищает поиск, фильтры и сортировку, делая возвращение к исходному набору очевидным. В рабочем продукте полезно также подписать активные предустановки, чтобы условия оставались заметными.
api.setFilterModel({
status:{filterType:'text',type:'equals',filter:'В работе'},
budget:{filterType:'number',type:'greaterThanOrEqual',filter:20000},
due:{filterType:'date',type:'lessThan',dateFrom:'2026-11-16 00:00:00'}
});
// Убрать условия колонок:
api.setFilterModel(null);
Сценарий 3: редакторы ячеек и понятная проверка
Здесь можно изменить статус, исполнителя и бюджет. На компьютере редактор открывается двойным щелчком или клавишами Enter/F2. На телефоне удобнее выбрать заявку и воспользоваться формой ниже: она меняет те же данные, но не требует точного попадания. Это два пути к одной операции, а не независимые наборы значений.
Бюджет использует штатный числовой редактор с диапазоном и дополнительную проверку при записи. Отрицательная или слишком большая сумма не должна попасть в набор при необычном вводе. После правки счётчики и карточка используют обновлённые числа. Сообщение подчёркивает, что изменение выполнено локально.
Отмена и повторение относятся к истории редактора ячеек. Внешняя форма обновляет строку через transaction и не обещает такую же историю. На сервере отмена принятого изменения потребует отдельной операции и проверки версии записи. Локальный Undo не восстанавливает бизнес-данные в базе. Подробности доступны в документации проверки редакторов.
const editableBudgetColumn = {
field:'budget', editable:true,
cellEditor:'agNumberCellEditor',
cellEditorParams:{min:0,max:1000000,precision:0},
valueSetter(params) {
const amount = Number(params.newValue);
if (!Number.isFinite(amount) || amount < 0 || amount > 1000000) return false;
params.data.budget = Math.round(amount);
return true;
}
};
Сценарий 4: выбранные строки и массовая передача
Рабочая очередь требует обрабатывать несколько записей одинаково: передать исполнителю, назначить статус или сформировать подборку. Здесь важно показывать точный объём операции. Чекбокс в заголовке и кнопка первых трёх строк работают с текущим фильтром, а счётчик выбора показывает количество и сумму бюджета выбранного набора.
После выбора фильтр можно изменить. Ранее отмеченные записи остаются выбранными, даже если перестали отображаться. В мастерской массовая передача работает со всеми выбранными заявками. Это поведение нужно проговорить пользователю, особенно перед необратимым действием. Для опасной операции добавьте предварительный список, подтверждение и серверный результат по каждой записи.
Демонстрационная кнопка назначает Ирину и статус «В работе». Обновляются только выбранные строки. При подключении backend отправляйте идентификаторы и разрешённые поля. Сервер самостоятельно проверяет права на каждую заявку; наличие чекбокса не доказывает доступ. Настройки выбора описаны в документации Multi-Row Selection.
const updates = api.getSelectedRows().map(row => ({
...row, owner:'Ирина', status:'В работе'
}));
api.applyTransaction({update:updates});
// При необходимости явно очистить выбор:
api.deselectAll();
Сценарий 5: добавить, обновить и удалить через transaction
Новая заявка не должна пересоздавать весь экран. Метод applyTransaction принимает добавления, изменения и удаления. Благодаря постоянному ID библиотека связывает обновлённый объект с существующей строкой. Пользователь сохраняет контекст таблицы, а приложение выполняет небольшое понятное изменение. Подробности механизма приведены в официальном описании transactions.
В мастерской можно добавить заявку, поднять её бюджет и удалить только добавленную строку. Журнал сообщает идентификатор, счётчик показывает фактический результат. Если активный фильтр скрывает новую запись, сообщение объясняет её отсутствие на экране. Кнопки операций отключаются, когда добавленной заявки ещё нет.
В приложении различайте успешный ответ сервера и получение повторного события. Уведомление о той же заявке должно обновить существующий ID, а не создать дубликат. При частых событиях объединяйте изменения в пачки. Transactions управляют клиентским отображением; гарантии доставки, порядок сообщений и повторы относятся к вашему протоколу обмена.
api.applyTransaction({add:[newRequest],addIndex:0});
api.applyTransaction({update:[{...newRequest,budget:13500}]});
api.applyTransaction({remove:[{id:newRequest.id}]});
Сценарий 6: страницы и реальный объём данных
Пагинация помогает просматривать набор частями. Можно выбрать десять, двадцать пять или пятьдесят строк, перейти вперёд и назад, затем ограничить список фильтром. Номер страницы берётся из настоящего API. Когда строк нет, кнопки отключаются и появляется понятное состояние. Настройки доступны в документации пагинации.
Это клиентская пагинация: весь набор уже в браузере. Изменение размера страницы не уменьшает объём скачанного JSON. Решение подходит умеренному списку, но его нельзя выдавать за масштабирование до миллионов записей. Большой набор потребует серверного поиска, ограничений, курсора, постраничных запросов или подходящей модели данных.
Договоритесь о стабильной сортировке и границах страницы в API. Если новые заявки появляются сверху, переход по номерам может показывать повторяющиеся или пропущенные записи. Это вопрос контракта данных, а не размера кнопки «Далее». Здесь набор фиксирован, поэтому пользователь изучает механику без фоновых изменений.
api.setGridOption('paginationPageSize',25);
api.paginationGoToNextPage();
const current = api.paginationGetCurrentPage() + 1;
const total = api.paginationGetTotalPages();
console.log(`Страница ${current} из ${total}`);
Сценарий 7: личный вид таблицы и снимок настроек
Разным сотрудникам нужны разные поля. Диспетчер смотрит клиента и статус, руководитель — бюджет и сроки, исполнитель — услугу и ответственного. Одинаковый перегруженный экран неудобен. Состояние колонок позволяет запомнить ширину, порядок, видимость и сортировку, а модель фильтров дополняет представление.
Есть короткий вид, переключение бюджета и возвращение всех колонок. Сохраните представление, измените его и восстановите. Снимок хранится в памяти сценария; при сбросе исчезает. Для изучения структуры его можно скачать в JSON. Автоматического сохранения профиля и обратного импорта файла здесь нет. Методы описаны в Column State API.
В реальном сервисе настройки можно связать с пользователем на сервере. Добавляйте версию схемы: после переименования поля старое представление может стать неполным. Восстанавливайте известные идентификаторы колонок и допустимые фильтры. Настройка удобства не должна менять серверное разрешение на чтение поля.
const savedView = {
version:1, columns:api.getColumnState(),
filters:api.getFilterModel(), pageSize:api.paginationGetPageSize()
};
api.applyColumnState({state:savedView.columns,applyOrder:true});
api.setFilterModel(savedView.filters);
api.setGridOption('paginationPageSize',savedView.pageSize);
Сценарий 8: CSV, фильтры и защита от формул
Выгрузка нужна для передачи и сверки данных. CSV содержит все строки после фильтра и сортировки либо выбранную часть этого результата. Это не только текущая страница. Колонки заданы явно, поэтому скрытие бюджета в представлении не удаляет его из файла. Такое поведение нужно обозначать заранее, особенно для чувствительных данных.
Числа выгружаются без знака валюты, разделитель — точка с запятой, кодировка — UTF-8 с BOM. Офисная программа может по-своему определить формат даты или ID. Для ответственной передачи задайте правила импорта и проверьте файл в целевом приложении. CSV не хранит оформление и типы так же, как специализированный формат.
Текст с начальным равенством, плюсом, минусом, @ или управляющими символами может стать формулой в табличном редакторе. Кнопка теста добавляет безвредную учебную строку, экспорт предваряет опасное начало апострофом. Это защита на границе выгрузки; в интерфейсе значение остаётся текстом. Ограничения описаны в документации CSV Export.
function safeCsvCell(value) {
const text = String(value ?? '');
return /^[\s]*[=+\-@]|^[\t\r\n]/.test(text) ? "'" + text : text;
}
const csv = api.getDataAsCsv({
columnKeys:['id','client','service','status','owner','priority','budget','hours','due'],
exportedRows:'filteredAndSorted',columnSeparator:';',
processCellCallback:p => safeCsvCell(p.value)
});
Сценарий 9: настоящий HTTP, ошибка и повторная попытка
Кнопка загрузки получает data/requests.json обычным fetch. Это реальный HTTP-запрос к серверу страницы. Вторая кнопка обращается к отсутствующему файлу и получает настоящий 404. Состояние ошибки возникает из ответа запроса. Повторная успешная попытка возвращает шестьдесят строк второго набора.
Во время загрузки старые данные очищаются, затем проверяется структура ответа. При неудаче таблица остаётся пустой, экспорт отключается, сообщение предлагает повторить действие. Это выбранная политика: пользователь не должен принять прошлые данные за свежий результат. В другом продукте можно сохранять старые строки, явно показывая возраст и статус.
Быстрые нажатия требуют защиты от запоздавшего ответа. Предыдущий запрос отменяется через AbortController, номер поколения дополнительно не позволяет старому результату заменить новый. При уходе со сценария запрос прекращается. Такая логика пригодится поиску и зависимым спискам. Проверка только успешного ответа не обнаружит эту проблему: воспроизводите задержку и смену выбора во время ожидания.
const controller = new AbortController();
api.setGridOption('rowData',[]);
api.setGridOption('loading',true);
try {
const response = await fetch('./data/requests.json',{signal:controller.signal});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
api.setGridOption('rowData',validateRows(await response.json()));
} finally {
api.setGridOption('loading',false);
}
// Полная мастерская также обрабатывает ошибку и гонку запросов.
Оформление: современная тема и осмысленные акценты
Тема должна помогать читать данные. Здесь светлый фон, спокойный заголовок, заметный фокус и текстовые статусы. Цвет дополняет название: смысл не исчезает при слабом различении оттенков. Высота строки оставляет место для касания, границы помогают удерживать взгляд на нужной записи.
Современная тема передаётся объектом через theme. Используется сборка noStyle, чтобы не смешивать новую систему со старыми CSS-темами. Не добавляйте старый ag-grid.css только потому, что он встретился в давнем примере. Bootstrap оформляет окружающие кнопки и формы, Theming API — внутреннюю таблицу. Подход описан в официальной документации оформления.
Шрифты системные: не требуется внешняя загрузка гарнитуры. В кабинете сначала проверьте длинные русские подписи, числа и выделение. Изменять десятки внутренних CSS-селекторов хрупче, чем использовать параметры темы и классы собственных элементов. После обновления библиотеки такие точечные переопределения требуют дополнительного внимания.
const theme = agGrid.themeQuartz.withParams({
fontFamily:'system-ui, sans-serif',fontSize:14,
accentColor:'#087b6c',backgroundColor:'#ffffff',
headerBackgroundColor:'#e8f2eb',borderColor:'#c9ded2'
});
// В options: {theme,loadThemeGoogleFonts:false}
Клавиатура, русские подписи и уменьшение движения
Стрелки перемещают фокус по ячейкам, Enter или F2 запускают доступный редактор, Space помогает выбрать строку. Рядом остаются обычные кнопки и форма. У таблицы есть доступное название, сообщения выводятся в области status. Официальная русская локаль переводит внутренние подписи библиотеки.
Анимация перестановки строк помогает видеть изменение порядка, но не всем комфортна. Проект учитывает prefers-reduced-motion и меняет animateRows при смене настройки устройства. Сортировка, фильтрация и действия работают так же. Уменьшение движения не должно отключать функциональность или лишать человека результата операции.
Виртуализированная таблица требует проверки с целевой программой экранного доступа. Наличие ARIA не гарантирует удобство везде. Пройдите задачи клавиатурой, проверьте ошибки, возврат фокуса и полную карточку. Она остаётся обычным читаемым HTML. Полезны рекомендации по доступности и локализации.
const media = matchMedia('(prefers-reduced-motion: reduce)');
api.setGridOption('animateRows',!media.matches);
media.addEventListener('change',event => {
api.setGridOption('animateRows',!event.matches);
});
api.setGridAriaProperty('label','Учебные заявки сервисной команды');
Мобильный экран: таблица и карточка дополняют друг друга
Девять колонок невозможно уместить в узкую область, сохранив читаемость. Поэтому таблица получает внутреннюю горизонтальную прокрутку, а страница сохраняет ширину. Снизу находится карточка со всеми полями текущей заявки. Выпадающий список позволяет выбрать запись без длинного перемещения вправо и влево.
Короткий вид из клиента и статуса полезен для быстрого просмотра. Остальные сведения не исчезают из данных и остаются в карточке. Отдельная форма избавляет от необходимости точно попадать в ячейку двойным нажатием. Массовые действия имеют крупные кнопки и явный счётчик.
При проверке своего интерфейса смотрите не только отсутствие скролла страницы. Читается ли подпись, виден ли результат, можно ли добраться до ошибочного поля, не закрывает ли экранная клавиатура важную информацию? Эмуляция узкой ширины помогает найти часть проблем; поведение физического телефона и ассистивных технологий требует отдельной проверки. Не запрещайте масштабирование страницы ради сохранения красивой композиции.
.grid-shell {min-width:0;max-width:100%;overflow:hidden;}
.grid {width:100%;height:430px;}
@media (max-width:600px) {
.grid {height:370px;}
.edit-fields {grid-template-columns:1fr;}
}
Подключение к PHP или Node.js: кто сохраняет изменения
Мастерская не пишет данные на сервер. Для кабинета понадобится API чтения и изменения. Backend может быть на PHP, Node.js или другом стеке: библиотека получает JSON и не требует конкретного языка. Для PHP проверку входных данных можно выстроить по материалу о Symfony Validator.
Есть две стратегии сохранения. При осторожной сначала отправляется запрос, затем подтверждённое значение попадает в таблицу. При оптимистичной значение видно сразу, рядом появляется ожидание, при отказе — восстановление или конфликт. Выбор зависит от стоимости ошибки. Для финансового поля необъяснимое исчезновение введённого значения особенно неприятно.
Передавайте ID, разрешённые поля и известную версию. Сервер проверяет сессию, права, CSRF для cookie-аутентификации, типы и актуальность версии. При конфликте покажите, что запись уже изменена другим сотрудником. Ответ должен возвращать каноническое состояние, чтобы клиент не вычислял его по догадке. Ниже пример контракта будущего API: в архиве такого endpoint нет.
const response = await fetch(`/api/requests/${encodeURIComponent(id)}`,{
method:'PATCH',
headers:{'Content-Type':'application/json','X-CSRF-Token':csrfToken},
body:JSON.stringify({version:knownVersion,changes:{budget:15000}})
});
if (response.status === 409) throw new Error('Запись уже изменена: обновите данные');
if (!response.ok) throw new Error('Сохранение не выполнено');
const savedRow = await response.json();
api.applyTransaction({update:[savedRow]});
Безопасность данных: скрытие поля не является доступом
Если поле пришло в JSON, пользователь браузера может его прочитать независимо от видимости колонки. Backend должен отдавать только сведения, разрешённые текущей роли. Фильтрация улучшает удобство, но не ограничивает права. Отключённая кнопка тоже не защищает endpoint: его можно вызвать отдельным HTTP-клиентом.
Не вставляйте клиентские строки через innerHTML без обработки. В проекте значения карточки экранируются, ячейки статуса используют textContent. Отдельная проверка CSV нужна потому, что безопасный для HTML текст может стать формулой в другой программе. Контекст вывода определяет защиту: одна универсальная замена символов не решает все случаи.
При журналировании не записывайте конфиденциальную строку целиком ради диагностики. Обычно достаточно ID, операции, результата, времени и идентификатора запроса. Срок хранения согласуется с задачей. Учебные данные можно публиковать открыто; реальные базы и токены не должны попадать в скачиваемый HTML, публичный JSON или архив исходников. Проверьте эту границу до замены демонстрационного набора настоящим.
Производительность, обновления и завершение работы
Виртуализация уменьшает количество отображаемых DOM-элементов, но не отменяет стоимость загрузки массива. Тысяча лёгких строк и тысяча строк с тяжёлыми компонентами — разные нагрузки. Начните с простых значений и измерьте поиск, фильтрацию, редактирование и обновление. Плавный скролл пустой таблицы ничего не говорит о скорости сервиса с настоящими данными.
При частых изменениях обновляйте строки по ID и объединяйте близкие события. Избегайте пересоздания экземпляра на каждый символ. В мастерской пересоздание происходит при смене сценария или сбросе, обычные действия идут через API. Это сохраняет связь с карточкой и параметрами.
При уходе вызывайте destroy и отменяйте запросы. Возврат из back-forward cache отличается от закрытия: уничтоженный экземпляр не должен оставаться на восстановленной странице. Проект сохраняет интерфейс при persisted-переходе и освобождает при завершении. В SPA за это отвечает жизненный цикл компонента. Проверяйте несколько быстрых переключений, а не только первый успешный запуск.
window.addEventListener('pagehide',event => {
if (!event.persisted) {
pendingController?.abort();
api.destroy();
}
});
Исходники: HTML, JSON и полный ZIP решают разные задачи
HTML включает выбранный сценарий с текущими учебными строками. Используется та же функция построения интерфейса, что и на странице: пример соответствует показанному поведению. Фильтры, выбор, страница и сохранённое представление при запуске начинают с исходного состояния. Это снимок данных и кода, а не сериализация браузерного сеанса.
Поместите файл в public/ полного проекта рядом с vendor/. Для HTTP-сценария нужен также data/. Одного HTML без зависимостей недостаточно. Такой формат позволяет читать и менять исходник, сохраняя локальные версии библиотек. Запускайте через HTTP, а не двойным щелчком по файлу.
«Данные JSON» выгружает весь загруженный набор независимо от фильтра, с отметкой synthetic. JSON вида содержит настройки колонок и поиска. Полный ZIP включает исходники, готовый public, lock-файл, тесты, сервер разработки и инструкции. Перенося решение, начните со структуры данных и одного сценария, затем добавляйте действия. Не публикуйте скачанный снимок, если уже заменили учебные сведения конфиденциальными.
aggrid-project/
src/ # интерфейс, данные, экспорт
public/ # готовые HTML/CSS/JS/vendor/data
scripts/ # сборка и локальный HTTP
tests/ # проверки настоящей библиотеки
deploy/Caddyfile # пример HTTPS-размещения
package-lock.json
README.md
THIRD-PARTY-LICENSES.txt
Windows: первый запуск и работа с исходниками
Установите Node.js ветки 24 и проверьте версию в PowerShell. Для первого просмотра достаточно распаковать архив и запустить сервер: браузерные зависимости уже включены в public. Команды предполагают ZIP в стандартном каталоге загрузок. При другом расположении замените путь к архиву.
Откройте адрес сервера. Он слушает локальный интерфейс и предназначен для разработки на этом компьютере. Остановка — Ctrl+C. Если порт занят, сначала определите владельца процесса или выберите свободный PORT; не завершайте неизвестные сервисы ради демонстрации. Например, PowerShell позволяет задать переменную окружения PORT перед запуском процесса.
Для изменения исходников выполните npm ci, сборку и тесты из корня проекта. Команда ci использует lock-файл. Ключ ignore-scripts подходит данному набору зависимостей и не мешает явной команде сборки. Обновлённые файлы появляются в public; после перезагрузки страницы сервер отдаёт новую версию. Не редактируйте только готовый public, если планируете повторную сборку: изменения нужно внести в src.
node --version
Expand-Archive -LiteralPath "$env:USERPROFILE/Downloads/aggrid-project.zip" -DestinationPath ./aggrid-demo
Set-Location ./aggrid-demo/aggrid-project
node scripts/server.mjs
# Открыть http://127.0.0.1:8151/; остановить Ctrl+C.
npm ci --ignore-scripts
npm run build
npm test
npm audit
npm start
Linux: локальная разработка и готовая статика
На Linux порядок тот же: распаковать проект, проверить Node.js 24 и запустить сервер. Для машины разработчика не требуется публичный домен. Это удобно для изучения исходников, тестирования контрактов и подготовки своей версии. Команды предполагают установленный Node подходящей версии; случайная старая версия из системного репозитория может не соответствовать проекту.
Для размещения готового public Node не обязателен. Папку может отдавать Caddy, Nginx или существующий веб-сервер приложения. JavaScript выполняется в браузере. PHP понадобится при добавлении API, сессий или серверной проверки доступа, но сама таблица не требует PHP-обработчика для каждого действия.
Не публикуйте весь корень вместо public. В архиве нет секретов, однако выставление наружу тестов и будущих конфигураций создаёт лишние риски. Выделенный каталог делает границу понятной. Для общей схемы окружений пригодится материал о Docker Compose, хотя этой статической мастерской контейнер не обязателен. Сначала определите, кто собирает файлы, а кто только обслуживает результат.
unzip aggrid-project.zip -d aggrid-demo
cd aggrid-demo/aggrid-project
node --version
npm ci --ignore-scripts
npm run build
npm test
node scripts/server.mjs
VPS: домен, HTTPS, доступ и журнал Caddy
Подготовьте домен с DNS-записью на VPS, установите Caddy по официальной инструкции ОС и разрешите входящие соединения на 80 и 443. Копируется только public. Текущая версия доступна через символическую ссылку, позволяющую переключить выпуск без ручной замены файлов. Подробнее сервер разобран в статье про Caddy.
Создайте каталог выпуска, скопируйте public и дайте Caddy право чтения. README содержит команды с владельцем root и группой caddy. Они рассчитаны на установленный пакет с такой группой; при другой установке проверьте пользователя сервиса. Если сервер уже обслуживает сайты, добавляйте блок домена, сохраняя остальные настройки.
Учебную мастерскую можно открыть всем. Внутреннюю панель закройте целиком, включая JSON. Для стенда подходит basic_auth с хешем, полученным интерактивной командой caddy hash-password. Для CRM нужны собственные пользователи и права на API. Не помещайте реальный пароль в JavaScript, URL или историю команд. Проверьте ответ 401 без учётных данных и для страницы, и для файла данных.
grid.example.com {
root * /srv/aggrid/current/public
encode zstd gzip
file_server
header X-Content-Type-Options nosniff
header Referrer-Policy strict-origin-when-cross-origin
log
# Для закрытого стенда добавьте:
# basic_auth {
# team REPLACE_WITH_GENERATED_HASH
# }
}
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -I https://grid.example.com/
sudo journalctl -u caddy --since '15 minutes ago' --no-pager
Официальные инструкции: установка Caddy и basic_auth. Проверьте доступность страницы, JavaScript, стилей и JSON: успешный ответ одного HTML ещё не подтверждает работоспособность интерфейса.
Обновление библиотеки, проверка выпуска и откат
Фиксированная версия делает исходники воспроизводимыми. Перед обновлением прочитайте изменения и миграцию, обновите пакет вместе с локалью и lock-файлом, выполните сборку и тесты. Проверьте пользовательские renderer и API сохранения. Успешная установка npm не подтверждает понятность рабочих действий.
На VPS размещайте новый public в отдельном каталоге releases/r2/public. Проверьте состав и права до переключения current. Команды ниже предполагают подготовленный r2, сохранённый r1 и отсутствие временной ссылки current-next. Переключение статики не требует перезапуска Caddy. Изменённую конфигурацию сервера, напротив, нужно проверить и перечитать.
После выпуска проверьте страницу, загрузку JSON, фильтры, редактирование и скачивание. При проблеме верните ссылку на предыдущий каталог. Схема не отменяет плана миграции базы: у мастерской её нет. После добавления API совместимость старого клиента и нового сервера станет условием отката. Сохраняйте предыдущий выпуск до завершения проверки, а не только до успешного копирования файлов.
sudo ln -s /srv/aggrid/releases/r2 /srv/aggrid/current-next
sudo mv -Tf /srv/aggrid/current-next /srv/aggrid/current
curl -I https://grid.example.com/
# Вернуть сохранённый выпуск r1:
sudo ln -s /srv/aggrid/releases/r1 /srv/aggrid/current-next
sudo mv -Tf /srv/aggrid/current-next /srv/aggrid/current
Что проверяют исходники и как сделать свой инструмент
Десять групп проверок используют настоящую AG Grid Community. Они проверяют структуру данных, фильтры, штатный числовой редактор и отмену, выбор, массовое обновление, transactions, страницы, состояние колонок и CSV. HTTP-проверка поднимает сервер, получает JSON, проходит 404 и повторное восстановление. Отдельный тест запускает сгенерированный HTML с тем же renderer.
Проверяется защита от запоздавшего ответа и завершение экземпляра. JSDOM задаёт геометрию для проверки API, поэтому тесты не доказывают визуальную корректность на телефоне. Для своей версии пройдите действия в браузере на узком экране и клавиатурой. Новая колонка, длинная подпись или сторонний редактор могут изменить удобство при зелёных тестах.
Следующий шаг — заменить учебную схему одной реальной сущностью, определить права и контракт сохранения, оставить частые действия и проверить их с пользователем. Добавляйте возможности по мере появления задачи. Рабочая таблица помогает найти запись, понять состояние и уверенно выполнить действие; эти результаты стоит проверять после каждого изменения.


