Skip to content

Commit c404551

Browse files
henrychoykeithmanville
authored andcommitted
feat(frontend): redesign common Job creation form
This commit makes the following changes to the Job creation form in the frontend: - Jobs can now be created through the all-jobs page and the experiment -> job page. - Entrypoint dropdown will be greyed out until experiment is selected, and will only show entrypoints that are linked to the selected experiment - Queue dropdown will be greyed out until entrypoint is selected, and will only show queues that are linked to the selected entrypoint - A message with link that opens a dialog box to update experiment/entrypoint associations is added under the Entrypoint dropdown - A message with link that opens a dialog box to update entrypoint/queue associations is added under the Queue dropdown - Returning to an unsaved form should give you the option to load previous values
1 parent d017c4f commit c404551

File tree

5 files changed

+499
-54
lines changed

5 files changed

+499
-54
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<template>
2+
<DialogComponent
3+
v-model="showDialog"
4+
@emitSubmit="submit"
5+
:hideDraftBtn="true"
6+
>
7+
<template #title>
8+
<label id="modalTitle">
9+
Assign {{ childResourceType }} for '{{ parentResourceObj.name }}'
10+
</label>
11+
</template>
12+
<q-select
13+
outlined
14+
dense
15+
v-model="childResourceObjs"
16+
use-input
17+
use-chips
18+
multiple
19+
option-label="name"
20+
option-value="id"
21+
input-debounce="100"
22+
:options="childResourceOptions"
23+
@filter="getChildResources"
24+
>
25+
<template v-slot:before>
26+
<div class="field-label text-capitalize">{{ childResourceType }}:</div>
27+
</template>
28+
<template v-slot:selected>
29+
<div>
30+
<div
31+
v-for="(resource, i) in childResourceObjs"
32+
:key="resource.id"
33+
:class="i > 0 ? 'q-mt-xs' : ''"
34+
>
35+
<q-chip
36+
removable
37+
color="secondary"
38+
text-color="white"
39+
class="q-ml-xs "
40+
@remove="childResourceObjs.splice(i, 1)"
41+
>
42+
{{ resource.name }}
43+
</q-chip>
44+
</div>
45+
</div>
46+
</template>
47+
</q-select>
48+
</DialogComponent>
49+
</template>
50+
51+
<script setup>
52+
import { ref, watch, computed } from 'vue'
53+
import DialogComponent from './DialogComponent.vue'
54+
import * as api from '@/services/dataApi'
55+
import * as notify from '../notify'
56+
57+
58+
const props = defineProps(['parentResourceType', 'parentResourceObj', 'childResourceType' ])
59+
const emit = defineEmits(['submit'])
60+
61+
const showDialog = defineModel()
62+
63+
const childResourceObjs = ref([])
64+
const selectedChildIds = computed(() => {
65+
return childResourceObjs.value.map((obj) => obj.id)
66+
})
67+
68+
const childResourceOptions = ref([])
69+
const originalChildIds = ref()
70+
71+
watch(showDialog, (newVal) => {
72+
if(newVal) {
73+
console.log('props = ', props.parentResourceObj)
74+
childResourceObjs.value = JSON.parse(JSON.stringify(props.parentResourceObj[props.childResourceType]))
75+
originalChildIds.value = JSON.parse(JSON.stringify(props.parentResourceObj[props.childResourceType].map((obj) => obj.id)))
76+
}
77+
})
78+
79+
async function submit() {
80+
let childIdsToAdd = []
81+
let childIdsToRemove = []
82+
83+
selectedChildIds.value.forEach((id) => {
84+
if (!originalChildIds.value.includes(id)) {
85+
childIdsToAdd.push(id)
86+
}
87+
})
88+
89+
originalChildIds.value.forEach((id) => {
90+
if (!selectedChildIds.value.includes(id)) {
91+
childIdsToRemove.push(id)
92+
}
93+
})
94+
95+
try {
96+
if(childIdsToAdd.length > 0) {
97+
await api.appendResource(props.parentResourceType, props.parentResourceObj.id, props.childResourceType, childIdsToAdd)
98+
}
99+
for(const id of childIdsToRemove) {
100+
await api.removeResourceFromResource(props.parentResourceType, props.parentResourceObj.id, props.childResourceType, id)
101+
}
102+
notify.success(`Successfully updated ${props.childResourceType} for '${props.parentResourceObj.name}'`)
103+
showDialog.value = false
104+
emit('submit')
105+
} catch (err) {
106+
notify.error(err.message)
107+
}
108+
}
109+
110+
async function getChildResources(val = '', update) {
111+
update(async () => {
112+
try {
113+
const res = await api.getData(props.childResourceType, {
114+
search: val,
115+
rowsPerPage: 0, // get all
116+
index: 0
117+
})
118+
childResourceOptions.value = res.data.data.filter((ep) => !selectedChildIds.value.includes(ep.id))
119+
} catch(err) {
120+
notify.error(err.response.data.message)
121+
}
122+
})
123+
}
124+
125+
</script>

src/frontend/src/router/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ const router = createRouter({
4848
path: '/experiments/:id/jobs/:jobId',
4949
component: () => import('../views/CreateJob.vue')
5050
},
51+
{
52+
path: '/jobs/new',
53+
component: () => import('../views/CreateJob.vue')
54+
},
5155
{
5256
path: '/experiments/:id',
5357
component: () => import('../views/CreateExperiment.vue')

src/frontend/src/services/dataApi.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,14 @@ export async function removePluginFromEntrypoint(entrypointId: string, pluginId:
315315
return await axios.delete(`/api/entrypoints/${entrypointId}/plugins/${pluginId}`)
316316
}
317317

318+
export async function appendResource<T extends ItemType>(parentResourceType: T, parentResourceId: number, childResourceType: T, ids: number[]) {
319+
return await axios.post(`/api/${parentResourceType}/${parentResourceId}/${childResourceType}`, {ids})
320+
}
321+
322+
export async function removeResourceFromResource<T extends ItemType>(parentResourceType: T, parentResourceId: number, childResourceType: T, id: number) {
323+
return await axios.delete(`/api/${parentResourceType}/${parentResourceId}/${childResourceType}/${id}`)
324+
}
325+
318326
export async function getVersions(id: string,) {
319327
return await axios.get(`/api/models/${id}/versions`)
320328
}

src/frontend/src/views/AllJobsView.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
ref="tableRef"
1212
:hideEditBtn="true"
1313
@editTags="(row) => { editObjTags = row; showTagsDialog = true }"
14-
:hideCreateBtn="true"
14+
@create="router.push('/jobs/new')"
1515
>
16+
<template #body-cell-experiment="props">
17+
{{ props.row.experiment.name }}
18+
</template>
1619
<template #body-cell-entrypoint="props">
1720
{{ props.row.entrypoint.name }}
1821
</template>
@@ -61,6 +64,7 @@
6164
const columns = [
6265
{ name: 'description', label: 'Description', align: 'left', field: 'description', sortable: true, },
6366
{ name: 'id', label: 'Job ID', align: 'left', field: 'id', sortable: false, },
67+
{ name: 'experiment', label: 'Experiment', align: 'left', field: 'experiment', sortable: false, },
6468
{ name: 'entrypoint', label: 'Entrypoint', align: 'left', field: 'entrypoint', sortable: false, },
6569
{ name: 'queue', label: 'Queue', align: 'left', field: 'queue', sortable: false, },
6670
{ name: 'status', label: 'Status', align: 'left', field: 'status', sortable: true },

0 commit comments

Comments
 (0)