Split Job into Vue component
This commit is contained in:
parent
7731b37c12
commit
1e954a0afc
130
src/App.vue
130
src/App.vue
@ -1,40 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-for="(job, jid) in jobs" :key="jid">
|
<Job
|
||||||
<h3>
|
v-for="(jobEvents, jid) in jobs"
|
||||||
<span v-if="job.startEvent">
|
:key="jid"
|
||||||
{{ job.startEvent.data.fun }}
|
:jid="jid"
|
||||||
{{ job.startEvent.data.arg }}
|
:showRawEvents="showRawEvents"
|
||||||
</span>
|
:events="jobEvents"
|
||||||
<span class="header-jid"> {{ jid }}</span>
|
></Job>
|
||||||
</h3>
|
|
||||||
<div v-for="(events, minion) in job.minionEvents" :key="minion">
|
|
||||||
<details class="minion">
|
|
||||||
<summary>
|
|
||||||
{{ minion }}
|
|
||||||
<span v-for="(event, index) in events" :key="index">
|
|
||||||
{{ event_symbol(event) }}
|
|
||||||
</span>
|
|
||||||
</summary>
|
|
||||||
<details class="event" v-for="(event, index) in events" :key="index">
|
|
||||||
<summary>{{ event_name(event) }}</summary>
|
|
||||||
<pre v-if="rawEvents">{{ JSON.stringify(event, null, 2) }}</pre>
|
|
||||||
<div v-if="isJobEventType(event, 'prog')">
|
|
||||||
{{ JSON.stringify(event.data.data, null, 2) }}
|
|
||||||
</div>
|
|
||||||
<div v-else-if="isJobEventType(event, 'ret')">
|
|
||||||
{{ event.data.jid }}: {{ event.data.fun }}
|
|
||||||
{{ event.data.fun_args }} => {{ event.data.retcode }}
|
|
||||||
<pre>{{
|
|
||||||
typeof event.data.return === 'string'
|
|
||||||
? event.data.return
|
|
||||||
: JSON.stringify(event.data.return, null, 2)
|
|
||||||
}}</pre>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -44,34 +16,16 @@ import { Vue, Component, Prop, Ref } from 'vue-property-decorator';
|
|||||||
import credentials from './credentials.json';
|
import credentials from './credentials.json';
|
||||||
|
|
||||||
import * as salt from './salt';
|
import * as salt from './salt';
|
||||||
|
import Job from './Job';
|
||||||
|
|
||||||
const BASE_URL = 'https://salt.sawtooth.claremontmakerspace.org:8000/';
|
const BASE_URL = 'https://salt.sawtooth.claremontmakerspace.org:8000/';
|
||||||
|
|
||||||
type MinionJobEvent = salt.JobProgEvent | salt.JobRetEvent;
|
@Component({ components: { Job } })
|
||||||
|
|
||||||
class Job {
|
|
||||||
startEvent?: salt.JobNewEvent;
|
|
||||||
minionEvents: { [key: string]: MinionJobEvent[] } = {};
|
|
||||||
jid: salt.JobID;
|
|
||||||
|
|
||||||
constructor(jid: salt.JobID, startEvent?: salt.JobNewEvent) {
|
|
||||||
this.jid = jid;
|
|
||||||
this.startEvent = startEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
addEvent(event: MinionJobEvent) {
|
|
||||||
if (!(event.data.id in this.minionEvents))
|
|
||||||
Vue.set(this.minionEvents, event.data.id, []);
|
|
||||||
this.minionEvents[event.data.id].push(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component
|
|
||||||
export default class App extends Vue {
|
export default class App extends Vue {
|
||||||
evtSource: EventSource | null = null;
|
evtSource: EventSource | null = null;
|
||||||
events: salt.SaltEvent[] = [];
|
events: salt.SaltEvent[] = [];
|
||||||
jobs: { [key: string]: Job } = {};
|
jobs: { [key: string]: salt.JobEvent[] } = {};
|
||||||
rawEvents: boolean = false;
|
showRawEvents: boolean = false;
|
||||||
|
|
||||||
mounted(): void {
|
mounted(): void {
|
||||||
fetch(BASE_URL + 'login', {
|
fetch(BASE_URL + 'login', {
|
||||||
@ -89,17 +43,9 @@ export default class App extends Vue {
|
|||||||
this.events.push(event);
|
this.events.push(event);
|
||||||
|
|
||||||
if (this.isEventType(event, 'job')) {
|
if (this.isEventType(event, 'job')) {
|
||||||
if (this.isJobEventType(event, 'new')) {
|
if (!(event.data.jid in this.jobs))
|
||||||
this.$set(
|
this.$set(this.jobs, event.data.jid, []);
|
||||||
this.jobs,
|
this.jobs[event.data.jid].push(event);
|
||||||
event.data.jid,
|
|
||||||
new Job(event.data.jid, event)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (!(event.data.jid in this.jobs))
|
|
||||||
this.$set(this.jobs, event.data.jid, new Job(event.data.jid));
|
|
||||||
this.jobs[event.data.jid].addEvent(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -111,53 +57,5 @@ export default class App extends Vue {
|
|||||||
): event is Extract<salt.SaltEvent, { splitTag: ['salt', T, ...any[]] }> {
|
): event is Extract<salt.SaltEvent, { splitTag: ['salt', T, ...any[]] }> {
|
||||||
return event.splitTag[1] === type;
|
return event.splitTag[1] === type;
|
||||||
}
|
}
|
||||||
|
|
||||||
isJobEventType<T extends salt.SaltEvent['splitTag'][3]>(
|
|
||||||
event: salt.SaltEvent,
|
|
||||||
type: T
|
|
||||||
): event is Extract<
|
|
||||||
salt.SaltEvent,
|
|
||||||
{ splitTag: ['salt', 'job', any, T, ...any[]] }
|
|
||||||
> {
|
|
||||||
return event.splitTag[3] === type;
|
|
||||||
}
|
|
||||||
|
|
||||||
event_name(event: salt.JobEvent) {
|
|
||||||
if (this.isJobEventType(event, 'prog')) {
|
|
||||||
return `${this.event_symbol(event)} Progress: ${
|
|
||||||
event.data.data.ret.name
|
|
||||||
}|${event.data.data.ret.duration} `;
|
|
||||||
} else if (this.isJobEventType(event, 'ret')) {
|
|
||||||
return `${this.event_symbol(event)} Return: ${event.data.fun} `;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event_symbol(event: salt.JobEvent) {
|
|
||||||
if (this.isJobEventType(event, 'prog')) {
|
|
||||||
const ret = event.data.data.ret;
|
|
||||||
if (!ret.result) return '✗';
|
|
||||||
else if (Object.keys(ret.changes).length !== 0) return 'Δ';
|
|
||||||
else return '✓';
|
|
||||||
} else if (this.isJobEventType(event, 'ret')) {
|
|
||||||
return event.data.success ? '✓' : '✗';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '?';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
.minion .event {
|
|
||||||
margin-left: 2ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-jid {
|
|
||||||
font-size: x-small;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
119
src/Job.vue
Normal file
119
src/Job.vue
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<template>
|
||||||
|
<div class="job">
|
||||||
|
<h3>
|
||||||
|
<span v-if="startEvent">
|
||||||
|
{{ startEvent.data.fun }}
|
||||||
|
{{ startEvent.data.arg }}
|
||||||
|
</span>
|
||||||
|
<span class="header-jid"> {{ jid }}</span>
|
||||||
|
</h3>
|
||||||
|
<div v-for="(events, minion) in minionEvents" :key="minion">
|
||||||
|
<details class="minion">
|
||||||
|
<summary>
|
||||||
|
{{ minion }}
|
||||||
|
<span v-for="(event, index) in events" :key="index">
|
||||||
|
{{ event_symbol(event) }}
|
||||||
|
</span>
|
||||||
|
</summary>
|
||||||
|
<details class="event" v-for="(event, index) in events" :key="index">
|
||||||
|
<summary>{{ event_name(event) }}</summary>
|
||||||
|
<pre v-if="showRawEvents">{{ JSON.stringify(event, null, 2) }}</pre>
|
||||||
|
<div v-if="isJobEventType(event, 'prog')">
|
||||||
|
{{ JSON.stringify(event.data.data, null, 2) }}
|
||||||
|
</div>
|
||||||
|
<div v-else-if="isJobEventType(event, 'ret')">
|
||||||
|
{{ event.data.jid }}: {{ event.data.fun }}
|
||||||
|
{{ event.data.fun_args }} => {{ event.data.retcode }}
|
||||||
|
<pre>{{
|
||||||
|
typeof event.data.return === 'string'
|
||||||
|
? event.data.return
|
||||||
|
: JSON.stringify(event.data.return, null, 2)
|
||||||
|
}}</pre>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component, Prop, Ref } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import * as salt from './salt';
|
||||||
|
|
||||||
|
type MinionJobEvent = salt.JobProgEvent | salt.JobRetEvent;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class Job extends Vue {
|
||||||
|
@Prop(Number) readonly jid: salt.JobID;
|
||||||
|
@Prop(Boolean) readonly showRawEvents: boolean;
|
||||||
|
@Prop() readonly events: salt.JobEvent[];
|
||||||
|
|
||||||
|
isJobEventType<T extends salt.JobEvent['splitTag'][3]>(
|
||||||
|
event: salt.JobEvent,
|
||||||
|
type: T
|
||||||
|
): event is Extract<
|
||||||
|
salt.JobEvent,
|
||||||
|
{ splitTag: ['salt', 'job', any, T, ...any[]] }
|
||||||
|
> {
|
||||||
|
return event.splitTag[3] === type;
|
||||||
|
}
|
||||||
|
|
||||||
|
get startEvent(): salt.JobNewEvent {
|
||||||
|
return this.events.find((event): event is salt.JobNewEvent =>
|
||||||
|
this.isJobEventType(event, 'new')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get minionEvents(): { [key: string]: MinionJobEvent[] } {
|
||||||
|
return this.events
|
||||||
|
.filter(
|
||||||
|
event =>
|
||||||
|
this.isJobEventType(event, 'prog') ||
|
||||||
|
this.isJobEventType(event, 'ret')
|
||||||
|
)
|
||||||
|
.reduce((acc, event: MinionJobEvent) => {
|
||||||
|
if (!(event.data.id in acc)) acc[event.data.id] = [];
|
||||||
|
acc[event.data.id].push(event);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
event_name(event: salt.JobEvent) {
|
||||||
|
if (this.isJobEventType(event, 'prog')) {
|
||||||
|
return `${this.event_symbol(event)} Progress: ${
|
||||||
|
event.data.data.ret.name
|
||||||
|
}|${event.data.data.ret.duration} `;
|
||||||
|
} else if (this.isJobEventType(event, 'ret')) {
|
||||||
|
return `${this.event_symbol(event)} Return: ${event.data.fun} `;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event_symbol(event: salt.JobEvent) {
|
||||||
|
if (this.isJobEventType(event, 'prog')) {
|
||||||
|
const ret = event.data.data.ret;
|
||||||
|
if (!ret.result) return '✗';
|
||||||
|
else if (Object.keys(ret.changes).length !== 0) return 'Δ';
|
||||||
|
else return '✓';
|
||||||
|
} else if (this.isJobEventType(event, 'ret')) {
|
||||||
|
return event.data.success ? '✓' : '✗';
|
||||||
|
}
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.minion .event {
|
||||||
|
margin-left: 2ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-jid {
|
||||||
|
font-size: x-small;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user