Skip to content

Commit f56b433

Browse files
committed
fix: execution-prompt implementation (#4)
1 parent f2f5e41 commit f56b433

File tree

4 files changed

+117
-41
lines changed

4 files changed

+117
-41
lines changed

frontend/src/base/sub/Jobs.svelte

Lines changed: 81 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script lang="ts">
22
import { onMount } from 'svelte';
3+
import { fade } from 'svelte/transition';
34
45
import {
56
InfoCircleSolid, PlaySolid, StopSolid, TrashBinSolid, EditSolid, FileCloneSolid, BookOpenSolid,
@@ -16,6 +17,7 @@
1617
import { classModalLabel } from '../Style.js';
1718
import { tq } from '../../util/translate.js';
1819
import { apiEdit, apiGet } from '../../util/api.js';
20+
import { choicesFromArray } from '../../util/form.js';
1921
import { type executionPromptsType } from './Config.js';
2022
import {
2123
classModalBackdrop, classModalBtns, classPopover, classPopoverTitle, classPopoverColumn1,
@@ -86,6 +88,7 @@
8688
let jobList: jobInfos[] = $state([]);
8789
let jobActions = $state({});
8890
let apiError = $state('');
91+
let apiSuccess = $state('');
8992
9093
interface executionPromptsFieldValues {
9194
tags: string,
@@ -149,6 +152,9 @@
149152
if (a) {
150153
a.scrollIntoView({behavior: "smooth", block: "end", inline: "end"});
151154
}
155+
} else {
156+
apiSuccess = t('common.success');
157+
setTimeout(() => {apiSuccess = ''}, 6000);
152158
}
153159
}
154160
@@ -170,8 +176,31 @@
170176
if (!jobId) {
171177
return;
172178
}
173-
// todo: add execution prompt values
174-
apiEdit('post', `job/${jobId}`, undefined, showAPIErrors);
179+
let promptData = {};
180+
181+
for (let f of executionPrompts.config.fields) {
182+
promptData[f] = executionPrompts.field_values[f];
183+
}
184+
185+
if (executionPrompts.config.vars.length) {
186+
let c: string[] = [];
187+
188+
for (let [k, v] of Object.entries(executionPrompts.var_values)) {
189+
if (v && v.trim()) {
190+
c.push(`-e "${k}=${v}"`)
191+
}
192+
}
193+
194+
if (c.length) {
195+
if (!executionPrompts.config.fields.includes('cmd_args')) {
196+
promptData['cmd_args'] = '';
197+
}
198+
promptData['cmd_args'] += ` ${c.join(' ')}`
199+
}
200+
}
201+
202+
apiEdit('post', `job/${jobId}`, promptData, showAPIErrors);
203+
jobActions[jobId].exec = false;
175204
}
176205
177206
function updateExecutionPrompts(encodedPrompts: string|null) {
@@ -207,9 +236,18 @@
207236

208237
<div id={apiErrorAlert} class="h-0"></div>
209238
{#if apiError}
210-
<Alert border color="red" class="text-wrap">
211-
<CloseCircleSolid slot="icon" class="w-5 h-5" /> {apiError}
212-
</Alert>
239+
<div transition:fade>
240+
<Alert border color="red" class="text-wrap">
241+
<CloseCircleSolid slot="icon" class="w-5 h-5" /> {apiError}
242+
</Alert>
243+
</div>
244+
{/if}
245+
{#if apiSuccess}
246+
<div transition:fade>
247+
<Alert border color="green" class="text-wrap">
248+
<InfoCircleSolid slot="icon" class="w-5 h-5" /> {apiSuccess}
249+
</Alert>
250+
</div>
213251
{/if}
214252
<div>
215253
<Table striped={true}>
@@ -230,7 +268,7 @@
230268
{job.name}
231269
<button id="job-name-{job.id}" class="ml-1">
232270
<InfoCircleSolid size="sm"/>
233-
<span class="sr-only">Show Job Information</span>
271+
<span class="sr-only">{t('jobs.info')}</span>
234272
</button>
235273
</TableBodyCell>
236274
<TableBodyCell class="max-lg:hidden">{job.inventory_file ? job.inventory_file : '-'}</TableBodyCell>
@@ -239,7 +277,7 @@
239277
{job.next_run ? job.next_run : '-'}
240278
<button id="job-schedule-{job.id}" class="ml-1">
241279
<InfoCircleSolid size="sm"/>
242-
<span class="sr-only">Show Execution Information</span>
280+
<span class="sr-only">{t('jobs.info.execution')}</span>
243281
</button>
244282
</TableBodyCell>
245283
<TableBodyCell>
@@ -284,7 +322,7 @@
284322
<div id="job-infos-{job.id}">
285323
<Popover triggeredBy="#job-name-{job.id}" class={classPopover} placement="bottom-start">
286324
<div class="p-3 space-y-2">
287-
<h3 class={classPopoverTitle}>Job Information</h3>
325+
<h3 class={classPopoverTitle}>{t('jobs.info')}</h3>
288326
</div>
289327
<table>
290328
<tbody>
@@ -355,12 +393,12 @@
355393
</Popover>
356394
<Popover triggeredBy="#job-schedule-{job.id}" class={classPopover} placement="bottom-start">
357395
<div class="p-3 space-y-2">
358-
<h3 class={classPopoverTitle}>Execution Information</h3>
396+
<h3 class={classPopoverTitle}>{t('jobs.info.execution')}</h3>
359397
<table>
360398
<tbody>
361399
<tr>
362400
<td class={classPopoverColumn1}>
363-
Schedule Enabled:
401+
{t('jobs.form.enabled')}:
364402
</td>
365403
<td class={classPopoverColumn2Div}>
366404
<button class="cursor-default">
@@ -370,15 +408,15 @@
370408
</tr>
371409
<tr>
372410
<td class={classPopoverColumn1}>
373-
Schedule Cron:
411+
{t('jobs.form.schedule')}:
374412
</td>
375413
<td class={classPopoverColumn2Text}>
376414
{job.schedule ? job.schedule : '-'}
377415
</td>
378416
</tr>
379417
<tr>
380418
<td class={classPopoverColumn1}>
381-
Next Run:
419+
{t('jobs.info.next_run')}:
382420
</td>
383421
<td class={classPopoverColumn2Text}>
384422
{job.next_run ? job.next_run : '-'}
@@ -387,31 +425,31 @@
387425
{#if job.executions.length}
388426
<tr>
389427
<td class={classPopoverColumn1}>
390-
Last Run:
428+
{t('jobs.info.last_run')}:
391429
</td>
392430
<td class={classPopoverColumn2Text}>
393431
{job.executions[0].time_start}
394432
</td>
395433
</tr>
396434
<tr>
397435
<td class={classPopoverColumn1}>
398-
Status:
436+
{t('common.status')}:
399437
</td>
400438
<td class={classPopoverColumn2Text}>
401439
{job.executions[0].status_name}
402440
</td>
403441
</tr>
404442
<tr>
405443
<td class={classPopoverColumn1}>
406-
Duration:
444+
{t('jobs.info.duration')}:
407445
</td>
408446
<td class={classPopoverColumn2Text}>
409447
{job.executions[0].time_duration}
410448
</td>
411449
</tr>
412450
<tr>
413451
<td class={classPopoverColumn1}>
414-
Failed:
452+
{t('jobs.info.failed')}:
415453
</td>
416454
<td class={classPopoverColumn2Div}>
417455
<button class="cursor-default">
@@ -422,7 +460,7 @@
422460
{#if job.executions[0].failed}
423461
<tr>
424462
<td class={classPopoverColumn1}>
425-
Error:
463+
{t('common.error')}:
426464
</td>
427465
<td class={classPopoverColumn2Div}>
428466
<Alert color="red" border>{job.executions[0].error_s}</Alert>
@@ -435,24 +473,26 @@
435473
</div>
436474
</Popover>
437475
<Modal bind:open={jobActions[job.id].exec} size="sm" autoclose={true} placement="top-center" backdropClass={classModalBackdrop}>
438-
<Heading tag="h2">Execute Job</Heading>
476+
<Heading tag="h2">{t('jobs.execute')}</Heading>
439477

440478
{#if executionPrompts.config.fields.includes('limit')}
441479
<Label for="job_prompt_{job.id}_limit" class={classModalLabel}>{t('jobs.form.limit')}</Label>
442480
<Input id="job_prompt_{job.id}_limit" bind:value={executionPrompts.field_values.limit} />
443481
{/if}
444-
{#if executionPrompts.config.fields.includes('mode_check')}
445-
<Label for="job_prompt_{job.id}_mode_check" class={classModalLabel}>{t('jobs.form.mode_check')}</Label>
446-
<div class={classCenterChildDiv}>
447-
<Toggle id="job_prompt_{job.id}_mode_check" bind:checked={executionPrompts.field_values.mode_check} />
448-
</div>
449-
{/if}
450-
{#if executionPrompts.config.fields.includes('mode_diff')}
451-
<Label for="job_prompt_{job.id}_mode_diff" class={classModalLabel}>{t('jobs.form.mode_diff')}</Label>
452-
<div class={classCenterChildDiv}>
453-
<Toggle id="job_prompt_{job.id}_mode_diff" bind:checked={executionPrompts.field_values.mode_diff} />
454-
</div>
455-
{/if}
482+
<div>
483+
{#if executionPrompts.config.fields.includes('mode_check')}
484+
<Label for="job_prompt_{job.id}_mode_check" class={classModalLabel}>{t('jobs.form.mode_check')}</Label>
485+
<div class={classCenterChildDiv}>
486+
<Toggle id="job_prompt_{job.id}_mode_check" bind:checked={executionPrompts.field_values.mode_check} />
487+
</div>
488+
{/if}
489+
{#if executionPrompts.config.fields.includes('mode_diff')}
490+
<Label for="job_prompt_{job.id}_mode_diff" class={classModalLabel}>{t('jobs.form.mode_diff')}</Label>
491+
<div class={classCenterChildDiv}>
492+
<Toggle id="job_prompt_{job.id}_mode_diff" bind:checked={executionPrompts.field_values.mode_diff} />
493+
</div>
494+
{/if}
495+
</div>
456496
{#if executionPrompts.config.fields.includes('tags')}
457497
<Label for="job_prompt_{job.id}_tags" class={classModalLabel}>{t('jobs.form.tags')}</Label>
458498
<Input id="job_prompt_{job.id}_tags" bind:value={executionPrompts.field_values.tags} />
@@ -474,6 +514,17 @@
474514
<Select id="job_prompt_{job.id}_creds" items={usableCredentialChoices}
475515
bind:value={executionPrompts.field_values.credentials} />
476516
{/if}
517+
{#each executionPrompts.config.vars as v, i (v.name)}
518+
{#if v.kind == 'text'}
519+
<Label for="job_prompt_{job.id}_var_{i}" class={classModalLabel}>{v.name}</Label>
520+
<Input id="job_prompt_{job.id}_var_{i}" bind:value={executionPrompts.var_values[v.varName]} />
521+
<!-- todo: regex validation -->
522+
{:else}
523+
<Label for="job_prompt_{job.id}_var_{i}" class={classModalLabel}>{v.name}</Label>
524+
<Select id="job_prompt_{job.id}_var_{i}" items={choicesFromArray(v.choices)}
525+
bind:value={executionPrompts.var_values[v.varName]} />
526+
{/if}
527+
{/each}
477528

478529
<div class={classModalBtns}>
479530
<!--

frontend/src/base/sub/forms/Job.svelte

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<script lang="ts">
2+
import { fade } from 'svelte/transition';
3+
24
import {
35
FolderSolid, FileSolid, CloseCircleSolid, TrashBinSolid, FloppyDiskSolid, CirclePlusSolid,
46
} from 'flowbite-svelte-icons';
@@ -341,9 +343,11 @@
341343
{:else}
342344
<div id={formErrorAlert} class="h-0"></div>
343345
{#if formError}
344-
<Alert border color="red" class="text-wrap">
345-
<CloseCircleSolid slot="icon" class="w-5 h-5" /> {formError}
346-
</Alert>
346+
<div transition:fade>
347+
<Alert border color="red" class="text-wrap">
348+
<CloseCircleSolid slot="icon" class="w-5 h-5" /> {formError}
349+
</Alert>
350+
</div>
347351
{/if}
348352
<Accordion class={classModalForm}>
349353
<AccordionItem>
@@ -553,7 +557,8 @@
553557
<div>
554558
<Label for="job_exec_prompt_limit_req" class={classModalLabel}>{t('jobs.form.prompt_limit_req')}</Label>
555559
<div class={classCenterChildDiv}>
556-
<Toggle id="job_exec_prompt_limit_req" bind:checked={executionPromptsSimple.limit_req} />
560+
<Toggle id="job_exec_prompt_limit_req" bind:checked={executionPromptsSimple.limit_req}
561+
disabled={!executionPromptsSimple.limit} />
557562
</div>
558563
</div>
559564
<div>
@@ -587,7 +592,7 @@
587592
<hr class="mt-10 mb-2">
588593
<div class={classModalInputDiv}>
589594
<div class={classModalInput}>
590-
<Label for="job_prompt_{p.id}_name" class={classModalLabel}>{t('common.name')}</Label>
595+
<Label for="job_prompt_{p.id}_name" class={classModalLabel}>{t('jobs.form.prompt_name')}</Label>
591596
<Input id="job_prompt_{p.id}_name" on:input={(e) => {valideInputInstance(e, p)}}
592597
bind:value={p.name.value} bind:color={p.name.color} />
593598
</div>
@@ -606,11 +611,13 @@
606611
<Toggle id="job_prompt_{p.id}_req" bind:checked={p.required.value} />
607612
</div>
608613
</div>
609-
<div class={classModalInput}>
610-
<Label for="job_prompt_{p.id}_choices" class={classModalLabel}>{t('common.choices')}</Label>
611-
<Input id="job_prompt_{p.id}_choices" bind:value={p.choices.value} />
612-
<Helper class={classModalHelp}>{t('jobs.form.help.prompt_choices')}</Helper>
613-
</div>
614+
{#if p.kind.value == 'dropdown'}
615+
<div class={classModalInput}>
616+
<Label for="job_prompt_{p.id}_choices" class={classModalLabel}>{t('common.choices')}</Label>
617+
<Input id="job_prompt_{p.id}_choices" bind:value={p.choices.value} />
618+
<Helper class={classModalHelp}>{t('jobs.form.help.prompt_choices')}</Helper>
619+
</div>
620+
{/if}
614621
<div class={classModalInput}>
615622
<Label for="job_prompt_{p.id}_regex" class={classModalLabel}>{t('jobs.form.prompt_regex')}</Label>
616623
<Input id="job_prompt_{p.id}_regex" on:input={(e) => {valideInputInstance(e, p)}}

frontend/src/util/form.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,10 @@ export function submitFormBase(form: any, method: formMethod, url: string, callb
6565
}
6666
}
6767

68+
export function choicesFromArray(a: string[]) {
69+
let c = [];
70+
for (let i of a) {
71+
c.push({'value': i, 'name': i})
72+
}
73+
return c
74+
}

src/oxl_ansible_webui/aw/config/languages/en.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
'common.name': 'Name',
3030
'common.choices': 'Choices',
3131
'common.required': 'Required',
32+
'common.status': 'Status',
33+
'common.error': 'Error',
34+
'common.success': 'Action succeeded',
3235

3336
# auth
3437
'login.user': 'Username',
@@ -52,13 +55,20 @@
5255
# jobs
5356
'jobs.new': 'New Job',
5457
'jobs.edit': 'Edit Job',
58+
'jobs.execute': 'Execute Job',
59+
'jobs.info': 'Job Information',
60+
'jobs.info.execution': 'Execution Information',
61+
'jobs.info.next_run': 'Next Run',
62+
'jobs.info.last_run': 'Last Run',
63+
'jobs.info.duration': 'Duration',
64+
'jobs.info.failed': 'Failed',
5565
## form fields
5666
'jobs.form.name': 'Name',
5767
'jobs.form.repository': 'Repository',
5868
'jobs.form.playbook_file': 'Playbook File',
5969
'jobs.form.inventory_file': 'Inventory File',
6070
'jobs.form.comment': 'Comment',
61-
'jobs.form.schedule': 'Schedule',
71+
'jobs.form.schedule': 'Schedule Cron',
6272
'jobs.form.enabled': 'Schedule Enabled',
6373
'jobs.form.limit': 'Limit',
6474
'jobs.form.tags': 'Tags',
@@ -77,6 +87,7 @@
7787
'jobs.form.prompt_limit_req': 'Require Limit',
7888
'jobs.form.prompt_fields': 'Fields to prompt',
7989
'jobs.form.prompt_vars': 'Variables to prompt',
90+
'jobs.form.prompt_name': 'Display Name',
8091
'jobs.form.prompt_varname': 'Variable Name',
8192
'jobs.form.prompt_kind': 'Kind',
8293
'jobs.form.prompt_regex': 'Validation Regex',

0 commit comments

Comments
 (0)