Skip to main content

Примеры скриптов конфигуратора

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

ВАЖНО: скрипты не проходили полноценного тестирования и не являются штатным функционалом, поэтому можно ожидать, что они будут сбоить или работать неожидаемым образом.

Закрывает чат по клавише Escape
Events.onKeyDown = function (event) {
  if (event.keyCode === 27) {
    Chat.close();
  }
}
Добавляет второго исполнителя ко всем задачам первого исполнителя

Для запуска скрипта нужно из-под администратора нажать Ctrl + Shift + / , в первом поле заполнить почту уже существующего исполнителя, во втором — нового исполнителя.

Скрипт включает второго пользователя во все проекты существующего под ролью Сотрудник, не забудьте ее сменить.

Работает только в браузере с возможностью открыть запрос (prompt).

Events.onKeyUp = function (event) { // следим за клавиатурой
  if (Events.isShiftPressed() && 
  Events.isCtrlPressed() && 
  Current.user.isAdmin &&
  event.keyCode === 191) { // если вызывает админ через Shift, Ctrl и /
   const assignedUserEmail = prompt('Введите email текущего исполнителя') // запрашиваем первый емейл
   const userToAssignEmail = prompt('Введите email нового исполнителя') // запрашиваем второй
   const assignedUser = Users.listAll().find(user => user.email === assignedUserEmail) // найдем текущего исполнителя
   const userToAssign = Users.listAll().find(user => user.email === userToAssignEmail)// найдем второго исполнителя
  // если емейлы не найдены, то показываем ошибку
   if (assignedUser === undefined) {alert('Email текущего исполнителя не найден')}
   if (userToAssign === undefined) {alert('Email нового исполнителя не найден')}

   if (userToAssign !== undefined && userToAssign !== undefined) { // если все нормально
     for (const project of Current.company.list())
      for (const boards of project.list()) // проекты на доски
      for (const columns of boards.list()) // доски на колонки
      for (const task of columns.list()) { // колонки на задачи
        if (Users.isUserAssigned(assignedUser, task)) { // если старый сотрудник подписан
          const usersInTask = Users.getAssigned(task, true) // получим список уже подписанных сотрудников
          const newUsersList = [...usersInTask, userToAssign] // добавим в него нового
    Users.assignUser(newUsersList, task) // применим этот список
    Users.addToChat(userToAssign, task) // подпишем в чат
     if (Users.isInProject(assignedUser, project)) { // в проекты, в которые добавлен текущий исполнитель
        Users.addToProject(userToAssign, project) // подпишем второго исполнителя
       }
  }}}
}}

Ограничивает количество задач в колонке

//в скрипте нужно заполнить два поля: id колонки в column и ограничение количества задач в ней

const column = '0da6cadd-7717-41cd-8dbe-6b571d15301a' // id колонки
const count = 10 // максимальное количество задач в колонке

Items.onBeforeAdd = function (location, name) { // смотрим перед добавлением
  if (location.id === column) { // если колонка совпадает с нужной
    const columnCount = location.list().filter(x => x.isArchived() === false).length // получаем количество неархивных задач
    if (columnCount >= count) { // если больше нашего количества
    alert('В колонке больше 10 задач!') // выводим сообщение
    return false // запрещаем добавление
    }
  } else { // иначе
  return true // разрешаем
  }
};


Items.onMove = function (object, from, to) { // при перемещении задачи
  if (to.id === column) { // если колонка назначения совпадает с нужной
    const columnCount = to.list().filter(x => x.isArchived() === false).length // получаем количество неархивных задач
    if (columnCount >= count) { // если больше нашего количества
    alert('В колонке больше 10 задач!') // выводим сообщение
    return false // запрещаем добавление
    }
  } else { // иначе
  return true // разрешаем
  }
};
Отписывает от всех задач доски через кнопку

Работает только в браузере с возможностью открыть диалог подтверждения (confirm).

Current.onBoardChange = function (oldBoard, newBoard) {
  //при смене доски
  const boardList = Current.project.list(); //собираем все проекты
  boardList.forEach(function (board) {
    //для каждой доски
    const btn = UI.button("Отписаться от всех задач"); //создаем кнопку
    board.ui.clear(); // предварительно очищаем, чтобы удалить предыдущий и не дублировать
    btn.onClick = function (e) {
      //в кнопке
      const warn = confirm(
        "Вы действительно хотите отписаться от всех задач доски?"
      ); //размещаем предупреждение
      if (warn) {
        //если все ок
        for (const column of Current.board.list()) //для колонок в доске
          for (const task of column.list()) {
            //для задач в колонке
            Chat.removeUser(task, Current.user); //отписываем пользователя
          }
      }
    };
    board.ui.add(btn); //добавляем кнопку в интерфейс
  });
};
Подписка на все чаты задач (при их создании)

