diff --git a/ui/src/app/knock/FORM_ARRAY_DOCUMENTATION.md b/ui/src/app/knock/FORM_ARRAY_DOCUMENTATION.md
new file mode 100644
index 0000000..dfa84e2
--- /dev/null
+++ b/ui/src/app/knock/FORM_ARRAY_DOCUMENTATION.md
@@ -0,0 +1,348 @@
+# Документация: FormArray в компоненте KnockPageComponent
+
+## Обзор
+
+В компоненте `KnockPageComponent` используется Angular FormArray для управления динамическими формами целей (targets) в режиме "form". Это позволяет пользователям добавлять, удалять и редактировать неограниченное количество целей для пропинывания портов.
+
+## Архитектура FormArray
+
+### 1. Структура данных
+
+```typescript
+form = this.fb.group({
+ // ... другие поля
+ targetForms: this.fb.array([]) // FormArray для динамических форм
+});
+
+get targetForms(): FormArray {
+ return this.form.get('targetForms') as FormArray;
+}
+```
+
+### 2. Структура отдельной формы цели
+
+Каждая форма цели содержит следующие поля:
+
+```typescript
+private createTargetForm(): FormGroup {
+ return this.fb.group({
+ protocol: ['tcp', Validators.required], // Протокол (TCP/UDP)
+ host: ['127.0.0.1', Validators.required], // IP адрес хоста
+ port: [22, [Validators.required, Validators.min(1), Validators.max(65535)]], // Порт
+ gateway: [''] // Шлюз (опционально)
+ });
+}
+```
+
+## Основные методы работы с FormArray
+
+### 1. Создание новой формы цели
+
+```typescript
+addTarget(): void {
+ const newTargetForm = this.createTargetForm();
+ this.targetForms.push(newTargetForm);
+ this.serializeFormTargets();
+}
+```
+
+**Что происходит:**
+
+- Создается новая FormGroup с полями по умолчанию
+- Форма добавляется в FormArray через `push()`
+- Автоматически вызывается сериализация данных
+
+### 2. Удаление формы цели
+
+```typescript
+removeTarget(index: number): void {
+ if (this.targetForms.length > 1) {
+ this.targetForms.removeAt(index);
+ this.serializeFormTargets();
+ }
+}
+```
+
+**Особенности:**
+
+- Защита от удаления последней формы (минимум 1 форма)
+- Используется `removeAt(index)` для удаления по индексу
+- Автоматическая сериализация после удаления
+
+### 3. Сериализация данных форм
+
+```typescript
+private serializeFormTargets(): void {
+ if (this.form.value.mode !== 'form') return;
+
+ const targets: string[] = [];
+ this.targetForms.controls.forEach(targetForm => {
+ const value = targetForm.value;
+ if (value.protocol && value.host && value.port) {
+ let targetString = `${value.protocol}:${value.host}:${value.port}`;
+ if (value.gateway && value.gateway.trim()) {
+ targetString += `:${value.gateway.trim()}`;
+ }
+ targets.push(targetString);
+ }
+ });
+
+ this.form.patchValue({ targets: targets.join(';') });
+}
+```
+
+**Процесс сериализации:**
+
+1. Проверка, что текущий режим - "form"
+2. Итерация по всем формам в FormArray
+3. Сборка строки в формате `protocol:host:port:gateway`
+4. Объединение всех целей через `;`
+5. Обновление поля `targets` в основной форме
+
+## Интеграция с HTML шаблоном
+
+### 1. Отображение форм
+
+```html
+
+
+
+
+
+```
+
+**Ключевые моменты:**
+
+- `*ngFor` итерируется по `targetForms.controls`
+- `[formGroup]` связывает каждую форму с FormGroup
+- `$any(targetForm)` решает проблему типизации TypeScript
+
+### 2. Поля формы
+
+```html
+
+
+
+
+```
+
+## Автоматическое сохранение и восстановление
+
+### 1. Подписка на изменения
+
+```typescript
+private setupAutoSave() {
+ // Подписка на изменения в формах целей
+ this.targetForms.valueChanges.subscribe(() => {
+ if (this.form.value.mode === 'form') {
+ this.serializeFormTargets();
+ setTimeout(() => this.saveStateToLocalStorage(), 300);
+ }
+ });
+}
+```
+
+### 2. Сохранение в localStorage
+
+```typescript
+private saveStateToLocalStorage() {
+ const state: any = {
+ // ... другие поля
+ };
+
+ // Сохраняем данные форм целей для режима form
+ if (formValue.mode === 'form' && this.targetForms.length > 0) {
+ state.targetForms = this.targetForms.value;
+ }
+
+ localStorage.setItem(this.STORAGE_KEY, JSON.stringify(state));
+}
+```
+
+### 3. Восстановление из localStorage
+
+```typescript
+private loadStateFromLocalStorage() {
+ // ... загрузка других полей
+
+ // Загружаем сохраненные формы целей для режима form
+ if (state.mode === 'form' && state.targetForms && Array.isArray(state.targetForms)) {
+ this.targetForms.clear();
+ state.targetForms.forEach((targetData: any) => {
+ const targetForm = this.fb.group({
+ protocol: [targetData.protocol || 'tcp', Validators.required],
+ host: [targetData.host || '127.0.0.1', Validators.required],
+ port: [targetData.port || 22, [Validators.required, Validators.min(1), Validators.max(65535)]],
+ gateway: [targetData.gateway || '']
+ });
+ this.targetForms.push(targetForm);
+ });
+ }
+}
+```
+
+## Преобразование между режимами
+
+### 1. Конвертация в режим Form
+
+```typescript
+private convertInlineToForm() {
+ const targetsString = this.form.value.targets || '';
+ const targets = targetsString.split(';').filter(t => t.trim());
+
+ targets.forEach(target => {
+ const parts = target.trim().split(':');
+ if (parts.length >= 3) {
+ const targetForm = this.fb.group({
+ protocol: [parts[0] || 'tcp', Validators.required],
+ host: [parts[1] || '127.0.0.1', Validators.required],
+ port: [parseInt(parts[2]) || 22, [Validators.required, Validators.min(1), Validators.max(65535)]],
+ gateway: [parts[3] || '']
+ });
+ this.targetForms.push(targetForm);
+ }
+ });
+}
+```
+
+### 2. Конвертация из режима Form
+
+```typescript
+private handleModeChangeFromForm(previousMode: string, newMode: string) {
+ // Сначала сериализуем данные формы
+ this.serializeFormTargets();
+
+ if (newMode === 'inline') {
+ // Данные уже в targets, ничего дополнительно не нужно
+ } else if (newMode === 'yaml') {
+ this.convertInlineToYaml();
+ }
+}
+```
+
+## Жизненный цикл FormArray
+
+### 1. Инициализация
+
+```typescript
+private initializeFormMode(): void {
+ // Если нет форм целей, создаем одну по умолчанию
+ if (this.targetForms.length === 0) {
+ this.addTarget();
+ }
+}
+```
+
+### 2. Очистка при смене режима
+
+```typescript
+private handleModeChangeToForm(previousMode: string) {
+ // Очищаем существующие формы
+ this.targetForms.clear();
+
+ // Конвертируем данные из предыдущего режима
+ if (previousMode === 'inline') {
+ this.convertInlineToForm();
+ } else if (previousMode === 'yaml') {
+ this.convertYamlToForm();
+ }
+
+ // Инициализируем формы если их нет
+ if (this.targetForms.length === 0) {
+ this.addTarget();
+ }
+}
+```
+
+## Валидация
+
+### 1. Валидация полей формы
+
+```typescript
+private createTargetForm(): FormGroup {
+ return this.fb.group({
+ protocol: ['tcp', Validators.required],
+ host: ['127.0.0.1', Validators.required],
+ port: [22, [Validators.required, Validators.min(1), Validators.max(65535)]],
+ gateway: ['']
+ });
+}
+```
+
+### 2. Защита от удаления всех форм
+
+```typescript
+removeTarget(index: number): void {
+ if (this.targetForms.length > 1) {
+ this.targetForms.removeAt(index);
+ this.serializeFormTargets();
+ }
+}
+```
+
+## Преимущества использования FormArray
+
+1. **Динамичность**: Возможность добавления/удаления форм в runtime
+2. **Валидация**: Встроенная валидация для каждой формы
+3. **Реактивность**: Автоматическое обновление UI при изменениях
+4. **Типобезопасность**: TypeScript поддержка
+5. **Интеграция**: Легкая интеграция с Angular Reactive Forms
+6. **Сериализация**: Простое преобразование в различные форматы
+
+## Потенциальные проблемы и решения
+
+### 1. Проблема типизации в шаблоне
+
+**Проблема:**
+```html
+[formGroup]="targetForm"
+```
+
+**Решение:**
+```html
+[formGroup]="$any(targetForm)"
+```
+
+### 2. Защита от пустого FormArray
+
+**Проблема:** Пользователь может удалить все формы
+
+**Решение:**
+```typescript
+removeTarget(index: number): void {
+ if (this.targetForms.length > 1) { // Минимум 1 форма
+ this.targetForms.removeAt(index);
+ }
+}
+```
+
+### 3. Производительность при большом количестве форм
+
+**Проблема:** Много форм может замедлить приложение
+
+**Решение:** Виртуализация или пагинация (не реализовано в текущей версии)
+
+## Заключение
+
+FormArray в данном компоненте обеспечивает гибкую и мощную систему управления динамическими формами. Реализация включает:
+
+- Полный жизненный цикл форм (создание, редактирование, удаление)
+- Автоматическую сериализацию/десериализацию
+- Интеграцию с системой режимов
+- Сохранение состояния в localStorage
+- Валидацию и защиту от некорректных данных
+
+Этот подход делает компонент удобным для пользователей и легко расширяемым для разработчиков.
diff --git a/ui/src/app/knock/knock-page.component.html b/ui/src/app/knock/knock-page.component.html
index 30b4cb6..4d7e104 100644
--- a/ui/src/app/knock/knock-page.component.html
+++ b/ui/src/app/knock/knock-page.component.html
@@ -71,7 +71,7 @@
/>
-