Commit b3731a5c authored by System Administrator's avatar System Administrator

[etersoft] Fix bug creating #14950

parent 3d9564fd
//Номер баги
let bugId = getIdFromUrl() || getBugIdFromField();
// Если id нет, то мы имеем дело с новой багой
if (!bugId) {
const currentTime = new Date().getTime()
// Присвоим текущее время, чтобы при создании следующей баги значения не сохранились
bugId = `c${currentTime}`;
}
// получим протокол
const {
protocol
} = window.location;
//Изменение баги
var changed_remain = 0;
// Создание баги
const isBugCreation = window.location.pathname.includes("enter");
function initTimer(config) {
// Показываем время только сотрудникам Etersoft
if (!isEtersoft()) return;
// достанем все необходимые параметры
// для конфигурирования таймера
const {
updateInterval,
selector,
protocol,
bugId,
udpateTimerCallback
} = config
// покажем сам таймер
document.querySelector(selector).style.display = "block";
const timer = new Timer(`bug:${protocol}${bugId}`, udpateTimerCallback);
timer.setAutoUpdate(updateInterval);
return timer
}
// Конфиг для валидации комментарии
const VALIDATION_CONFIG = {
minLength: 9,
maxTime: 8,
}
// Конфиг таймера
const TIMER_CONFIG = {
// Интервал обновления таймера в мс, на точность не влияет
updateInterval: 1000,
// Селектор элемента, в котором лежит сам таймер
selector: "#timerblock",
// протокол
protocol,
// номер баги
bugId,
// функция updateTimer
udpateTimerCallback: updateTimer
}
// Объект таймера, создается при инициализации
// Подробнее про таймер см. timer_common.js
const timer = initTimer(TIMER_CONFIG);
// this при вызове - объект таймера
function updateTimer() {
setPauseDisplay(this.isPaused());
document.querySelector("#timespent").value = this.getFormattedString();
}
// Установка в поле отработанного времени в минутах
function setWorkTime(manualTime) {
const minutes = Math.ceil(timer.getElapsedSeconds() / 60);
document.querySelector("#realworktime").value = manualTime ?
manualTime :
minutes;
}
// переключение видимости по селектору
function toggleVisibility(selector, isHidden) {
document.querySelector(selector).style.visibility = isHidden ?
"hidden" :
"visible"
}
// меняем вид таймера при паузе
function setPauseDisplay(pause) {
document.querySelector("#timespent").style.color = pause ? "gray" : "black";
// прячем кнопку для паузы
toggleVisibility("#timer_pause", pause);
// показываем кнопку для включения
toggleVisibility("#timer_play", !pause);
}
// Получение номера баги из поля
function getBugIdFromField() {
const field = document.querySelector("#changeform input[name=id]");
if (field) {
return parseInt(field.value);
}
return false;
}
// Является ли пользователь сотрудником Etersoft
function isEtersoft() {
const email = document.getElementById("useremail").className;
if (!email) return false;
const domain = email.split("@")[1];
return domain === "etersoft.ru";
}
// Является ли пользователь ответственным
function isWorker() {
const email = document.getElementById("useremail").className;
const assignemail = document.getElementById("assigntoemail").className;
return email == assignemail;
}
// функция для получения времени с таймера в минутах
function getTimespentValue() {
return Math.round(timer.getElapsedSeconds() / 60);
}
// лямбда для получения числового значения времени по селектору
const parseTimeInt = (selector) => parseInt(document.querySelector(selector).value);
// лямбда для получения числового значения времени из элемента
const parseTimeIntFromData = (elem) => parseInt(elem.dataset["time"]);
// лямбда для перевода времени из минут в часы
const calcTimeValue = (time) => Math.ceil((time / 60) * 100) / 100;
// функция для обновления оставшегося времени
function updateRemainingTime(workTimeValue) {
// получаем estimatedTime
const estimatedTimeElement = document.querySelector('#estimated_time');
const workedTimeElement = document.querySelector('.bz_time_tracking_table > tbody:nth-child(1) > tr:nth-child(2) > td:nth-child(3)');
if (estimatedTimeElement && workedTimeElement) {
const estimatedTime = Number(estimatedTimeElement.value);
// получаем отработанное время
const workedTime = Number(workedTimeElement.innerText);
// пересчитанное отработанное время
const updatedWorkedTime = ((workedTime * 100) + (workTimeValue * 100)) / 100;
// считаем сколько осталось
const remainingTimeValue = Math.ceil(((estimatedTime * 100) - (updatedWorkedTime * 100))) / 100;
// обновляем оставшееся время
document.querySelector("#remaining_time").value = remainingTimeValue > 0 ? remainingTimeValue : 0;
}
}
// функция для отправки комментария
function submitComment(commentData) {
const validatedComment = validateComment(...commentData);
const { error, text } = validatedComment;
if (error) {
alert(text);
return;
}
const bugForm = isBugCreation ? "#Create" : "#changeform";
document.querySelector(bugForm).submit();
timer.clear();
localStorage.removeItem("time");
}
// функция для валидации комментария
function validateComment(comment, workTimeValue, productiveTimeValue, validationConfig = VALIDATION_CONFIG) {
const commentLength = comment.length;
const isMinLength = commentLength > validationConfig.minLength;
const isMaxWorkTime = workTimeValue > validationConfig.maxTime;
const isMaxProductiveTime = productiveTimeValue > validationConfig.maxTime;
const isProductiveTimeHigher = productiveTimeValue > workTimeValue;
const isNotCommentTooShort = productiveTimeValue > 2 &&
comment.length < productiveTimeValue * 60;
const isZeroTime = !comment.length && workTimeValue === 0 && productiveTimeValue === 0;
let error = "";
if (commentLength) {
if (!isMinLength) {
error = "Слишком короткий комментарий";
} else if (isMaxWorkTime || isMaxProductiveTime) {
error = "Недопустимо указывать отработанное/продуктивное время более восьми часов. Правильным следованием рабочему процессу было бы выполнение работы по частям, о каждой из которых будет написано отдельно.";
} else if (isNotCommentTooShort) {
error = "Недопустимо коротко комментировать длительные работы. Мы ожидаем не менее 60 символов на каждый указанный час.";
} else if (isProductiveTimeHigher) {
error = "Продуктивное время не может быть больше отработанного!";
}
} else if (!isZeroTime) {
error = "Поле комментария не может быть пустым!";
}
const errorObj = {
error: false,
text: ""
};
if (error) {
errorObj.error = true;
errorObj.text = error;
}
return errorObj;
}
window.addEventListener("load", function() {
// работа с модальным окном
const openButton = document.querySelector("#commit");
const closeButton = document.querySelector("#timeQuestionDiv .close");
const dialog = document.querySelector("#timeQuestionDiv");
// функция для открытия модального окна для ввода времени
function opetTimeModal(event) {
event.preventDefault();
closeButton.addEventListener("click", () => {
dialog.style.display = "none";
})
if (!isEtersoft()) {
const comment = document.querySelector('#comment').value.length;
if (!comment) {
alert('Поле комментария не может быть пустым!');
return
}
const bugForm = isBugCreation ? "#Create" : "#changeform";
document.querySelector(bugForm).submit();
return
}
const timespentValue = getTimespentValue();
dialog.style.display = "block";
focusManager.capture(dialog);
// записываем отработанное время
document.querySelector("#realworktime").value =
!localStorage.time ? timespentValue : localStorage.time;
document.querySelector("#saveTime").dataset["time"] = timespentValue;
}
openButton.addEventListener("click", opetTimeModal);
// если кнопка сохранить есть сверху, то добавим то же событие
// и на неё
const openButtonTop = document.getElementById("commit_top");
if (openButtonTop) {
openButtonTop.addEventListener("click", opetTimeModal);
}
function updateTimeValue() {
document.querySelector("#saveTime").dataset["time"] = this.value;
localStorage.time = this.value;
}
document
.querySelector("#realworktime")
.addEventListener("change", updateTimeValue);
document
.querySelector("#realworktime")
.addEventListener("paste", updateTimeValue);
// add listener for enter key down to work time input
document.querySelector("#realworktime").addEventListener("keyup", (event) => {
if (event.key === "Enter") {
document.querySelector("#realworktime").blur();
document.querySelector("#ProductTime").focus();
}
});
// add listener for enter key down to productive time input
document.querySelector("#ProductTime").addEventListener("keyup", () => {
if (event.key === "Enter") {
document.querySelector("#saveTime").click();
}
});
// add listener for time commit
const saveTimeButton = document.querySelector("#saveTime");
saveTimeButton.addEventListener("click", function(event) {
// cancel form submiting
event.preventDefault();
// let's calc time for #work_time input
let workTime = parseTimeInt("#realworktime");
const timeFromButton = parseTimeIntFromData(saveTimeButton);
// если время совпадает с тем что ввёл пользователь
// будем использовать его
// иначе будем использовать отработанное
workTime = workTime === timeFromButton
? timeFromButton
: workTime;
// если время не задано, то пусть будет нулём
workTime = workTime || 0;
const workTimeValue = calcTimeValue(workTime);
const productiveTime = parseTimeInt("#ProductTime") || workTime;
const productiveTimeValue = calcTimeValue(productiveTime);
document.querySelector("#work_time").value = workTimeValue;
document.querySelector("#productive_time").value = productiveTimeValue;
// обновим оставшееся время
if (document.getElementById('estimated_time')) {
updateRemainingTime(workTimeValue);
}
// check comment before submit
const comment = document.querySelector("#comment").value;
const commentData = [
comment,
workTimeValue,
productiveTimeValue
];
submitComment(commentData);
});
});
// let's validate!
function validate(_event) {
console.log(_event);
const event = _event || window.event;
console.log(event);
let key = event.keyCode || event.which;
key = String.fromCharCode(key);
const regex = /[0-9\s]/;
if (!regex.test(key)) {
event.returnValue = false;
if (event.preventDefault) event.preventDefault();
}
}
function addValidationToElement(selector) {
// добавляем слушатель на keypress
document
.querySelector(selector)
.addEventListener("keypress", validate);
// добавляем слушатель на paste
document
.querySelector(selector)
.addEventListener("paste", validate);
}
addValidationToElement("#realworktime");
addValidationToElement("#ProductTime");
<link rel="stylesheet" type="text/css" href="js/etersoft/timersplash.css?15_04_2020" />
<div style="display: none;" id="useremail" class="[% user.email FILTER html %]"></div>
<div style="display: none;" id="assigntoemail" class="[% bug.assigned_to.email FILTER html %]"></div>
<!-- Таймер -->
<div id="timerblock" title="Время на странице">
<img src="js/etersoft/control_pause.gif" id="timer_pause" onclick="timer.togglePause()" title="Пауза" />
<img src="js/etersoft/control_right.gif" id="timer_play" onclick="timer.togglePause()" title="Продолжить" />
<img src="js/etersoft/control_stop.gif" id="timer_stop" onclick="if (confirm('Вы точно хотите сбросить таймер?')) {timer.reset();}" title="Сбросить таймер" />
<input type="text" size="10" title="Время на странице" id='timespent' name="timespent" value="" readonly="readonly">
</div>
<!-- Сохранение времени -->
<div id="timeQuestionDiv">
<div class="container">
<div class="workTime">
<h3>Укажите отработанное время</h3>
<fieldset>
Отработанное время:
<div class="workTimeInner">
<input class="workTime__input" id="realworktime" name="realworktime" data-time="" placeholder="в минутах" title="Общее время, потраченное на задачу." type="text" tabindex="1" required autofocus>
<button class="workTime__button" data-time="1" onclick="document.querySelector('#realworktime').value=this.dataset['time']" tabindex="2">1</button>
<button class="workTime__button" data-time="5" onclick="document.querySelector('#realworktime').value=this.dataset['time']" tabindex="3">5</button>
<button class="workTime__button" data-time="15" onclick="document.querySelector('#realworktime').value=this.dataset['time']" tabindex="4">15</button>
<button class="workTime__button" data-time="30" onclick="document.querySelector('#realworktime').value=this.dataset['time']" tabindex="5">30</button>
</div>
</fieldset>
<fieldset>
Продуктивное время:
<div class="workTimeInner">
<input class="workTime__input" id="ProductTime" placeholder="в минутах" title="Время, которое вы бы потратили на задачу, зная как её решать." type="text" tabindex="6" required>
<button class="workTime__button" data-time="1" onclick="document.querySelector('#ProductTime').value=this.dataset['time']" tabindex="7">1</button>
<button class="workTime__button" data-time="5" onclick="document.querySelector('#ProductTime').value=this.dataset['time']" tabindex="8">5</button>
<button class="workTime__button" data-time="15" onclick="document.querySelector('#ProductTime').value=this.dataset['time']" tabindex="9">15</button>
<button class="workTime__button" data-time="30" onclick="document.querySelector('#ProductTime').value=this.dataset['time']" tabindex="10">30</button>
</div>
</fieldset>
<fieldset>
<button class="workTime__button--save" id="saveTime" tabindex="11">Сохранить</button>
</fieldset>
<button class="close" tabindex="12">&times;</button>
</div>
</div>
</div>
<script language="javascript" type="text/javascript" src="js/etersoft/focusManager.js"></script>
<script language="javascript" type="text/javascript" src="js/etersoft/timer_common.js?25_10_2017"></script>
<script language="javascript" type="text/javascript" src="js/etersoft/timer.js?23_04_2021"></script>
<link rel="stylesheet" type="text/css" href="js/etersoft/timersplash.css?15_04_2020" />
<div style="display: none;" id="useremail" class="[% user.email FILTER html %]"></div>
<div style="display: none;" id="assigntoemail" class="[% bug.assigned_to.email FILTER html %]"></div>
<!-- Таймер -->
<div id="timerblock" title="Время на странице">
<img src="js/etersoft/control_pause.gif" id="timer_pause" onclick="timer.togglePause()" title="Пауза" />
<img src="js/etersoft/control_right.gif" id="timer_play" onclick="timer.togglePause()" title="Продолжить" />
<img src="js/etersoft/control_stop.gif" id="timer_stop" onclick="if (confirm('Вы точно хотите сбросить таймер?')) {timer.reset();}" title="Сбросить таймер" />
<input type="text" size="10" title="Время на странице" id='timespent' name="timespent" value="" readonly="readonly">
</div>
<!-- Сохранение времени -->
<div id="timeQuestionDiv">
<div class="container">
<div class="workTime">
<h3>Укажите отработанное время</h3>
<fieldset>
Отработанное время:
<div class="workTimeInner">
<input class="workTime__input" id="realworktime" name="realworktime" data-time="" placeholder="в минутах" title="Общее время, потраченное на задачу." type="text" tabindex="1" required>
<button class="workTime__button" data-time="1" onclick="document.querySelector('#realworktime').value=this.dataset['time']" tabindex="2">1</button>
<button class="workTime__button" data-time="5" onclick="document.querySelector('#realworktime').value=this.dataset['time']" tabindex="3">5</button>
<button class="workTime__button" data-time="15" onclick="document.querySelector('#realworktime').value=this.dataset['time']" tabindex="4">15</button>
<button class="workTime__button" data-time="30" onclick="document.querySelector('#realworktime').value=this.dataset['time']" tabindex="5">30</button>
</div>
</fieldset>
<fieldset>
Продуктивное время:
<div class="workTimeInner">
<input class="workTime__input" id="ProductTime" placeholder="в минутах" title="Время, которое вы бы потратили на задачу, зная как её решать." type="text" tabindex="6" required>
<button class="workTime__button" data-time="1" onclick="document.querySelector('#ProductTime').value=this.dataset['time']" tabindex="7">1</button>
<button class="workTime__button" data-time="5" onclick="document.querySelector('#ProductTime').value=this.dataset['time']" tabindex="8">5</button>
<button class="workTime__button" data-time="15" onclick="document.querySelector('#ProductTime').value=this.dataset['time']" tabindex="9">15</button>
<button class="workTime__button" data-time="30" onclick="document.querySelector('#ProductTime').value=this.dataset['time']" tabindex="10">30</button>
</div>
</fieldset>
<fieldset>
<button class="workTime__button--save" id="saveTime" tabindex="11">Сохранить</button>
</fieldset>
<button class="close" tabindex="12">&times;</button>
</div>
</div>
</div>
<script language="javascript" type="text/javascript" src="js/etersoft/focusManager.js"></script>
<script language="javascript" type="text/javascript" src="js/etersoft/timer_common.js?25_10_2017"></script>
<script language="javascript" type="text/javascript" src="js/etersoft/timer.js?23_04_2021"></script>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment