Я думаю каждый сталкивался с проблемой, что на ячейки системной таблицы нет возможности навесить скрипт на изменение значения или добавить фильтр, например к столбцу с типом "Приложение".
Предлагаю вам ознакомиться с решением этой проблемы при помощи использования виджета "Динамический список".
По сути, под капотом, мы имеем ту же самую таблицу, которая будет выступать в роли источника данных.
Итак, покажу на примере созданного мной раздела "Отпуска".  В разделе есть приложение "Тип отпуска", "Сотрудник" и "Отпуска". В приложение отпуска добавим таблицу с детализацией - она будет являться источником для динамического списка и еще пару атрибутов.
	
	
Далее создадим виджет на уровне раздела, и продублируем переменные из таблицы, а также саму таблицу и, забегая наперед, переменную которая будет хранить ID доступных типов отпусков для текущего сотрудника:
	
	
Создадим шаблон виджета, добавим 4 колонки и кнопку для удаления:
	
	
Каждая строка таблицы будет являться копией этого виджета с данными, которые находятся в этой строке. Создаем необходимые нам скрипты на изменения значений, навешиваем фильтр на переменную с типом отпуска, чтобы сотрудник мог выбрать только те типы, которые за ним закреплены:
	Код:
	
async function onInit(): Promise<void> {
    if (Context.data.vacation_types_id) {
        let ids: string[] = JSON.parse(Context.data.vacation_types_id).result
        Context.fields.type_vacation.data.setFilter(f => f.__id.in(ids));
    }
}
async function on_change_start(): Promise<void> {
    if (Context.data.end && Context.data.start) {
        if (Context.data.end.before(Context.data.start)) {
            Context.data.show_date_error = true;
            Context.data.end = undefined;
        } else {
            Context.data.show_date_error = false;
        }
        //Скрипт для подсчета кол-ва дней в промежутке
        let duration = Math.ceil(((Context.data.end!.asDatetime(new TTime(4, 0, 0, 0)).unix()) - (Context.data.start.asDatetime(new TTime(22, 0, 0, 0)).unix())) / (24 * 60 * 60))
        Context.data.days = duration + 1;
        let row = Context.data.vacation_details!.find(f => f.id == Context.data.id_row);
        if (row) {
            row.days = Context.data.days;
            row.start = Context.data.start!;
            Context.data.vacation_details = Context.data.vacation_details;
        }
    }
}
async function on_change_end(): Promise<void> {
    if (Context.data.end && Context.data.start) {
        if (Context.data.end.before(Context.data.start)) {
            Context.data.show_date_error = true;
            Context.data.end = undefined;
        } else {
            Context.data.show_date_error = false;
        }
        //Скрипт для подсчета кол-ва дней в промежутке
        let duration = Math.ceil(((Context.data.end!.asDatetime(new TTime(4, 0, 0, 0)).unix()) - (Context.data.start.asDatetime(new TTime(22, 0, 0, 0)).unix())) / (24 * 60 * 60))
        Context.data.days = duration + 1;
        let row = Context.data.vacation_details!.find(f => f.id == Context.data.id_row);
        if (row) {
            row.days = Context.data.days;
            row.end = Context.data.end!;
            Context.data.vacation_details = Context.data.vacation_details;
        }
    }
}
async function on_change_type_vacation(): Promise<void> {
    if (Context.data.type_vacation) {
        let row = Context.data.vacation_details!.find(f => f.id == Context.data.id_row);
        if (row) {
            row.type_vacation = Context.data.type_vacation
            Context.data.vacation_details = Context.data.vacation_details;
        }
    }
}
async function deleted(): Promise<void> {
    for (let i = Context.data.vacation_details!.length - 1; i >= 0; i--) {
        const row = Context.data.vacation_details![i];
        if (row.id == Context.data.id_row) {
            Context.data.vacation_details!.delete(i);
        }
    }
    Context.data.vacation_details = Context.data.vacation_details;
}
 Публикуем виджет и возвращаемся к форме создания отпуска. Добавляем на форму "Панель с заголовком", назовем ее "Детализация отпуска". Внутрь панели добавляем виджет "Динамический список" и в настройках выбираем таблицу из контекста приложения:
	
	
