first trigger of builds via GUI
This commit is contained in:
parent
56b5598c15
commit
0e0be14415
|
@ -0,0 +1,3 @@
|
||||||
|
.hidden{
|
||||||
|
display: none;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<script type="module" src="cibuild.js"></script>
|
||||||
|
<link rel="stylesheet" href="cibuild.css"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Build your own ESP32-NMEA2000</h1>
|
||||||
|
<div class="xrow">
|
||||||
|
<label>Board type</label>
|
||||||
|
<input type="text" id="environment" value="m5stack-atom-generic">
|
||||||
|
</div>
|
||||||
|
<div class="xrow">
|
||||||
|
<label>Build Flags</label>
|
||||||
|
<input type="text" id="buildflags" value="">
|
||||||
|
</div>
|
||||||
|
<div class="xrow">
|
||||||
|
<button id="start">Start</button>
|
||||||
|
</div>
|
||||||
|
<div class="xrow">
|
||||||
|
<label>Pipeline Id</label>
|
||||||
|
<div id="pipeline">---</div>
|
||||||
|
</div>
|
||||||
|
<div class="xrow">
|
||||||
|
<label>Status</label>
|
||||||
|
<div id="status">---</div>
|
||||||
|
</div>
|
||||||
|
<div class="xrow hidden">
|
||||||
|
<a target="_" id="link">WebStatus</a>
|
||||||
|
</div>
|
||||||
|
<div class="xrow hidden">
|
||||||
|
<button id="download">Download</button>
|
||||||
|
</div>
|
||||||
|
<iframe id="dlframe" width="1" height="1"></iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { setButtons,fillValues, setValue, buildUrl, fetchJson, setVisible, enableEl } from "./helper";
|
||||||
|
(function(){
|
||||||
|
const STATUS_INTERVAL=2000;
|
||||||
|
const CURRENT_PIPELINE='pipeline';
|
||||||
|
let API="cibuild.php";
|
||||||
|
let currentPipeline=undefined;
|
||||||
|
let downloadUrl=undefined;
|
||||||
|
let timer=undefined;
|
||||||
|
const fetchStatus=()=>{
|
||||||
|
if (currentPipeline === undefined) return;
|
||||||
|
fetchJson(API,{api:'status',pipeline:currentPipeline})
|
||||||
|
.then((st)=>{
|
||||||
|
setValue('status',st.status);
|
||||||
|
let l=document.getElementById('link');
|
||||||
|
if (l){
|
||||||
|
if (st.status_url){
|
||||||
|
l.setAttribute('href',st.status_url);
|
||||||
|
setVisible(l.parentElement,true);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
setVisible(l.parentElement,false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (st.status === 'success'){
|
||||||
|
enableEl('start',true);
|
||||||
|
fetchJson(API,{api:'artifacts',pipeline:currentPipeline})
|
||||||
|
.then((ar)=>{
|
||||||
|
if (! ar.items || ar.items.length < 1){
|
||||||
|
throw new Error("no download link");
|
||||||
|
}
|
||||||
|
downloadUrl=ar.items[0].url;
|
||||||
|
setVisible(document.getElementById('download'),true,true);
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch((err)=>alert("Unable to get build result: "+err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
setVisible(document.getElementById('download'),false,true);
|
||||||
|
}
|
||||||
|
timer=window.setTimeout(fetchStatus,STATUS_INTERVAL)
|
||||||
|
})
|
||||||
|
.catch((e)=>{
|
||||||
|
timer=window.setTimeout(fetchStatus,STATUS_INTERVAL);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const setCurrentPipeline=(pipeline)=>{
|
||||||
|
currentPipeline=pipeline;
|
||||||
|
window.localStorage.setItem(CURRENT_PIPELINE,pipeline);
|
||||||
|
};
|
||||||
|
const startBuild=()=>{
|
||||||
|
let param={};
|
||||||
|
currentPipeline=undefined;
|
||||||
|
if (timer) window.clearTimeout(timer);
|
||||||
|
timer=undefined;
|
||||||
|
fillValues(param,['environment','buildflags']);
|
||||||
|
setValue('status','requested');
|
||||||
|
fetchJson(API,Object.assign({
|
||||||
|
api:'start'},param))
|
||||||
|
.then((json)=>{
|
||||||
|
if (json.status === 'error'){
|
||||||
|
throw new Error("unable to create job "+(json.error||''));
|
||||||
|
}
|
||||||
|
if (!json.id) throw new Error("unable to create job, no id");
|
||||||
|
setCurrentPipeline(json.id);
|
||||||
|
setValue('pipeline',currentPipeline);
|
||||||
|
setValue('status',json.status);
|
||||||
|
enableEl('start',false);
|
||||||
|
timer=window.setTimeout(fetchStatus,STATUS_INTERVAL);
|
||||||
|
})
|
||||||
|
.catch((err)=>{
|
||||||
|
setValue('status','error');
|
||||||
|
enableEl('start',true);
|
||||||
|
alert(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const runDownload=()=>{
|
||||||
|
if (! downloadUrl) return;
|
||||||
|
let df=document.getElementById('dlframe');
|
||||||
|
if (df){
|
||||||
|
df.setAttribute('src',null);
|
||||||
|
df.setAttribute('src',downloadUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const btConfig={
|
||||||
|
start:startBuild,
|
||||||
|
download:runDownload
|
||||||
|
};
|
||||||
|
window.onload=()=>{
|
||||||
|
setButtons(btConfig);
|
||||||
|
currentPipeline=window.localStorage.getItem(CURRENT_PIPELINE);
|
||||||
|
if (currentPipeline){
|
||||||
|
setValue('pipeline',currentPipeline);
|
||||||
|
enableEl('start',false);
|
||||||
|
fetchStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
|
@ -0,0 +1,96 @@
|
||||||
|
const getParam = (key) => {
|
||||||
|
let value = RegExp("" + key + "[^&]+").exec(window.location.search);
|
||||||
|
// Return the unescaped value minus everything starting from the equals sign or an empty string
|
||||||
|
return decodeURIComponent(!!value ? value.toString().replace(/^[^=]+./, "") : "");
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* add an HTML element
|
||||||
|
* @param {*} type
|
||||||
|
* @param {*} clazz
|
||||||
|
* @param {*} parent
|
||||||
|
* @param {*} text
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const addEl = (type, clazz, parent, text) => {
|
||||||
|
let el = document.createElement(type);
|
||||||
|
if (clazz) {
|
||||||
|
if (!(clazz instanceof Array)) {
|
||||||
|
clazz = clazz.split(/ */);
|
||||||
|
}
|
||||||
|
clazz.forEach(function (ce) {
|
||||||
|
el.classList.add(ce);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (text) el.textContent = text;
|
||||||
|
if (parent) parent.appendChild(el);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* call a function for each matching element
|
||||||
|
* @param {*} selector
|
||||||
|
* @param {*} cb
|
||||||
|
*/
|
||||||
|
const forEachEl = (selector, cb) => {
|
||||||
|
let arr = document.querySelectorAll(selector);
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
cb(arr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setButtons=(config)=>{
|
||||||
|
for (let k in config){
|
||||||
|
let bt=document.getElementById(k);
|
||||||
|
if (bt){
|
||||||
|
bt.addEventListener('click',config[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fillValues=(values,items)=>{
|
||||||
|
items.forEach((it)=>{
|
||||||
|
let e=document.getElementById(it);
|
||||||
|
if (e){
|
||||||
|
values[it]=e.value; //TODO: type of el
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
const setValue=(id,value)=>{
|
||||||
|
let el=document.getElementById(id);
|
||||||
|
if (! el) return;
|
||||||
|
if (el.tagName == 'DIV'){
|
||||||
|
el.textContent=value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (el.tagName == 'INPUT'){
|
||||||
|
el.value=value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const buildUrl=(url,pars)=>{
|
||||||
|
let delim=(url.match("[?]"))?"&":"?";
|
||||||
|
for (let k in pars){
|
||||||
|
url+=delim;
|
||||||
|
delim="&";
|
||||||
|
url+=encodeURIComponent(k);
|
||||||
|
url+="=";
|
||||||
|
url+=encodeURIComponent(pars[k]);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
const fetchJson=(url,pars)=>{
|
||||||
|
let furl=buildUrl(url,pars);
|
||||||
|
return fetch(furl).then((rs)=>rs.json());
|
||||||
|
}
|
||||||
|
const setVisible=(el,vis,useParent)=>{
|
||||||
|
if (! el) return;
|
||||||
|
if (useParent) el=el.parentElement;
|
||||||
|
if (! el) return;
|
||||||
|
if (vis) el.classList.remove('hidden');
|
||||||
|
else el.classList.add('hidden');
|
||||||
|
}
|
||||||
|
const enableEl=(id,en)=>{
|
||||||
|
let el=document.getElementById(id);
|
||||||
|
if (!el) return;
|
||||||
|
if (en) el.disabled=false;
|
||||||
|
else el.disabled=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getParam, addEl, forEachEl,setButtons,fillValues, setValue,buildUrl,fetchJson,setVisible, enableEl }
|
|
@ -9,9 +9,9 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
</body>
|
|
||||||
<div class="heading"></div>
|
<div class="heading"></div>
|
||||||
<div class="console"></div>
|
<div class="console"></div>
|
||||||
<div class="content"></div>
|
<div class="content"></div>
|
||||||
<div id="terminal"></div>
|
<div id="terminal"></div>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -1,10 +1,10 @@
|
||||||
import {XtermOutputHandler} from "./installUtil.js";
|
import {XtermOutputHandler} from "./installUtil.js";
|
||||||
import ESPInstaller from "./installUtil.js";
|
import ESPInstaller from "./installUtil.js";
|
||||||
|
import { addEl, getParam } from "./helper.js";
|
||||||
(function(){
|
(function(){
|
||||||
let espLoaderTerminal;
|
let espLoaderTerminal;
|
||||||
let espInstaller;
|
let espInstaller;
|
||||||
let releaseData={};
|
let releaseData={};
|
||||||
const addEl=ESPInstaller.addEl; //shorter typing
|
|
||||||
let showConsole;
|
let showConsole;
|
||||||
let hideConsole;
|
let hideConsole;
|
||||||
const enableConsole=(enable,disableBoth)=>{
|
const enableConsole=(enable,disableBoth)=>{
|
||||||
|
@ -134,8 +134,8 @@ import ESPInstaller from "./installUtil.js";
|
||||||
showError("your browser does not support the ESP flashing (no serial)");
|
showError("your browser does not support the ESP flashing (no serial)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let user = window.gitHubUser||ESPInstaller.getParam('user');
|
let user = window.gitHubUser||getParam('user');
|
||||||
let repo = window.gitHubRepo || ESPInstaller.getParam('repo');
|
let repo = window.gitHubRepo || getParam('repo');
|
||||||
if (!user || !repo) {
|
if (!user || !repo) {
|
||||||
alert("missing parameter user or repo");
|
alert("missing parameter user or repo");
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,39 +72,6 @@ class ESPInstaller{
|
||||||
// Return the unescaped value minus everything starting from the equals sign or an empty string
|
// Return the unescaped value minus everything starting from the equals sign or an empty string
|
||||||
return decodeURIComponent(!!value ? value.toString().replace(/^[^=]+./,"") : "");
|
return decodeURIComponent(!!value ? value.toString().replace(/^[^=]+./,"") : "");
|
||||||
};
|
};
|
||||||
/**
|
|
||||||
* add an HTML element
|
|
||||||
* @param {*} type
|
|
||||||
* @param {*} clazz
|
|
||||||
* @param {*} parent
|
|
||||||
* @param {*} text
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
static addEl(type, clazz, parent, text) {
|
|
||||||
let el = document.createElement(type);
|
|
||||||
if (clazz) {
|
|
||||||
if (!(clazz instanceof Array)) {
|
|
||||||
clazz = clazz.split(/ */);
|
|
||||||
}
|
|
||||||
clazz.forEach(function (ce) {
|
|
||||||
el.classList.add(ce);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (text) el.textContent = text;
|
|
||||||
if (parent) parent.appendChild(el);
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* call a function for each matching element
|
|
||||||
* @param {*} selector
|
|
||||||
* @param {*} cb
|
|
||||||
*/
|
|
||||||
static forEachEl(selector,cb){
|
|
||||||
let arr=document.querySelectorAll(selector);
|
|
||||||
for (let i=0;i<arr.length;i++){
|
|
||||||
cb(arr[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static checkAvailable(){
|
static checkAvailable(){
|
||||||
if (! navigator.serial || ! navigator.serial.requestPort) return false;
|
if (! navigator.serial || ! navigator.serial.requestPort) return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in New Issue