Merge branch 'next' into feat-add-language-support

This commit is contained in:
James Read 2025-11-10 21:53:04 +00:00 committed by GitHub
commit 9cf79863b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 62 additions and 60 deletions

View File

@ -14,12 +14,9 @@
</div> </div>
<template v-else-if="component.type == 'fieldset'"> <template v-else-if="component.type == 'fieldset'">
<fieldset> <template v-for="subcomponent in component.contents" :key="subcomponent.title">
<legend>{{ component.title }}</legend> <DashboardComponent :component="subcomponent" />
<template v-for="subcomponent in component.contents" :key="subcomponent.title"> </template>
<DashboardComponent :component="subcomponent" />
</template>
</fieldset>
</template> </template>
<div v-else> <div v-else>

View File

@ -7,30 +7,30 @@
<form @submit="handleSubmit"> <form @submit="handleSubmit">
<template v-if="actionArguments.length > 0"> <template v-if="actionArguments.length > 0">
<template v-for="arg in actionArguments" :key="arg.name" class="argument-group"> <template v-for="arg in actionArguments" :key="arg.name">
<label :for="arg.name"> <label :for="arg.name">
{{ formatLabel(arg.title) }} {{ formatLabel(arg.title) }}
</label> </label>
<datalist v-if="arg.suggestions && Object.keys(arg.suggestions).length > 0" :id="`${arg.name}-choices`"> <datalist v-if="arg.suggestions && Object.keys(arg.suggestions).length > 0" :id="`${arg.name}-choices`">
<option v-for="(suggestion, key) in arg.suggestions" :key="key" :value="key"> <option v-for="(suggestion, key) in arg.suggestions" :key="key" :value="key">
{{ suggestion }} {{ suggestion }}
</option> </option>
</datalist> </datalist>
<select v-if="getInputComponent(arg) === 'select'" :id="arg.name" :name="arg.name" :value="getArgumentValue(arg)" <select v-if="getInputComponent(arg) === 'select'" :id="arg.name" :name="arg.name" :value="getArgumentValue(arg)"
:required="arg.required" @input="handleInput(arg, $event)" @change="handleChange(arg, $event)"> :required="arg.required" @input="handleInput(arg, $event)" @change="handleChange(arg, $event)">
<option v-for="choice in arg.choices" :key="choice.value" :value="choice.value"> <option v-for="choice in arg.choices" :key="choice.value" :value="choice.value">
{{ choice.title || choice.value }} {{ choice.title || choice.value }}
</option> </option>
</select> </select>
<component v-else :is="getInputComponent(arg)" :id="arg.name" :name="arg.name" :value="getArgumentValue(arg)" <component v-else :is="getInputComponent(arg)" :id="arg.name" :name="arg.name" :value="getArgumentValue(arg)"
:list="arg.suggestions ? `${arg.name}-choices` : undefined" :list="arg.suggestions ? `${arg.name}-choices` : undefined"
:type="getInputComponent(arg) !== 'select' ? getInputType(arg) : undefined" :type="getInputComponent(arg) !== 'select' ? getInputType(arg) : undefined"
:rows="arg.type === 'raw_string_multiline' ? 5 : undefined" :rows="arg.type === 'raw_string_multiline' ? 5 : undefined"
:step="arg.type === 'datetime' ? 1 : undefined" :pattern="getPattern(arg)" :required="arg.required" :step="arg.type === 'datetime' ? 1 : undefined" :pattern="getPattern(arg)" :required="arg.required"
@input="handleInput(arg, $event)" @change="handleChange(arg, $event)" /> @input="handleInput(arg, $event)" @change="handleChange(arg, $event)" />
<span class="argument-description" v-html="arg.description"></span> <span class="argument-description" v-html="arg.description"></span>
</template> </template>
@ -96,18 +96,27 @@ async function setup() {
// Initialize values from query params or defaults // Initialize values from query params or defaults
actionArguments.value.forEach(arg => { actionArguments.value.forEach(arg => {
const paramValue = getQueryParamValue(arg.name)
argValues.value[arg.name] = paramValue !== null ? paramValue : arg.defaultValue || ''
if (arg.type === 'confirmation') { if (arg.type === 'confirmation') {
hasConfirmation.value = true hasConfirmation.value = true
const paramValue = getQueryParamValue(arg.name)
let checkedValue = false
if (paramValue !== null) {
checkedValue = paramValue === '1' || paramValue === 'true' || paramValue === true
} else if (arg.defaultValue !== undefined && arg.defaultValue !== '') {
checkedValue = arg.defaultValue === '1' || arg.defaultValue === 'true' || arg.defaultValue === true
}
argValues.value[arg.name] = checkedValue
confirmationChecked.value = checkedValue
} else {
const paramValue = getQueryParamValue(arg.name)
argValues.value[arg.name] = paramValue !== null ? paramValue : arg.defaultValue || ''
} }
}) })
// Run initial validation on all fields after DOM is updated // Run initial validation on all fields after DOM is updated
await nextTick() await nextTick()
for (const arg of actionArguments.value) { for (const arg of actionArguments.value) {
if (arg.type && !arg.type.startsWith('regex:') && arg.type !== 'select' && arg.type !== '') { if (arg.type && !arg.type.startsWith('regex:') && arg.type !== 'select' && arg.type !== '' && arg.type !== 'confirmation') {
await validateArgument(arg, argValues.value[arg.name]) await validateArgument(arg, argValues.value[arg.name])
} }
} }
@ -143,7 +152,11 @@ function getInputType(arg) {
return undefined return undefined
} }
if (arg.type === 'ascii_identifier') { if (arg.type === 'confirmation') {
return 'checkbox'
}
if (arg.type === 'ascii_identifier' || arg.type === 'ascii') {
return 'text' return 'text'
} }
@ -158,8 +171,8 @@ function getPattern(arg) {
} }
function getArgumentValue(arg) { function getArgumentValue(arg) {
if (arg.type === 'checkbox') { if (arg.type === 'checkbox' || arg.type === 'confirmation') {
return argValues.value[arg.name] === '1' || argValues.value[arg.name] === true return argValues.value[arg.name] === '1' || argValues.value[arg.name] === true || argValues.value[arg.name] === 'true'
} }
return argValues.value[arg.name] || '' return argValues.value[arg.name] || ''
} }
@ -240,7 +253,7 @@ function getArgumentValues() {
for (const arg of actionArguments.value) { for (const arg of actionArguments.value) {
let value = argValues.value[arg.name] || '' let value = argValues.value[arg.name] || ''
if (arg.type === 'checkbox') { if (arg.type === 'checkbox' || arg.type === 'confirmation') {
value = value ? '1' : '0' value = value ? '1' : '0'
} }
@ -348,22 +361,6 @@ form {
grid-template-columns: max-content auto auto; grid-template-columns: max-content auto auto;
} }
.argument-group {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.argument-group label {
font-weight: 500;
color: #333;
}
.argument-group input:invalid,
.argument-group select:invalid,
.argument-group textarea:invalid {
border-color: #dc3545;
}
.argument-description { .argument-description {
font-size: 0.875rem; font-size: 0.875rem;

View File

@ -104,7 +104,7 @@ let terminal = null
function initializeTerminal() { function initializeTerminal() {
terminal = new OutputTerminal(executionTrackingId.value) terminal = new OutputTerminal(executionTrackingId.value)
terminal.open(xtermOutput.value) terminal.open(xtermOutput.value)
terminal.resize(80, 24) terminal.resize(80, 40)
window.terminal = terminal window.terminal = terminal
} }
@ -327,6 +327,17 @@ function goBack() {
} }
onMounted(() => { onMounted(() => {
document.addEventListener('fullscreenchange', (e) => {
setTimeout(() => { // Wait for the DOM to settle
if (document.fullscreenElement) {
window.terminal.fit()
} else {
window.terminal.resize(80, 40)
window.terminal.fit()
}
}, 100)
})
initializeTerminal() initializeTerminal()
fetchExecutionResult(props.executionTrackingId) fetchExecutionResult(props.executionTrackingId)

View File

@ -43,7 +43,7 @@ describe('config: dashboards with basic fieldsets', function () {
// Check that we have the expected number of fieldsets // Check that we have the expected number of fieldsets
const allFieldsets = await webdriver.findElements(By.css('fieldset')) const allFieldsets = await webdriver.findElements(By.css('fieldset'))
expect(allFieldsets).to.have.length(5, 'Expected 5 fieldsets total') expect(allFieldsets).to.have.length(3, 'Expected 3 fieldsets total')
// Check that we have fieldsets with the expected titles // Check that we have fieldsets with the expected titles
const fieldsetTitles = [] const fieldsetTitles = []

View File

@ -89,13 +89,10 @@ func buildDefaultDashboard(rr *DashboardRenderRequest) *apiv1.Dashboard {
} }
func sortActions(components []*apiv1.DashboardComponent) []*apiv1.DashboardComponent { func sortActions(components []*apiv1.DashboardComponent) []*apiv1.DashboardComponent {
log.Infof("sortActions: %+v", components)
sort.Slice(components, func(i, j int) bool { sort.Slice(components, func(i, j int) bool {
if components[i].Action == nil { if components[i].Action == nil || components[j].Action == nil {
return false return components[i].Title < components[j].Title
}
if components[j].Action == nil {
return true
} }
if components[i].Action.Order == components[j].Action.Order { if components[i].Action.Order == components[j].Action.Order {