Reducir la fricción en los flujos de trabajo con Jira se logra con pequeños fragmentos de JavaScript que se ejecutan directamente en el navegador. Con herramientas como Arc Boost o las extensiones de Chrome es posible modificar el DOM, ajustar el comportamiento de filtros e inyectar valores automáticamente, ahorrando tiempo y evitando errores manualse.
Herramientas para inyectar scripts en cualquier sitio
Uso el boost de Arc, que permite asociar código JavaScript a un host específico. Al crear un boost se accede a una pestaña code donde se pega el script y se ejecuta en el contexto de la página. Para quienes no usan Arc, una extensión de Chrome que emplee content_scripts y haga coincidir patrones de URL ofrece el mismo resultado, e incluso más flexibilidad.
Modificaciones sobre la interfaz de Jira
Jira concentra muchas operaciones repetitivas. A continuación se muestran algunos ajustes que apliqué para agilizar el trabajo diario.
Reordenar el panel de filtros del daily
El orden de los compañeros en el tablero no coincidía con el que se seguía en la reunión. Bastó con manipular los elementos hijo del contenedor de la extensión rápida de filtros.
const contenedor = document.querySelector('.aui-expander-content.ghx-quick-content');
if (contenedor) {
const hijos = contenedor.children;
hijos[6].remove();
hijos[10].remove();
hijos[6].after(hijos[2]);
hijos[9].after(hijos[1]);
}
Convertir selección múltiple en selección única
Los filtros del tablero aceptan múltiples selecciones; al pasar de una persona a otra era necesario desmarcar la anterior manualmente. Mediante un event listener se fuerza el comportamiento de botones de radio: al hacer clic en uno se desactivan los demás.
let actual = null;
contenedor.addEventListener('click', (e) => {
if (actual) return;
actual = e.target;
Array.from(contenedor.children).forEach(item => {
const boton = item.children[0];
if (boton && boton.classList.contains('ghx-active') && boton.innerHTML !== actual.innerHTML) {
boton.click();
}
});
actual = null;
});
Autocompletar los campos obligatorios al cerrar un bug
Al cerrar una incidencia siempre se requerían los mismos valores: causa, tipo de resolución, descripción, etc. Un intervalo que localiza los campos y les asigna un valor elimina por completo la tarea repetitiva.
const rellenarCampo = (id, valor) => {
const elemento = document.getElementById(id);
if (elemento) elemento.value = valor;
};
setInterval(() => {
rellenarCampo('resolution', 10000);
rellenarCampo('customfield_10903', 12502);
rellenarCampo('customfield_12301', 'Causa: error de código\nSolución: corrección\nÁmbito: interfaz\nResponsable: equipo');
}, 1000);
Accediendo a la instancia de Vue para mejorar un panel
En otro contexto, un panel de control de una aplicación Vue mostraba información muy resumida, aunque los datos completos ya estaban disponibles en el cliente. Con ayuda de la instancia Vue expuesta en el DOM se puede enriquecer la vista sin modificar el código original.
Localizar la instancia de Vue recorriendo el DOM
Vue almacena una referencia interna en el DOM (__vue__), que también utiliza la extensión Vue Devtools. Un recorrido recursivo revela dónde residen los datos.
const buscarVue = (nodo) => {
if (nodo.__vue__) {
console.log(nodo.__vue__._data);
}
[...nodo.children].forEach(hijo => buscarVue(hijo));
};
buscarVue(document.body);
Script final para inyectar estadísticas
Luego de identificar el nodo raíz se extrae la lista de datos desde _data y se agregan valores a cada fila de la tabla.
(function() {
const appRoot = document.querySelector('.page_mod_page_simple.page_home');
if (!appRoot || !appRoot.__vue__) return;
const lista = appRoot.__vue__.$parent.currentList;
const tabla = document.querySelector('.table_wrp_emotion_list .table_body');
if (tabla && lista) {
const filas = tabla.children;
for (let i = 0; i < filas.length; i++) {
if (lista[i]) {
filas[i].children[2].innerHTML += ' (' + lista[i].SendNum + ' - ' + lista[i].DataTime + ')';
}
}
}
})();
Resolver el aislamiento del entorno de ejecución
Los boosts y los content scripts de extensiones se ejecutan en un contexto separado del de la página, por lo que la propiedad __vue__ no siempre está accesible. Para sortearlo se crea un elemento <script> dinámico cuyo código corre en el contexto real de la aplicación.
const scriptPagina = document.createElement('script');
scriptPagina.textContent = `
(function() {
const raiz = document.querySelector('.page_mod_page_simple.page_home');
if (!raiz || !raiz.__vue__) return;
const datos = raiz.__vue__.$parent.currentList;
const cuerpo = document.querySelector('.table_wrp_emotion_list .table_body');
if (cuerpo && datos) {
const filas = cuerpo.children;
for (let i = 0; i < filas.length; i++) {
if (datos[i]) {
filas[i].children[2].innerHTML += ' (' + datos[i].SendNum + ' - ' + datos[i].DataTime + ')';
}
}
}
})();
`;
setTimeout(() => document.head.appendChild(scriptPagina), 1000);