Скрипт работает только для администраторов компании, внутри скрипта нужно указать их список

Не работает для подзадач.

// Нужно заполнить e-mail-ы администраторов в listOfEmails, которые будут подписываться на чаты

const listOfEmails = ["example1@example.com", "example2@example.com"]; // список emailов для подписки
const findId = listOfEmails.map((email) => Users.get(email)); // переведем почты в id
const justAdmins = findId.filter((user) => user.isAdmin); // отфильтруем только администраторов

Items.onAdd = function (task) {
  // при добавлении
  if (task.type === "Task") {
    // задачи
    justAdmins.forEach((admin) => Chat.addUser(task, admin)); // подписываем на чат
  }
};

Уведомление в чат о перемещении задачи

Не работает для подзадач.

Items.onMove = function (task, from, to) { // при перемещении
    if (task.type === 'Task') { // задачи
      Chat.postMessage(task, '', `Сотрудник ${Current.user.name} переместил задачу из колонки «${from.name}» в колонку «${to.name}».`) // пишем сообщение в чат
    }
  };
Вставляет сквозные по компании ID задач в тело карточки задач

image.png

function addTo(task) {
    var data = task.getData();
    if (data.id) {
        return;
    }
    var cData = Current.company.getData();
    var curId = cData.currentId || 1;
    curId++;
    data.id = 'ID' + curId;
    task.setData(data);
    cData.currentId = curId;
    Current.company.setData(cData);
}

function getId(task, recur) {
    var data = task.getData();
    if (!data.id) {
        if (recur) {
            return;
        }
        addTo(task);
        return getId(task, true);
    }
    return data.id;
}

Items.onAdd = function(task) {
    if (task.type !== 'Task') {
        return;
    }
    addTo(task);
};

var style = {
    position: 'absolute',
    fontSize: '9px',
    right: '4px',
    top: '-1px',
    fontWeight: 'bold'
};

Items.onList = function(obj, arr) {
    if (obj.type === 'Column') {
        arr.forEach(function(t) {
            var id = getId(t);
            var el = UI.text(id);
            el.style = style;
            t.ui.clear();
            t.ui.add(el);
        });
    }
    return arr;
};

Архивация задач при выполнении

// Архивирует задачи при их выполнении
Items.onUpdate = function(obj) { // вызываем при обновлении 
    if (obj.isCompleted() === true) { // если задача выполнена
        obj.setTaskCompleted(true); // то архивируем ее
    }
};

Считает количество задач в колонке и печатает его в интерфейсе

image.png

// Пишет количество задач в колонках при отрисовке страницы и обновлении объектов.
// Вносить в него ничего не надо, можно в p.style поменять что-то на свой вкус
Current.onBoardChange = function (oldBoard, newBoard) { //работаем при смене доски
  const listOfColumns = Current.board.list() //получаем список колонок
  listOfColumns.forEach(function (i) { // перебираем каждую колонку
    if (!Items.get(i.id).isMirror() && !Items.get(i.id).isReport()) { // если колонка не зеркало и не сводка
    const column = Items.get(i.id); // получаем id колонки
    const numberTasks = column.list() // берем общее количество задач в колонке
    const tasksIsNotArchived = numberTasks.filter(x => x.isArchived() === false) // забирем задачи не в ахиве
    const p = UI.panel(); // создаем контейнер
    column.ui.clear() // предварительно очищаем, чтобы удалить предыдущий и не дублировать
    column.ui.add(p);
    p.style = {
      margin: 'auto',
      width: '100px',
      padding: 'auto',
      color: '#572'
    }; // оформляем контейнер
    p.add(UI.text('Задач: ' + tasksIsNotArchived.length)); // пишем текст
  }})
}


Items.onUpdate = function (obj) { //вызываем функцию при обновлении, 
  // чтобы работало в реальном времени
  Current.onBoardChange()
};

Запрашивает обязательный комментарий при перемещении задачи в другую колонку и печатает его в описание

Работает только в браузере с возможностью открыть запрос (prompt).

// Запрашивает обязательный комментарий при перемещении задачи
Items.onMove = function(obj, from, to) {
    if (to.id === 'id колонки') { //если id колонки совпадает
        let comment = prompt('Введите комментарий') //запрашиваем комментарий
        if (!comment) { //если комментария нет
            return false // отказываем
        } else { //иначе
            Chat.postMessage(obj, '', `Задача перемещена пользователем ${Current.user.name}`) //пишем в чат, что переместили задачу
            Chat.setDescription(obj, Chat.getDescription(obj) + '<br> <p><b>Комментарий пользователя ' + Current.user.name + ': </b></p>' +
                '<p>' + comment + '</p>') //пишем в описание комментарий
        }
        return true
    }
}


