mirror of
git://git.yoctoproject.org/yocto-autobuilder2.git
synced 2025-07-19 20:59:02 +02:00
yocto_console_view: Add release selector
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
This commit is contained in:
parent
c8f1590596
commit
58efe8c055
|
@ -16,3 +16,4 @@
|
|||
*/
|
||||
|
||||
import './views/ConsoleView/ConsoleView';
|
||||
import './releaseselectorfield';
|
||||
|
|
152
yocto_console_view/src/releaseselectorfield.ts
Normal file
152
yocto_console_view/src/releaseselectorfield.ts
Normal file
|
@ -0,0 +1,152 @@
|
|||
import {buildbotSetupPlugin} from "buildbot-plugin-support";
|
||||
buildbotSetupPlugin((reg) => {
|
||||
let selectListName = null;
|
||||
let inputRefs = null;
|
||||
let selectors = null;
|
||||
|
||||
const onTransitionEndEvent = (event) => {
|
||||
/*
|
||||
* We are looking for the transition showing the "forcebuild" dialog.
|
||||
*/
|
||||
if (!event.target.classList.contains("bb-forcebuild-modal"))
|
||||
return
|
||||
|
||||
/*
|
||||
* Find modal-body div.
|
||||
*/
|
||||
const modalDialog = Array.from(event.target.children).find(e => e.classList.contains("modal-dialog"));
|
||||
const modalContent = modalDialog ? Array.from(modalDialog.children).find(e => e.classList.contains("modal-content")) : null;
|
||||
const modalBody = modalContent ? Array.from(modalContent.children).find(e => e.classList.contains("modal-body")) : null;
|
||||
if (!modalBody)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Generate a map of all inputs, identifed by the field name.
|
||||
*/
|
||||
inputRefs = new Map();
|
||||
document.querySelectorAll('input').forEach(input => {
|
||||
let idparent = input;
|
||||
while (!idparent.attributes.getNamedItem('data-bb-test-id')
|
||||
&& idparent.parentElement != modalBody) {
|
||||
idparent = idparent.parentElement;
|
||||
}
|
||||
|
||||
const id = idparent.attributes.getNamedItem('data-bb-test-id')
|
||||
if (id)
|
||||
inputRefs.set(id.value, input);
|
||||
|
||||
prepareInterceptor(input);
|
||||
});
|
||||
|
||||
/*
|
||||
* Only show the pretty name in the release selector field.
|
||||
*/
|
||||
const releaseSelector = inputRefs.get('force-field-branchselector');
|
||||
const releaseSelectorLabel = releaseSelector.parentNode.previousSibling;
|
||||
const sepIdx = releaseSelectorLabel.textContent.indexOf(':');
|
||||
releaseSelectorLabel.textContent = releaseSelectorLabel.textContent.substring(0, sepIdx);
|
||||
|
||||
/*
|
||||
* Get the name of the ReleaseSelector field div.
|
||||
*/
|
||||
const branchInputId = releaseSelector.attributes.getNamedItem('id').value;
|
||||
const selectName = branchInputId.substring(0, branchInputId.lastIndexOf('-'));
|
||||
selectListName = selectName + '-listbox';
|
||||
}
|
||||
window.addEventListener('transitionend', onTransitionEndEvent);
|
||||
|
||||
const onClick = (event) => {
|
||||
if (selectListName) {
|
||||
const listDiv = document.getElementById(selectListName);
|
||||
if (listDiv) {
|
||||
/*
|
||||
* The ReleaseSelector menu is shown: save
|
||||
* associated selectors for later and clean menu items.
|
||||
*/
|
||||
selectors = new Map();
|
||||
listDiv.childNodes.forEach(div => {
|
||||
const sepIdx = div.textContent.indexOf(':');
|
||||
const propName = div.textContent.substring(0, sepIdx);
|
||||
const content = div.textContent.substring(sepIdx + 1);
|
||||
div.textContent = propName
|
||||
selectors.set(propName, JSON.parse(content));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (event.target.parentElement) {
|
||||
const parentId = event.target.parentElement.attributes.getNamedItem('id');
|
||||
if (parentId && parentId.value == selectListName) {
|
||||
/*
|
||||
* One entry was clicked in the ReleaseSelector
|
||||
* menu: update all fields described by the
|
||||
* selector configuration.
|
||||
*/
|
||||
const selector = selectors.get(event.target.textContent);
|
||||
if (selector) {
|
||||
new Promise((resolve, reject) => {
|
||||
return applySelector(selector, event.target).then(resolve);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
window.addEventListener('click', onClick);
|
||||
|
||||
/*
|
||||
* Apply values from the selected field selector
|
||||
*/
|
||||
async function applySelector(selector, selectList) {
|
||||
for (let [field, value] of Object.entries(selector)) {
|
||||
const input = inputRefs.get('force-field-' + field);
|
||||
if (input && input.value != value) {
|
||||
/*
|
||||
* Setting value using input.value is not enough here: field
|
||||
* would appear modified but this value would not be used on
|
||||
* form submission.
|
||||
*/
|
||||
await setFieldValue(input, value);
|
||||
}
|
||||
}
|
||||
|
||||
const releaseSelector = inputRefs.get('force-field-branchselector');
|
||||
releaseSelector.parentNode.previousSibling.textContent = selectList.textContent;
|
||||
releaseSelector.focus();
|
||||
}
|
||||
|
||||
/*
|
||||
* All code below is highly based on work from testing-library/user-event:
|
||||
* https://github.com/testing-library/user-event
|
||||
* The MIT License (MIT)
|
||||
* Copyright (c) 2020 Giorgio Polvara
|
||||
*/
|
||||
function prepareInterceptor(element) {
|
||||
const prototypeDescriptor = Object.getOwnPropertyDescriptor(element.constructor.prototype, 'value');
|
||||
const objectDescriptor = Object.getOwnPropertyDescriptor(element, 'value');
|
||||
Object.defineProperty(element, 'value', {
|
||||
objectDescriptor,
|
||||
['set']: function(v) {
|
||||
const realFunc = prototypeDescriptor['set'];
|
||||
realFunc.call(this, v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const UIValue = Symbol('Displayed value in UI');
|
||||
async function setFieldValue(element, value) {
|
||||
element.focus();
|
||||
element[UIValue] = value;
|
||||
element.value = Object.assign(new String(value), {
|
||||
[UIValue]: true
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('blur', (e)=>{
|
||||
const event = new Event('change', {bubbles: true, target: e.target, cancelable: false});
|
||||
e.target.dispatchEvent(event);
|
||||
}, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
|
||||
});
|
36
yocto_console_view/yocto_console_view/__init__.py
Normal file
36
yocto_console_view/yocto_console_view/__init__.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
# This file is part of Buildbot. Buildbot is free software: you can
|
||||
# redistribute it and/or modify it under the terms of the GNU General Public
|
||||
# License as published by the Free Software Foundation, version 2.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Copyright Buildbot Team Members
|
||||
|
||||
from buildbot.www.plugin import Application
|
||||
from buildbot.schedulers.forcesched import ChoiceStringParameter
|
||||
|
||||
import json
|
||||
|
||||
# create the interface for the setuptools entry point
|
||||
ep = Application(__package__, "Yocto Buildbot Console View plugin")
|
||||
|
||||
class ReleaseSelector(ChoiceStringParameter):
|
||||
|
||||
spec_attributes = ["selectors"]
|
||||
selectors = None
|
||||
|
||||
def __init__(self, name, selectors, **kw):
|
||||
def format_choice(choice):
|
||||
return choice + ': ' + json.dumps(selectors.get(choice, {}))
|
||||
|
||||
super().__init__(name, **kw)
|
||||
self.choices = [format_choice(choice)
|
||||
for choice in kw.get('choices', {})]
|
||||
self.__dict__['default'] = format_choice(self.__dict__['default'])
|
Loading…
Reference in New Issue
Block a user