v0.4.63: SSO row alignment, themed checkbox, dropdown affordance
Three UI nits the operator caught on v0.4.62, plus the queued PXE-theme research note for the next release. - SSO header grid is now a 4-column form-row matching the Administrator account card column-for-column (display name / logo URL / metadata source / metadata URL). Switching to XML mode collapses column 4 and drops the multi-line textarea on its own full-width row below. - Native form chrome (checkboxes, scroll bars) follows the active OpenPXE theme via CSS `color-scheme`; the inline meta tag was forcing dark form controls in light mode, which is why the "Enable single sign-on" checkbox rendered as an opaque black square against the light panel. - Checkbox itself is now custom-styled (16x16 rounded square, accent fill + tick on :checked) so the chrome reads identically across both palettes and browsers, not just on whichever WebKit happens to honor `accent-color`. - <select> dropdowns get a hand-drawn chevron via background-image SVG; with `-webkit-appearance: none` the native arrow had disappeared, making "Metadata source" look squished next to the inputs beside it. - Update credentials + Save SSO settings buttons get explicit top margins so they sit clearly under their input rows instead of butting against the field beneath. - `docs/queued/ipxe-pxe-menu-theme-research.md` captures findings on how iVentoy paints its boot menu (iPXE `console --picture` with baked-in per-resolution PNGs, no EDID auto-detect) and the recommended Rust architecture for the follow-up release. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
d729a7ae2f
commit
9f694f7c79
+32
-15
@@ -1025,7 +1025,11 @@
|
||||
const newPwConfirm = el('input', {type:'password', autocomplete:'new-password',
|
||||
placeholder: 'confirm new password'});
|
||||
const accountMsg = el('div', {class:'msg', style:'margin-top:8px'});
|
||||
const accountSave = el('button', {onclick: async () => {
|
||||
// v0.4.63: explicit top margin so the action button sits clearly
|
||||
// beneath the input row instead of butting against the password
|
||||
// fields. Mirrors the `Save SSO settings` button below for visual
|
||||
// parity between the two settings cards.
|
||||
const accountSave = el('button', {style:'margin-top:6px', onclick: async () => {
|
||||
accountMsg.textContent = ''; accountMsg.className = 'msg';
|
||||
if (!currentPw.value) {
|
||||
accountMsg.textContent = 'Current password is required.';
|
||||
@@ -1130,29 +1134,39 @@
|
||||
el('option', {value:'xml'}, 'Metadata XML'),
|
||||
]);
|
||||
ssoMode.value = sso.metadata && !sso.metadata_url ? 'xml' : 'url';
|
||||
// v0.4.63: the IdP metadata URL now sits inside the 4-col header
|
||||
// grid as column 4, so the SSO row is column-for-column aligned with
|
||||
// the Administrator account row above. When the operator switches
|
||||
// to XML mode, column 4 collapses (display:none) and the multi-line
|
||||
// XML textarea takes its own full-width row below — there's no way
|
||||
// to fit a 6-row textarea into a single grid cell without making
|
||||
// the rest of the row look stretched.
|
||||
const urlWrap = el('label', {class:'field'}, [
|
||||
el('span', {class:'name'}, 'IdP metadata URL'),
|
||||
ssoUrl,
|
||||
el('span', {class:'hint'},
|
||||
'OpenPXE will fetch this URL once SSO sign-in lands; v0.4.6 just stores it.'),
|
||||
]);
|
||||
const xmlWrap = el('label', {class:'field'}, [
|
||||
const xmlWrap = el('label', {class:'field', style:'margin-top:14px'}, [
|
||||
el('span', {class:'name'}, 'IdP metadata XML'),
|
||||
ssoXml,
|
||||
el('span', {class:'hint'},
|
||||
'Paste the raw <EntityDescriptor>…</EntityDescriptor> document from your IdP.'),
|
||||
]);
|
||||
// Hint that used to live under the URL field; surfaced once below
|
||||
// the whole row so it doesn't compete with the in-grid layout.
|
||||
const urlHint = el('p', {class:'msg', style:'margin-top:10px;margin-bottom:0'},
|
||||
'OpenPXE will fetch the metadata URL once SSO sign-in lands; v0.4.63 stores it.');
|
||||
const refreshSsoFields = () => {
|
||||
if (ssoMode.value === 'url') {
|
||||
urlWrap.style.display = ''; xmlWrap.style.display = 'none';
|
||||
urlHint.style.display = '';
|
||||
} else {
|
||||
urlWrap.style.display = 'none'; xmlWrap.style.display = '';
|
||||
urlHint.style.display = 'none';
|
||||
}
|
||||
};
|
||||
ssoMode.onchange = refreshSsoFields;
|
||||
refreshSsoFields();
|
||||
const ssoMsg = el('div', {class:'msg', style:'margin-top:8px'});
|
||||
const ssoSave = el('button', {onclick: async () => {
|
||||
const ssoSave = el('button', {style:'margin-top:16px', onclick: async () => {
|
||||
ssoMsg.textContent = ''; ssoMsg.className = 'msg';
|
||||
const payload = {
|
||||
enabled: ssoEnabled.checked,
|
||||
@@ -1193,32 +1207,35 @@
|
||||
ssoEnabled,
|
||||
el('span', {}, 'Enable single sign-on'),
|
||||
]),
|
||||
// 3-column header strip: display name, logo URL, metadata
|
||||
// source. All three controls inherit the same border/padding/
|
||||
// focus chrome from the global `label.field input/select`
|
||||
// rule, so they line up cleanly. Below: the active source
|
||||
// field (URL or XML) spans the full width.
|
||||
el('div', {class:'form-row cols-3'}, [
|
||||
// v0.4.63: 4-column form-row that matches the Administrator
|
||||
// account card above column-for-column — display name / logo
|
||||
// URL / metadata source / metadata URL. All four controls share
|
||||
// the same `label.field` chrome so they line up cleanly. When
|
||||
// the operator picks "Metadata XML" the URL column collapses
|
||||
// and the multi-line textarea drops below the row.
|
||||
el('div', {class:'form-row'}, [
|
||||
el('label', {class:'field'}, [
|
||||
el('span', {class:'name'}, 'IdP display name'),
|
||||
ssoName,
|
||||
el('span', {class:'hint'}, '"Sign in with X" label on the login screen.'),
|
||||
]),
|
||||
el('label', {class:'field'}, [
|
||||
el('span', {class:'name'}, 'IdP logo URL'),
|
||||
ssoLogo,
|
||||
el('span', {class:'hint'}, 'Optional. Shown next to the IdP name on the login button.'),
|
||||
]),
|
||||
el('label', {class:'field'}, [
|
||||
el('span', {class:'name'}, 'Metadata source'),
|
||||
ssoMode,
|
||||
]),
|
||||
urlWrap,
|
||||
]),
|
||||
urlWrap,
|
||||
xmlWrap,
|
||||
urlHint,
|
||||
ssoSave, ssoMsg,
|
||||
]),
|
||||
]);
|
||||
// Wire up + paint the initial visibility now that all elements
|
||||
// referenced by `refreshSsoFields` are attached.
|
||||
refreshSsoFields();
|
||||
|
||||
// ── Custom logo upload.
|
||||
// Single-file drop-zone; PNG/SVG/JPEG/WebP/GIF up to 2 MB.
|
||||
|
||||
Reference in New Issue
Block a user