Назначение пользователя в определенной колонке

// Добавляет исполнителя в задачу, если ее переместить в колонку и у задачи нет исполнителя.
// Надо вписать id колонки и id пользователя. 
// Для текущего пользователя (кто перемещает задачу) можно вместо id пользователя вписать Current.user.id без кавычек, это сделает его исполнителем
Items.onMove = function(obj, from, to) {
    const task = Items.get(obj.id) //берем id таска
    const user = Users.get('id пользователя'); //берем id пользователя
    if (to.id === '<id колонки>' && !Users.getAssigned(task)) { //если id колонки совпадает
        //и в задаче нет исполнителя
        Users.assignUser(user, task); // назначаем пользователя
    }
};


Скрывает задачу не из "белого списка" аккаунтов, если на нее навесить определенный стикер

// Скрывает задачу, если на него закреплен стикер (в примере — состояние "Запрет" для стикера "Ограничение")
// userRestrict — массив, в который вносятся emailы, для которых задача скрывается
Items.isHidden = function(object) { // функция скрытия
    const stickerRestrict = Stickers.get('Ограничение'); // забираем нужный текстовый стикер
    const allowToSee = Stickers.getValue(object, stickerRestrict); //забираем состояние этого стикера
    const userRestrict = ['example1@example.com', 'example2@example.com']; //массив почт, для которых задача скроется
    function checkEmail(email) { // функция, которая возвращает совпадение запрещенного списка с текущим пользователем
        return email === Current.user.email
    }
    const restrict = userRestrict.find(checkEmail); // ищет совпадение 

    if (object.type === 'Task' && allowToSee === 'Запрет' && restrict !== undefined) { //если задача со стикером Запрет 
        // и текущий пользователь попадает в список
        return true // скрываем
    }
    return false; // в остальных случаях должно быть открыто
};


Сообщение в чат при удалении исполнителя

Stickers.onUnpin = function(task, sticker) { //при откреплении стикера
    if (sticker.name === 'User') { //если ститкер — исполнитель
        const userID = Stickers.getValue(task, sticker) //берем id исполнителя
        const userName = Users.get(userID).name //получаем его имя
        Chat.postMessage(task, '', `${userName} удален из исполнителей задачи`) // пишем в чат задачи
    }
    return true;
}

Сообщение в чат при добавлении файла в описание задачи

// Добавляет сообщене в чат задачи при добавлении вложения в описание.
Items.onUpdate = function(obj) {
    if (obj.type === 'Task') { //фильтруем только задачи
        let descDump = obj.getData().description; //берем наш дамп описания задачи
        if (descDump === undefined) {
            descDump = ''
        } //если дампа нет, то оставляем его пустым
        const currenDesc = Chat.getDescription(obj); // берем описание задачи
        const diff = findDiff(descDump, currenDesc) // сравниваем и находим разницу
        if (diff.includes('rel="noopener noreferrer"')) { // если в разнице есть свойство вложения
            Chat.postMessage(obj, '', 'Файл добавлен в описание') // пишем в чат
        }
        obj.setData({
            description: currenDesc
        }) // сохраняем текущее описание в дамп на будущее
    }
};

function findDiff(str1, str2) { // это функция, которая сравнивает две строки и выводят между ними разницу
    let diff = "";
    str2.split('').forEach(function(val, i) {
        if (val != str1.charAt(i))
            diff += val;
    });
    return diff;
}


Сообщение в чат о прикреплении/изменении дедлайна

//Реагирует на создание и изменение дедлайна задачи, отписывая сообщение в чат задачи. 
//Удаление дедлайна игнорирует
Stickers.onPin = function(task, sticker, value) { //при прикреплении стикера
    if (sticker.type === 'Deadline' && value !== undefined) { //если это дедлайн и у него у него есть значение
        Chat.postMessage(task, '', 'Прикреплен/изменен дедлайн'); //пишем сообщение в чат
    }
};
При клике на карточку задачи через Shift назначать себя исполнителем, а через Alt — еще удалить участников чата
Items.onClick = function (object) { // при клике
  if (object.type === 'Task') { // на задачу
    if (Events.isShiftPressed()) { // если зажата Shift
      Users.assignUser(Current.user, object); // назначаем себя на задачу
      Chat.addUser(object, Current.user) // добавляем себя в чат
    }
    if (Events.isAltPressed()) { // если зажата Alt
      const listInChat = Chat.listUsers(object) // собираем участников чатов
      listInChat.forEach(user => Chat.removeUser(object, user)) // удаляем их из чата
      Users.assignUser(Current.user, object); // назначаем себя
      Chat.addUser(object, Current.user) // подписываем себя на чат
    }
  }
  return true;
};