Skip to content

Commit f0ec177

Browse files
authored
Merge pull request #4582 from cloud-gov/feat-admin-site-build-task-config-ui
feat(admin): Add runDay input to manage build tasks
2 parents e5fa2cb + 405082c commit f0ec177

File tree

17 files changed

+225
-28
lines changed

17 files changed

+225
-28
lines changed

admin-client/src/components/Nav.svelte

+5
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@
9696
<span>Builds</span>
9797
</a>
9898
</li>
99+
<li class="usa-nav__primary-item">
100+
<a class="usa-nav__link" class:usa-current={currentPath === '/tasks'} href="/tasks">
101+
<span>Tasks</span>
102+
</a>
103+
</li>
99104
<li class="usa-nav__primary-item">
100105
<a class="usa-nav__link" class:usa-current={currentPath === '/users'} href="/users">
101106
<span>Users</span>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<script>
2+
export let error;
3+
export let hint;
4+
export let id;
5+
export let label;
6+
export let name;
7+
export let required = false;
8+
export let value;
9+
export let min;
10+
export let max;
11+
12+
$: idValue = id ?? name;
13+
$: errorMessageId = `${idValue}-error-message`;
14+
</script>
15+
16+
<label class="usa-label" for={idValue}>
17+
{label}{#if required}<abbr title="required" class="usa-hint usa-hint--required">*</abbr>{/if}
18+
</label>
19+
{#if hint}
20+
<span class="usa-hint">{hint}</span>
21+
{/if}
22+
{#if error}
23+
<span id={errorMessageId} class="usa-error-message">{error}</span>
24+
{/if}
25+
<input
26+
class="usa-select"
27+
name={name}
28+
id={idValue}
29+
type="number"
30+
min={min}
31+
max={max}
32+
{required}
33+
bind:value={value}
34+
/>

admin-client/src/components/SiteFormBuildTaskType.svelte

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<script>
22
import Form from './Form.svelte';
3+
import NumberInput from './NumberInput.svelte';
34
import SelectInput from './SelectInput.svelte';
45
5-
export let buildTaskTypes;
6+
export let buildTaskTypes = [];
67
export let site;
78
export let onSubmit;
89
export let onSuccess;
@@ -21,13 +22,14 @@
2122
2223
$: value = undefined;
2324
$: branch = undefined;
25+
$: runDay = undefined;
2426
</script>
2527

2628
<div class="grid-row">
2729
<div class="grid-col-8 grid-offset-4">
2830
<Form
2931
action="Add"
30-
onSubmit={() => onSubmit(value, branch)}
32+
onSubmit={() => onSubmit(value, branch, runDay)}
3133
{onSuccess}
3234
{onFailure}
3335
let:errors
@@ -39,6 +41,7 @@
3941
name="build-task-types"
4042
label='Build Task Types'
4143
options={options}
44+
required
4245
bind:value={value}
4346
/>
4447
<SelectInput
@@ -48,7 +51,14 @@
4851
options={branches}
4952
bind:value={branch}
5053
/>
51-
54+
<NumberInput
55+
error={errors.isActive}
56+
name="runDay"
57+
label='Runs On'
58+
min={1}
59+
max={27}
60+
bind:value={runDay}
61+
/>
5262
</fieldset>
5363
</Form>
5464
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<script>
2+
import Form from './Form.svelte';
3+
import Modal from './Modal.svelte';
4+
import NumberInput from './NumberInput.svelte';
5+
6+
export let branch;
7+
export let buildTaskName;
8+
export let id;
9+
export let initialRunDay;
10+
export let runDay;
11+
export let closeModal;
12+
export let onSubmit;
13+
export let onSuccess;
14+
export let onFailure;
15+
</script>
16+
17+
18+
{#if buildTaskName && id}
19+
<Modal>
20+
<div class="display-flex flex-column flex-align-end">
21+
<button
22+
class="usa-button usa-button--base"
23+
on:click|preventDefault={() => closeModal()}
24+
>
25+
Close
26+
</button>
27+
</div>
28+
<Form
29+
action="Edit"
30+
disabled={initialRunDay === runDay}
31+
onSubmit={() => onSubmit(id, runDay)}
32+
{onSuccess}
33+
{onFailure}
34+
let:errors
35+
>
36+
<fieldset class="usa-fieldset">
37+
<p class="font-sans-lg">
38+
Edit the <span class="text-bold">{buildTaskName}</span>
39+
running on the
40+
<span class="font-code-lg bg-base-lightest padding-x-1">{branch}</span> branch.
41+
</p>
42+
<NumberInput
43+
error={errors.isActive}
44+
name="run-day"
45+
label="Select day of the month to run report. (Choose a number
46+
from 1 to 27)"
47+
min={1}
48+
max={27}
49+
bind:value={runDay}
50+
/>
51+
</fieldset>
52+
</Form>
53+
</Modal>
54+
{/if}

admin-client/src/components/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export { default as LabeledItem } from './LabeledItem.svelte';
1616
export { default as Modal } from './Modal.svelte';
1717
export { default as Nav } from './Nav.svelte';
1818
export { default as NavButton } from './NavButton.svelte';
19+
export { default as NumberInput } from './NumberInput.svelte';
1920
export { default as PageTitle } from './PageTitle.svelte';
2021
export { default as PaginatedQueryPage } from './PaginatedQueryPage.svelte';
2122
export { default as PaginationBanner } from './PaginationBanner.svelte';

admin-client/src/lib/api.js

+5
Original file line numberDiff line numberDiff line change
@@ -318,12 +318,17 @@ async function addSiteBuildTask(id, params) {
318318
return post(`/sites/${id}/tasks`, params);
319319
}
320320

321+
async function updateSiteBuildTask(id, params) {
322+
return put(`/site-build-tasks/${id}`, params);
323+
}
324+
321325
async function removeBuildTask(id) {
322326
return destroy(`/site-build-tasks/${id}`);
323327
}
324328

325329
export {
326330
addSiteBuildTask,
331+
updateSiteBuildTask,
327332
removeBuildTask,
328333
destroySite,
329334
fetchMe,

admin-client/src/pages/Site.svelte

+72-9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
fetchUsers,
1313
updateSite,
1414
addSiteBuildTask,
15+
updateSiteBuildTask,
1516
removeBuildTask,
1617
} from '../lib/api';
1718
import {
@@ -33,6 +34,7 @@
3334
import { destroySite } from '../flows';
3435
import { selectSiteDomains, stateColor } from '../lib/utils';
3536
import SiteFormBuildTaskType from '../components/SiteFormBuildTaskType.svelte';
37+
import SiteFormUpdateBuildTaskType from '../components/SiteFormUpdateBuildTaskType.svelte';
3638
3739
const { id } = $router.params;
3840
$: sitePromise = fetchSite(id);
@@ -44,6 +46,14 @@
4446
$: usersPromise = fetchUsers({ site: id });
4547
$: uevsPromise = fetchUserEnvironmentVariables({ site: id });
4648
49+
const initEditedBuildTask = {
50+
isEditing: false,
51+
initialRunDay: null,
52+
data: null,
53+
};
54+
55+
let editedBuildTask = initEditedBuildTask;
56+
4757
async function handleOrganizationSubmit(organizationId) {
4858
return updateSite(id, { organizationId });
4959
}
@@ -78,8 +88,12 @@
7888
notification.setError(`Site webhook create error: ${error.message}`);
7989
}
8090
81-
async function handleSiteBuildTaskSubmit(buildTaskTypeId, branch) {
82-
return addSiteBuildTask(id, { buildTaskTypeId, branch });
91+
async function handleSiteBuildTaskSubmit(
92+
buildTaskTypeId,
93+
branch,
94+
runDay = null,
95+
) {
96+
return addSiteBuildTask(id, { buildTaskTypeId, branch, runDay });
8397
}
8498
8599
async function handleSiteBuildTaskSuccess() {
@@ -91,6 +105,28 @@
91105
notification.setError('Build task update error');
92106
}
93107
108+
async function handleCloseEditSiteBuildTask() {
109+
editedBuildTask = initEditedBuildTask;
110+
}
111+
112+
async function handleOpenEditSiteBuildTask(data) {
113+
editedBuildTask = {
114+
isEditing: true,
115+
initialRunDay: data?.metadata?.runDay,
116+
data,
117+
};
118+
}
119+
120+
async function handleEditSiteBuildTaskSubmit(sbtId, runDay = null) {
121+
return updateSiteBuildTask(sbtId, { runDay });
122+
}
123+
124+
async function handleEditSiteBuildTaskSuccess() {
125+
sitePromise = fetchSite(id);
126+
notification.setSuccess('Build task edited successfully');
127+
editedBuildTask = initEditedBuildTask;
128+
}
129+
94130
async function handleRemoveBuildTask(sbt) {
95131
await removeBuildTask(sbt.id);
96132
sitePromise = fetchSite(id);
@@ -166,10 +202,7 @@
166202
</Await>
167203
</AccordionContent>
168204
<AccordionContent title="Domains">
169-
<DataTable
170-
data={selectSiteDomains(site)}
171-
borderless={true}
172-
>
205+
<DataTable data={selectSiteDomains(site)} borderless={true}>
173206
<tr slot="header">
174207
<th>Domain Names</th>
175208
<th>Context</th>
@@ -236,23 +269,38 @@
236269
<th>Build Task Type</th>
237270
<th>Type Id</th>
238271
<th>Branch</th>
239-
<th>Metadata</th>
272+
<th>Run Day</th>
273+
<th>Rules</th>
240274
<th>Created At</th>
275+
<th>Edit</th>
241276
<th>Remove</th>
242277
</tr>
243278
<tr slot="item" let:item={sbt}>
244279
<td>{sbt.id}</td>
245280
<td>{sbt.BuildTaskType.name}</td>
246281
<td>{sbt.buildTaskTypeId}</td>
247282
<td>{sbt.branch}</td>
248-
<td>{JSON.stringify(sbt.metadata)}</td>
283+
<td>
284+
{sbt.metadata?.runDay}
285+
</td>
286+
<td>{JSON.stringify(sbt.metadata?.rules)}</td>
249287
<td>{sbt.createdAt}</td>
288+
<td>
289+
<input
290+
class="usa-button"
291+
type="button"
292+
value="Edit"
293+
on:click|preventDefault={() => handleOpenEditSiteBuildTask(sbt)}
294+
/>
295+
</td>
250296
<td>
251297
<input
252298
class="usa-button usa-button--base"
253299
type="reset"
254300
value="Remove"
255-
on:click|preventDefault={() => handleRemoveBuildTask(sbt)} /></td>
301+
on:click|preventDefault={() => handleRemoveBuildTask(sbt)}
302+
/>
303+
</td>
256304
</tr>
257305
<p slot="empty">No build tasks registered</p>
258306
</DataTable>
@@ -271,3 +319,18 @@
271319
</Accordion>
272320
</Await>
273321
</GridContainer>
322+
323+
{#if editedBuildTask.isEditing}
324+
<SiteFormUpdateBuildTaskType
325+
isEditing={editedBuildTask.site}
326+
branch={editedBuildTask.data?.branch}
327+
buildTaskName={editedBuildTask?.data?.BuildTaskType?.name}
328+
id={editedBuildTask?.data?.id}
329+
initialRunDay={editedBuildTask.initialRunDay}
330+
runDay={editedBuildTask.data?.metadata?.runDay}
331+
closeModal={handleCloseEditSiteBuildTask}
332+
onSubmit={handleEditSiteBuildTaskSubmit}
333+
onSuccess={handleEditSiteBuildTaskSuccess}
334+
onFailure={handleSiteBuildTaskFailure}
335+
/>
336+
{/if}

api/admin/controllers/task.js

+16-2
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,30 @@ module.exports = wrapHandlers({
5757
},
5858

5959
async addSiteBuildTask(req, res) {
60+
const { branch, runDay } = req.body;
61+
const metadata = runDay ? { runDay } : {};
62+
6063
await SiteBuildTask.create({
6164
buildTaskTypeId: req.body.buildTaskTypeId,
6265
siteId: req.params.id,
63-
branch: req.body.branch,
64-
metadata: {},
66+
branch,
67+
metadata,
6568
});
6669

6770
return res.json({});
6871
},
6972

73+
async updateSiteBuildTask(req, res) {
74+
const { id } = req.params;
75+
const { runDay } = req.body;
76+
77+
const sbt = await SiteBuildTask.findByPk(id);
78+
79+
await sbt.update({ metadata: { ...sbt.metadata, runDay } });
80+
81+
return res.json({});
82+
},
83+
7084
async removeSiteBuiltTask(req, res) {
7185
const { id } = req.params;
7286

api/admin/routers/api.js

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ apiRouter.post('/sites/:id/tasks', AdminControllers.Task.addSiteBuildTask);
5656
apiRouter.get('/tasks', AdminControllers.Task.list);
5757
apiRouter.get('/tasks/types', AdminControllers.Task.listTypes);
5858
apiRouter.delete('/site-build-tasks/:id', authorize(['pages.admin']), AdminControllers.Task.removeSiteBuiltTask);
59+
apiRouter.put('/site-build-tasks/:id', AdminControllers.Task.updateSiteBuildTask);
5960
apiRouter.get('/me', AdminControllers.User.me);
6061
apiRouter.get('/user-environment-variables', AdminControllers.UserEnvironmentVariable.list);
6162
apiRouter.get('/users', AdminControllers.User.list);

api/controllers/site.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ module.exports = wrapHandlers({
4141
const { user } = req;
4242

4343
const sites = await Site.forUser(user).findAll({
44-
include: [Domain, SiteBranchConfig],
44+
include: [Domain, SiteBranchConfig, SiteBuildTask],
4545
});
4646

4747
if (!sites) {
@@ -304,7 +304,7 @@ module.exports = wrapHandlers({
304304
body,
305305
} = req;
306306

307-
const { metadata } = body;
307+
const { metadata: { rules } } = body;
308308

309309
// check Site for authorizer's sake
310310
const site = await Site.findByPk(siteId);
@@ -321,7 +321,9 @@ module.exports = wrapHandlers({
321321
return res.notFound();
322322
}
323323

324-
await siteBuildTask.update({ metadata });
324+
const { metadata } = siteBuildTask.dataValues;
325+
326+
await siteBuildTask.update({ metadata: { ...metadata, rules } });
325327

326328
return res.ok({});
327329
},

0 commit comments

Comments
 (0)