var xMousePos = null; var yMousePos = null; document.onmousemove = function(e) { xMousePos = e.clientX + window.scrollX; yMousePos = e.clientY + window.scrollY; } document.oncontextmenu = function(e) { xMousePos = e.clientX + window.scrollX; yMousePos = e.clientY + window.scrollY; } /** * Récupère depuis le document l'identifiant de l'élément * @param {string} id Identifiant de l'élément `id='identifiant'` * @returns */ function getID(id) { return document.getElementById(id) } /** * * @param {Date} GetDate * @returns */ function getFormattedDate(GetDate) { const date = new Date(GetDate) var gmonth = date.getMonth() + 1 var gday = date.getDate() var gHour = date.getHours() var gMinute = date.getMinutes() var gSecondes = date.getSeconds() if(date.getMonth() + 1 < 10) { gmonth = "0" + (date.getMonth() + 1) } if(date.getDate() + 1 <= 10) { gday = "0" + date.getDate() } if(date.getHours() + 1 <= 10) { gHour = "0" + date.getHours() } if(date.getMinutes() + 1 <= 10) { gMinute = "0" + date.getMinutes() } if(date.getSeconds() + 1 <= 10) { gSecondes = "0" + date.getSeconds() } return gday + "/" + gmonth + "/" + date.getFullYear() + " - " + gHour + ":" + gMinute } /** * Permet de faire une pop-up automatique */ class TextResponse { constructor(name) { this.name = name this.element = getID(this.name) this.element.innerHTML = " " this.element.style.fontSize = "14px" this.element.style.textAlign = "center" } clear() { this.element.innerHTML = " " } err(text) { this.element.classList.add("yellow") this.element.innerHTML = " " + text } info(text) { this.element.classList.remove("yellow") this.element.innerHTML = " " + text } setSize(size) { this.element.style.fontSize = size } setWidth(width) { this.element.style.width = width } } const AllViews = new Map() var zIndex = 5 /** * Permet de créer une fenêtre * @param {object} properties Propriétés de la fenêtre */ class ViewWindow { ViewHTML = null ViewWindowDiv ViewProperties = null ViewSpanInteger = null ViewPopupSpanInteger = null ViewPopupHTML = null ViewPopupTitle = null ViewItem = new ViewItem(this) constructor (properties) { if(!AllViews.has(properties.title)) { this.ViewProperties = properties AllViews.set(properties.title, true) this.ViewHTML = `

${properties.title}

` this.ViewSpanInteger = document.createElement("div") document.body.appendChild(this.ViewSpanInteger); this.ViewSpanInteger.outerHTML = this.ViewHTML const header = document.getElementById(properties.title + "_header") const windowDiv = document.getElementById(properties.title + "_window") this.ViewWindowDiv = windowDiv const closeWindow = document.getElementById(properties.title + "_close") const minimizeWindow = document.getElementById(properties.title + "_minimize") const reduceWindow = document.getElementById(properties.title + "_reduce") closeWindow.addEventListener("click", () => { this.destroy() }) reduceWindow.addEventListener("click", () => { windowDiv.style.display = "none" }) minimizeWindow.addEventListener("click", () => { const windowDiv = document.getElementById(properties.title + "_window") const contentDiv = document.getElementById(properties.title + "_content") const minimizeIcon = document.getElementById(properties.title + "_minimize").children[0] if(windowDiv.classList.contains("minimized")) { windowDiv.classList.remove("minimized") contentDiv.style.display = "unset" windowDiv.style.backgroundColor = "#605e58c1" minimizeIcon.classList.remove("fa-window-restore") minimizeIcon.classList.add("fa-window-maximize") } else { windowDiv.classList.add("minimized") contentDiv.style.display = "none" windowDiv.style.backgroundColor = "transparent" minimizeIcon.classList.remove("fa-window-maximize") minimizeIcon.classList.add("fa-window-restore") this.destroyPopup() } }) let isDragging = false; let offsetX, offsetY; windowDiv.style.zIndex = zIndex + 1 header.addEventListener('mousedown', (e) => { isDragging = true; zIndex+=2 windowDiv.style.zIndex = zIndex // Enregistrez la position de la souris par rapport à la fenêtre offsetX = e.clientX - windowDiv.getBoundingClientRect().left; offsetY = e.clientY - windowDiv.getBoundingClientRect().top; }); // Gérer le déplacement document.addEventListener('mousemove', (e) => { if (isDragging) { header.style.cursor = "grab" // Calculez la nouvelle position de la fenêtre en fonction de la position de la souris const newLeft = e.clientX - offsetX; const newTop = e.clientY - offsetY; // Limitation de la position pour éviter un débordement const maxX = window.innerWidth - windowDiv.offsetWidth; const maxY = window.innerHeight - windowDiv.offsetHeight; windowDiv.style.left = Math.min(Math.max(newLeft, 0), maxX) + 'px'; windowDiv.style.top = Math.min(Math.max(newTop, 0), maxY) + 'px'; } }); // Gérer la fin du glisser-déposer document.addEventListener('mouseup', () => { header.style.cursor = "unset" isDragging = false; }); } this.ViewItem.show() } destroy() { const win = getID(`${this.ViewProperties.title}_window`) win.outerHTML = " " AllViews.delete(this.ViewProperties.title) this.ViewItem.hide() } setContent(text) { const contentDiv = document.getElementById(this.ViewProperties.title + "_content") contentDiv.innerHTML = text } getViewTitle() { return this.ViewProperties.title } createPopup(properties) { this.ViewPopupHTML = `

${properties.title}

${properties.content}
` const contentDiv = getID(this.ViewProperties.title + "_content") const popupDiv = getID(this.ViewProperties.title + "_popupDiv") this.ViewPopupSpanInteger = document.createElement("div") popupDiv.appendChild(this.ViewPopupSpanInteger); this.ViewPopupSpanInteger.outerHTML = this.ViewPopupHTML this.ViewPopupTitle = properties.title const popup = getID(properties.title + "_popup") const popupClose = getID(properties.title + "_popupClose") popupClose.addEventListener("click", () => { this.destroyPopup() }) // Center the popup to the window div popup.style.left = (contentDiv.offsetWidth / 2) - (popup.offsetWidth / 2) + "px" popup.style.top = (contentDiv.offsetHeight / 2) - (popup.offsetHeight / 2) + "px" // Render parent element styled blur contentDiv.classList.add("blur") // Disable all interractions like click and events with contentDiv children for(var child of contentDiv.children) { child.style.pointerEvents = "none" } } destroyPopup() { const popup = getID(this.ViewPopupTitle + "_popup") if(popup) { const contentDiv = getID(this.ViewProperties.title + "_content") for(var child of contentDiv.children) { child.style.pointerEvents = "unset" } contentDiv.classList.remove("blur") popup.outerHTML = "" } } } var AllComponents = new Array() /** * Permet de créer un composant de vue * @param {object} properties Propriétés du composant de vue */ class ViewComponent { name; icon; permission; window; constructor (properties) { this.name = properties.name this.icon = properties.icon this.permission = properties.permission AllComponents.push(this) } inject(array) { array.push(`

${this.name}

`) } createWindow(functionToExecute) { this.window = functionToExecute } bindView() { const component = getID(this.name) if(component) { component.addEventListener("click", () => { console.log(component) if(this.window) { this.window() } }) } } forceWindow() { if(this.window) { this.window() } } } /** * Permet de créer un menu déroulant * @param {object} properties Propriétés du menu déroulant */ var ActualDroppableMenu = null class DroppableMenu { options = new Array() id = null DMSpanInteger = null #enableHide = false constructor() { this.id = Math.random().toString(36).substring(7) this.options.push(`
`) } add(action, string) { this.options.push("
" + string + "
") } show() { console.log("DROPPABLE MENU - " + this.id) if(ActualDroppableMenu) { ActualDroppableMenu.hide() } ActualDroppableMenu = this this.options.push(`
`) if(xMousePos && yMousePos) { this.DMSpanInteger = document.createElement("span") document.body.appendChild(this.DMSpanInteger); this.DMSpanInteger.outerHTML = this.options.join('') const menu = getID(`dm-${this.id}`) menu.style.zIndex = zIndex + 2 zIndex+=1 menu.style.left = (xMousePos - 40) + "px" menu.style.top = (yMousePos - 40) + "px" } this.#enableHide = false document.addEventListener("click", () => { this.hide() }) } get(action) { return getID(this.id + "_" + action) } hide() { const menu = getID(`dm-${this.id}`) if(menu) { menu.outerHTML = "" } } } /** * Permet de créer un composant de type "Serveur" */ class Server { constructor(properties) { this.name = properties.name this.description = properties.description this.icon = properties.icon } generateHTML() { return `

${this.name}

${this.description}

RAM

-- Mo / -- Mo

CPU

---%

DISK

-- Go / -- Go

` } loadScript() { const ramSpan = getID(`${this.name}_ram`) const cpuSpan = getID(`${this.name}_cpu`) const diskSpan = getID(`${this.name}_disk`) setInterval(() => { if(getID(`${this.name}_ram`)) { const request = post(`SERVER_GET_METRICS_` + this.name, this.name ) console.log(this.name) request.then((answer) => { console.log(answer) console.log(this.name) //Transform all metrics in mb to answer.metrics to Go or % answer.metrics.usedram = Math.round(answer.metrics.usedram) answer.metrics.totalram = Math.round(answer.metrics.totalram) //Transform all metrics in blocks to Go answer.metrics.usedisk = Math.round((answer.metrics.usedisk * 3.814697265625) / 1000000) answer.metrics.totaldisk = Math.round((answer.metrics.totaldisk * 3.814697265625) / 1000000) if(answer.metrics.name == this.name) { ramSpan.innerHTML = `${answer.metrics.usedram} Mo / ${answer.metrics.totalram} Mo` cpuSpan.innerHTML = answer.metrics.cpu + "%" diskSpan.innerHTML = `${answer.metrics.usedisk} Go / ${answer.metrics.totaldisk} Go` } }) } }, 1000) } } /** * Créer un composant de vue de type "Service" * @param {object} properties Propriétés du composant de vue */ class Service { name = null description = null icon = null url = null canAccess = false isOnline = false View = null constructor(properties) { this.name = properties.name this.description = properties.description this.icon = properties.icon this.url = properties.url this.canAccess = properties.canAccess this.View = properties.View } generateHTML() { return `
${this.name}

${this.name}

${this.description}

Etat : Vérification en cours ...

${this.canAccess ? `` : ""}
` } loadScript() { return new Promise((resolve, reject) => { const statusSpan = getID(`${this.name}_status`) const request = post(`SV_GET_SERVICE_STATUS`, this.url) request.then((answer) => { if(answer.name == this.url) { if(answer.answer == "ONLINE") { statusSpan.innerHTML = ' En ligne' this.isOnline = true } else { statusSpan.innerHTML = ' Hors ligne' } resolve("LOADED") } }) const powerButton = getID(`${this.name}_svpower`) // Make a popup of View to select if you want to start, stop or restart the service by doing a request powerButton.addEventListener("click", () => { this.View.createPopup({ title: ` Gestion de l'alimentation du service`, content: `

${this.name}

` }) const startButton = getID(`${this.name}_start`) const stopButton = getID(`${this.name}_stop`) const restartButton = getID(`${this.name}_restart`) const info = new TextResponse("sv-power-info") info.setWidth("350px") if(this.isOnline) { startButton.style.display = "none" info.info("Verifiez que le service n'est pas utilisé par quelqu'un d'autre avant de le redémarrer ou de l'arrêter") } else { stopButton.style.display = "none" restartButton.style.display = "none" info.info("Si le service ne démarre pas, vérifiez l'intégrité du service") } startButton.addEventListener("click", () => { const request = post(`SV_START_SERVICE`, this.url) request.then((answer) => { if(answer.answer == "OK") { statusSpan.innerHTML = ' En ligne' this.View.destroyPopup("` Gestion de l'alimentation du service`") this.isOnline = true } else { info.err("Impossible de démarrer le service") } }) }) stopButton.addEventListener("click", () => { const request = post(`SV_STOP_SERVICE`, this.url) request.then((answer) => { if(answer.answer == "OK") { statusSpan.innerHTML = ' Hors ligne' this.isOnline = false this.View.destroyPopup("` Gestion de l'alimentation du service`") } else { info.err("Impossible d'arrêter le service") } }) }) restartButton.addEventListener("click", () => { console.log("RESTART") const request = post(`SV_RESTART_SERVICE`, this.url) request.then((answer) => { if(answer.answer == "OK") { statusSpan.innerHTML = ' En ligne' this.View.destroyPopup("` Gestion de l'alimentation du service`") this.isOnline = true } else { info.err("Impossible de redémarrer le service") } }) }) }) }) } } /** * Permet de créer un composant de vue de type "Pipeline" * @param {object} properties Propriétés du composant de vue */ class Pipeline { name; pipe; class; url; View; constructor(properties) { this.name = properties.pipeline.name this.class = properties.pipeline._class this.url = properties.pipeline.url this.pipe = properties.pipeline this.View = properties.View if(!this.pipe.description) { this.pipe.description = "Aucune description" } } generateHTML() { var image = null var classInfo = null var lastBuildStatus = "" if(this.class == "hudson.model.FreeStyleProject") { image = `` if(this.pipe.lastBuild) { lastBuildStatus = `

Construction en cours ... - N°${this.pipe.nextBuildNumber - 1}

` if(this.pipe.lastSuccessfulBuild) { if(this.pipe.lastSuccessfulBuild.number == this.pipe.nextBuildNumber - 1) { lastBuildStatus = `

Dernière construction réussie - N°${this.pipe.nextBuildNumber - 1}

` } } if(this.pipe.lastFailedBuild) { if(this.pipe.lastFailedBuild.number == this.pipe.nextBuildNumber - 1) { lastBuildStatus = `

Dernière construction échouée - N°${this.pipe.nextBuildNumber - 1}

` } } } else { lastBuildStatus = `

Aucune construction

` } // TRUE : lastBuildStatus = `

Dernière construction réussie - N°${this.pipe.jobs[0].lastSuccessfulBuild.number}

` // BUILDING : lastBuildStatus = `

Construction en cours ... - N°${this.pipe.nextBuildNumber - 1}

` // FAILED : lastBuildStatus = `

Dernière construction échouée - N°${this.pipe.jobs[0].nextBuildNumber - 1}

` // NOITHING : lastBuildStatus = `

Aucune construction

` } else { image = `` if(this.pipe.jobs[0].lastBuild) { lastBuildStatus = `

Construction en cours ... - N°${this.pipe.jobs[0].nextBuildNumber - 1}

` if(this.pipe.jobs[0].lastSuccessfulBuild) { if(this.pipe.jobs[0].lastSuccessfulBuild.number == this.pipe.jobs[0].nextBuildNumber - 1) { lastBuildStatus = `

Dernière construction réussie - N°${this.pipe.jobs[0].nextBuildNumber - 1}

` } } if(this.pipe.jobs[0].lastFailedBuild) { if(this.pipe.jobs[0].lastFailedBuild.number == this.pipe.jobs[0].nextBuildNumber - 1) { lastBuildStatus = `

Dernière construction échouée - N°${this.pipe.jobs[0].nextBuildNumber - 1}

` } } } else { lastBuildStatus = `

Aucune construction

` } } return `
${image}

${this.name}

${this.pipe.description}

${lastBuildStatus}
` } loadScript() { const powerButton = getID(`${this.name}_pipelinepower`) powerButton.addEventListener("click", () => { if(this.class == "hudson.model.FreeStyleProject" && this.pipe.property[0].parameterDefinitions.length > 0) { var allProperties = new Array() for(const property of this.pipe.property[0].parameterDefinitions) { console.log(property) if(property.type == "StringParameterDefinition") { allProperties.push("

" + property.name + "

") } if(property.type == "ChoiceParameterDefinition") { var options = new Array() for(const option of property.choices) { options.push(``) } allProperties.push("

" + property.name + "

") } } this.View.createPopup({ title: ` Démarrer la pipeline`, content: `

${this.name}

${allProperties.join("")}

` }) const startButton = getID(`${this.name}_start`) const info = new TextResponse("pl-power-info") startButton.addEventListener("click", () => { info.clear() var allFields = new Array() for(const property of this.pipe.property[0].parameterDefinitions) { if(getID(property.name).value == "") { info.err("Veuillez remplir tous les champs") return } allFields.push({name: property.name,value: getID(property.name).value} ) } const request = post(`PL_START`, {name: this.name, fields: allFields, url: this.url, type: this.class}) request.then((answer) => { if(answer == "OK") { info.info("La pipeline a été démarrée avec succès") this.View.destroyPopup() } else { info.err("Impossible de démarrer la pipeline") } }) }) } else { // Open a confirmation popup to start the pipeline this.View.createPopup({ title: ` Démarrer la pipeline`, content: `

${this.name}

` }) const startButton = getID(`${this.name}_start`) const info = new TextResponse("pl-power-info") startButton.addEventListener("click", () => { info.clear() const request = post(`PL_START`, {name: this.name, url: this.url, type: this.class, jobname: this.pipe.jobs[0].name}) request.then((answer) => { console.log(answer) if(answer == "OK") { info.info("La pipeline a été démarrée avec succès") this.View.destroyPopup() } else { info.err("Impossible de démarrer la pipeline") } }) }) } }) } } class User { constructor(properties) { this.username = properties.username this.display_name = properties.display_name this.picture = properties.picture this.permission = properties.permission this.View = properties.window this.Component = properties.component } generateHTML() { return `
${this.username}

${this.display_name}

${this.username}

${this.username == "raphix" ? "" : ``}
` } loadScript() { const editButton = getID(`${this.username}_edit`) const deleteButton = getID(`${this.username}_delete`) editButton.addEventListener("click", () => { this.View.createPopup({ title: ` Editer l'utilisateur : ${this.username}`, content: `
${this.username}

${this.display_name}

${this.username}

Nom d'utilisateur

Nom d'affichage

Mot de passe

Permissions


Photo de profil


` }) const editCButton = getID(`${this.username}_cedit`) const editTokensButton = getID(`${this.username}_edittokens`) const editUsername = getID(`${this.username}_editusername`) const editDisplay = getID(`${this.username}_editdisplay`) const editPassword = getID(`${this.username}_editpassword`) const editPicture = getID(`${this.username}_addpicture`) const returnInfo = new TextResponse(`${this.username}_returninfo`) const editPermissions = new Array() editTokensButton.addEventListener("click", () => { const request = post(`US_CLEAR_TOKENS`, this.username) request.then((answer) => { if(answer == "NO_TOKENS") { returnInfo.err("Aucun token n'a été généré pour cet utilisateur") } else { returnInfo.info("Les tokens ont été éffacés avec succès") } }) }) editPermissions.push(getID(`${this.username}_perm_FILES_EXPLORER`)) editPermissions.push(getID(`${this.username}_perm_SERVICES`)) editPermissions.push(getID(`${this.username}_perm_LINKS`)) editPermissions.push(getID(`${this.username}_perm_SERVERS`)) editPermissions.push(getID(`${this.username}_perm_PIPELINES`)) editPermissions.push(getID(`${this.username}_perm_METRICS`)) editPermissions.push(getID(`${this.username}_perm_USERS`)) editPermissions.push(getID(`${this.username}_perm_SETTINGS`)) for(const actualPerm of this.permission) { getID(`${this.username}_perm_${actualPerm}`).checked = true } editUsername.addEventListener("change", () => { editUsername.value = editUsername.value.replace(/[^a-zA-Z0-9]/g, '') }) editCButton.addEventListener("click", () => { const newPerms = new Array() for(const permission of editPermissions) { if(permission.checked) { newPerms.push(permission.id.replace(`${this.username}_perm_`, "")) } } const request = post(`US_EDIT`, {username: this.username, newusername: editUsername.value, display_name: editDisplay.value, password: editPassword.value, permissions: newPerms, picture: editPicture.files[0]}) request.then((answer) => { if(answer == "ALREADY_EXIST") { returnInfo.err("L'utilisateur existe déjà !") } else if(answer == "USERNAME_MISSING") { returnInfo.err("Le nom d'utilisateur est manquant !") } else if(answer == "DISPLAY_NAME_MISSING") { returnInfo.err("Le nom d'affichage est manquant !") } else if(answer == "PASSWORD_MISSING") { returnInfo.err("Le mot de passe est manquant !") } else { this.View.destroyPopup() this.View.destroy() this.Component.forceWindow() loadUserInfo() } }) }) }) if(this.username != "raphix") { deleteButton.addEventListener("click", () => { this.View.createPopup({ title: ` Supprimer l'utilisateur : ${this.username}`, content: `

Voulez-vous vraiment supprimer l'utilisateur ${this.username} ?

` }) const deleteCButton = getID(`${this.username}_deleteconfirm`) deleteCButton.addEventListener("click", () => { const request = post(`US_DELETE`, this.username) request.then((answer) => { if(answer == "OK") { this.View.destroyPopup() this.View.destroy() this.Component.forceWindow() } else { console.log(answer) } }) }) }) } } } /** * Permet de créer un composant de vue de type "Metrics" */ class Metric { properties; View; Component; data; constructor(settings) { this.properties = settings.properties this.View = settings.View this.Component = settings.Component this.data = settings.properties.data } generateHTML() { return `

${this.properties.name}

${this.properties.id}

` } loadScript() { const contentDiv = getID(`${this.properties.id}_content`) if(this.data == "ERROR") { contentDiv.innerHTML += `

Impossible de charger les données de la métrique

` } else { for(const data of this.data) { contentDiv.innerHTML += `

${data.description}

${data.name}

Valeur : ${data.value}

` } } const deleteButton = getID(`${this.properties.id}_metricpower`) deleteButton.addEventListener("click", () => { this.View.createPopup({ title: ` Supprimer la métrique : ${this.properties.name}`, content: `

Voulez-vous vraiment supprimer la métrique ${this.properties.name} ?

` }) const deleteCButton = getID(`${this.properties.id}_deleteconfirm`) deleteCButton.addEventListener("click", () => { const request = post(`MT_DELETE`, this.properties.id) request.then((answer) => { if(answer == "OK") { this.View.destroyPopup() this.View.destroy() this.Component.forceWindow() } else { console.log(answer) } }) }) }) } } /** * Permet de créer un item de la barre des tâches * @param {ViewWindow} window ViewWindow associé à l'item */ class ViewItem { /** * * @param {ViewWindow} window */ constructor(window) { this.window = window } show() { const viewItems = getID("views-items") const item = document.createElement("div") item.id = `${this.window.ViewProperties.title}_item` item.classList.add("view-item") item.innerHTML = this.window.ViewProperties.title viewItems.appendChild(item) item.addEventListener("click", () => { zIndex+=1 this.window.ViewWindowDiv.style.zIndex = zIndex + 1 this.window.ViewWindowDiv.style.display = "unset" }) item.addEventListener("contextmenu", () => { const dp = new DroppableMenu() dp.add("index", ` Afficher`) dp.add("close", ` Fermer`) dp.show() const index = dp.get("index") const close = dp.get("close") index.addEventListener("click", () => { zIndex+=1 this.window.ViewWindowDiv.style.display = "unset" this.window.ViewWindowDiv.style.zIndex = zIndex + 1 dp.hide() }) close.addEventListener("click", () => { this.window.destroy() dp.hide() }) }) } hide() { const viewItems = getID("views-items") const item = getID(`${this.window.ViewProperties.title}_item`) item.outerHTML = "" } }