Внутрь динамического списка добавляем еще одну панель с заголовком, в поле "Заголовок" оставляем пробел. Это нужно для того чтобы наш динамический список выглядел более элегантно)). После чего в панель с заголовком без заголовка))) добавляем ранее созданный виджет и связываем поля с данными из таблицы - источника:
	
	
Выносим виджет "Кнопка", которая будет добавлять новую строку в таблицу и в конечном итоге должно получится следующее:
![[IMG]](https://community.elma365.com/ru/assets/U2NyZWVuc2hvdF8zMTY4NjY1ODgyNg==.png)
Пишем скрипты, тут как говориться, кто на что горазд. Я написал небольшой онинит скрипт, который определяет текущего пользователя, ищет в справочнике сотрудников его карточку и записывает ID доступных для него отпусков. ID мы передаем во внешний виджет вместе с данными из таблицы.
.
Также, чтобы нам было проще понимать, какая именно строка из таблицы источника перед нами, генерируем 8 значный идентификатор.
Ну и скрипт, который добавляет строку в таблицу источник, тут все просто.
	Код:
	
async function onInit(): Promise<void> {
    Context.data.staff = await System.users.getCurrentUser();
    //ищем текущего пользователя в справочнике сотрудников и записываем ID доступных типов отпусков
    let staff = await Namespace.app.staff.search().where((f, g) => g.and(
        f.__deletedAt.eq(null),
        f.user.eq(Context.data.staff!)
    )).first();
    if (staff && staff.data.vacation_types && staff.data.vacation_types.length > 0) {
        let type_vacations = staff.data.vacation_types;
        let ids = type_vacations.map(f => f.id);
        //записываем в строку и передаем во внешний виджет
        ViewContext.data.vacation_types_id = JSON.stringify({ result: ids });
    }
}
async function addRow(): Promise<void> {
    //добавление строки в таблицу-источник
    let start_date_new: TDate | undefined = undefined;
    if (Context.data.vacation_details && Context.data.vacation_details.length > 0) {
        let last_row = Context.data.vacation_details[Context.data.vacation_details.length - 1];
        if (last_row.end) {
            start_date_new = last_row.end.addDate(0, 0, 1);
        }
    }
    let row = Context.data.vacation_details!.insert();
    if (start_date_new) {
        row.start = start_date_new
    }
    let id = ID_generation();
    row.id = id;
    Context.data.vacation_details = Context.data.vacation_details;
}
//генерируем ID строки для дальнейшего определения строки в таблице-источнике из внешнего виджета
function ID_generation() {
    const valid = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ23456789!&?`~№;:^\|/'#$%&*=-+_)(}{][@";
    let length = 8;
    let id = '';
    while (0 < length--) {
        id += valid.charAt(Math.floor(Math.random() * valid.length))
    }
    return id
}
 Чтобы динамический список запустился нужно, чтобы в таблице были какие-то данные, поэтому пишем ончейндж скрипт на изменение даты начала:
	Код:
	
//при заполнении даты начала инициализируем динамический список, заполняя дату начала в первой строке
async function on_change_start_date(): Promise<void> {
    console.log('on_change_start_date')
    let row = Context.data.vacation_details!.insert();
    row.start = Context.data.start!;
    let id = ID_generation();
    row.id = id;
    Context.data.vacation_details = Context.data.vacation_details;
    ViewContext.data.show_details = true;
}
 Публикуем форму и идем создавать отпуск.
Из-за того, что виджет внешний, его валидация не будет срабатывать на форме создания отпуска. Поэтому идем и пишем функцию валидации на форме создания, где будем проверять заполнение полей.
	Код:
	
//Валидация
async function validation(): Promise<ValidationResult> {
    const result = new ValidationResult();
    //проверка на то, что все бязательные поля в детализации заполнены
    if (Context.data.vacation_details && Context.data.vacation_details.length > 0) {
        for (let row of Context.data.vacation_details!) {
            if(!row.start || !row.end || !row.type_vacation){
                result.addMessage('Заполните все обязательные поля в детализации отпуска.')
                return result
            }
        }
        Context.data.start = Context.data.vacation_details[0].start;
        Context.data.end = Context.data.vacation_details[Context.data.vacation_details.length - 1].end;
        Context.data.amount_days = Context.data.vacation_details.map(f => f.days).reduce((sum,el) => sum + el, 0);
    }
    return result
}
 
Выгруженный раздел с виджетом во вложениях, можно пощупать.