@jbrowse/plugin-jobs-management 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +201 -0
  2. package/dist/JobsListWidget/components/CurrentJobCard.d.ts +7 -0
  3. package/dist/JobsListWidget/components/CurrentJobCard.js +58 -0
  4. package/dist/JobsListWidget/components/CurrentJobCard.js.map +1 -0
  5. package/dist/JobsListWidget/components/JobCard.d.ts +7 -0
  6. package/dist/JobsListWidget/components/JobCard.js +17 -0
  7. package/dist/JobsListWidget/components/JobCard.js.map +1 -0
  8. package/dist/JobsListWidget/components/JobsListWidget.d.ts +7 -0
  9. package/dist/JobsListWidget/components/JobsListWidget.js +58 -0
  10. package/dist/JobsListWidget/components/JobsListWidget.js.map +1 -0
  11. package/dist/JobsListWidget/index.d.ts +3 -0
  12. package/dist/JobsListWidget/index.js +13 -0
  13. package/dist/JobsListWidget/index.js.map +1 -0
  14. package/dist/JobsListWidget/model.d.ts +163 -0
  15. package/dist/JobsListWidget/model.js +80 -0
  16. package/dist/JobsListWidget/model.js.map +1 -0
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.js +74 -0
  19. package/dist/index.js.map +1 -0
  20. package/esm/JobsListWidget/components/CurrentJobCard.d.ts +7 -0
  21. package/esm/JobsListWidget/components/CurrentJobCard.js +33 -0
  22. package/esm/JobsListWidget/components/CurrentJobCard.js.map +1 -0
  23. package/esm/JobsListWidget/components/JobCard.d.ts +7 -0
  24. package/esm/JobsListWidget/components/JobCard.js +12 -0
  25. package/esm/JobsListWidget/components/JobCard.js.map +1 -0
  26. package/esm/JobsListWidget/components/JobsListWidget.d.ts +7 -0
  27. package/esm/JobsListWidget/components/JobsListWidget.js +53 -0
  28. package/esm/JobsListWidget/components/JobsListWidget.js.map +1 -0
  29. package/esm/JobsListWidget/index.d.ts +3 -0
  30. package/esm/JobsListWidget/index.js +5 -0
  31. package/esm/JobsListWidget/index.js.map +1 -0
  32. package/esm/JobsListWidget/model.d.ts +163 -0
  33. package/esm/JobsListWidget/model.js +76 -0
  34. package/esm/JobsListWidget/model.js.map +1 -0
  35. package/esm/index.d.ts +7 -0
  36. package/esm/index.js +45 -0
  37. package/esm/index.js.map +1 -0
  38. package/package.json +59 -0
  39. package/src/JobsListWidget/components/CurrentJobCard.tsx +73 -0
  40. package/src/JobsListWidget/components/JobCard.tsx +19 -0
  41. package/src/JobsListWidget/components/JobsListWidget.tsx +103 -0
  42. package/src/JobsListWidget/index.ts +5 -0
  43. package/src/JobsListWidget/model.ts +85 -0
  44. package/src/index.test.ts +3 -0
  45. package/src/index.ts +51 -0
@@ -0,0 +1,73 @@
1
+ import React, { useState } from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import {
4
+ Box,
5
+ Button,
6
+ Card,
7
+ CardActions,
8
+ CardContent,
9
+ LinearProgress,
10
+ Typography,
11
+ } from '@mui/material'
12
+ import { NewJob } from '../model'
13
+
14
+ function CurrentJobCard({ job }: { job: NewJob }) {
15
+ const [clicked, setClicked] = useState(false)
16
+ return (
17
+ <Card variant="outlined">
18
+ <CardContent>
19
+ <Typography variant="body1">
20
+ <strong>{'Name: '}</strong>
21
+ {job.name}
22
+ </Typography>
23
+ <Typography variant="body1">
24
+ <strong>{'Message: '}</strong>
25
+ {job.statusMessage || 'No message provided'}
26
+ </Typography>
27
+ <Box
28
+ sx={{
29
+ display: 'flex',
30
+ alignItems: 'center',
31
+ marginTop: 10,
32
+ marginBottom: 10,
33
+ marginLeft: 10,
34
+ }}
35
+ >
36
+ {job.progressPct === 0 || job.progressPct === 100 ? (
37
+ <Box sx={{ width: '100%' }}>
38
+ <LinearProgress variant="indeterminate" />
39
+ </Box>
40
+ ) : (
41
+ <>
42
+ <Box sx={{ width: '100%' }}>
43
+ <LinearProgress variant="determinate" value={job.progressPct} />
44
+ </Box>
45
+ <Box sx={{ m: 1 }}>
46
+ <Typography>{`${Math.round(
47
+ job.progressPct || 0,
48
+ )}%`}</Typography>
49
+ </Box>
50
+ </>
51
+ )}
52
+ </Box>
53
+ </CardContent>
54
+ {job.cancelCallback ? (
55
+ <CardActions>
56
+ <Button
57
+ variant="contained"
58
+ color="inherit"
59
+ disabled={clicked || job.progressPct === 0}
60
+ onClick={() => {
61
+ job.cancelCallback && job.cancelCallback()
62
+ setClicked(true)
63
+ }}
64
+ >
65
+ Cancel
66
+ </Button>
67
+ </CardActions>
68
+ ) : null}
69
+ </Card>
70
+ )
71
+ }
72
+
73
+ export default observer(CurrentJobCard)
@@ -0,0 +1,19 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { Card, CardContent, Typography } from '@mui/material'
4
+ import { NewJob } from '../model'
5
+
6
+ function JobCard({ job }: { job: NewJob }) {
7
+ return (
8
+ <Card variant="outlined">
9
+ <CardContent>
10
+ <Typography variant="body1">
11
+ <strong>{'Name: '}</strong>
12
+ {job.name}
13
+ </Typography>
14
+ </CardContent>
15
+ </Card>
16
+ )
17
+ }
18
+
19
+ export default observer(JobCard)
@@ -0,0 +1,103 @@
1
+ import React from 'react'
2
+ import {
3
+ Accordion,
4
+ AccordionSummary,
5
+ Card,
6
+ CardContent,
7
+ Typography,
8
+ } from '@mui/material'
9
+ import { makeStyles } from 'tss-react/mui'
10
+ import { observer } from 'mobx-react'
11
+
12
+ // icons
13
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
14
+
15
+ import JobCard from './JobCard'
16
+ import CurrentJobCard from './CurrentJobCard'
17
+ import { JobsListModel, NewJob } from '../model'
18
+
19
+ const useStyles = makeStyles()(theme => ({
20
+ root: {
21
+ margin: theme.spacing(1),
22
+ },
23
+ expandIcon: {
24
+ color: theme.palette.tertiary.contrastText,
25
+ },
26
+ button: {
27
+ marginTop: theme.spacing(1),
28
+ marginRight: theme.spacing(1),
29
+ },
30
+ adminBadge: {
31
+ margin: '0.5em',
32
+ borderRadius: 3,
33
+ backgroundColor: theme.palette.quaternary.main,
34
+ padding: '1em',
35
+ display: 'flex',
36
+ alignContent: 'center',
37
+ },
38
+ }))
39
+
40
+ function JobsListWidget({ model }: { model: JobsListModel }) {
41
+ const { classes } = useStyles()
42
+ const { jobs, finished, queued } = model
43
+ return (
44
+ <div className={classes.root}>
45
+ <Accordion defaultExpanded>
46
+ <AccordionSummary
47
+ expandIcon={<ExpandMoreIcon className={classes.expandIcon} />}
48
+ >
49
+ <Typography variant="h5">Jobs</Typography>
50
+ </AccordionSummary>
51
+ {jobs.length ? (
52
+ jobs.map((job: NewJob, index: number) => (
53
+ <CurrentJobCard job={job} key={`${JSON.stringify(job)}-${index}`} />
54
+ ))
55
+ ) : (
56
+ <Card variant="outlined">
57
+ <CardContent>
58
+ <Typography variant="body1">No jobs</Typography>
59
+ </CardContent>
60
+ </Card>
61
+ )}
62
+ </Accordion>
63
+ <Accordion defaultExpanded>
64
+ <AccordionSummary
65
+ expandIcon={<ExpandMoreIcon className={classes.expandIcon} />}
66
+ >
67
+ <Typography variant="h5">Queued jobs</Typography>
68
+ </AccordionSummary>
69
+ {queued.length ? (
70
+ queued.map((job: NewJob, index: number) => (
71
+ <JobCard job={job} key={`${JSON.stringify(job)}-${index}`} />
72
+ ))
73
+ ) : (
74
+ <Card variant="outlined">
75
+ <CardContent>
76
+ <Typography variant="body1">No queued jobs</Typography>
77
+ </CardContent>
78
+ </Card>
79
+ )}
80
+ </Accordion>
81
+ <Accordion defaultExpanded>
82
+ <AccordionSummary
83
+ expandIcon={<ExpandMoreIcon className={classes.expandIcon} />}
84
+ >
85
+ <Typography variant="h5">Jobs completed</Typography>
86
+ </AccordionSummary>
87
+ {finished.length ? (
88
+ finished.map((job: NewJob, index: number) => (
89
+ <JobCard key={`${JSON.stringify(job)}-${index}`} job={job} />
90
+ ))
91
+ ) : (
92
+ <Card variant="outlined">
93
+ <CardContent>
94
+ <Typography variant="body1">No jobs completed</Typography>
95
+ </CardContent>
96
+ </Card>
97
+ )}
98
+ </Accordion>
99
+ </div>
100
+ )
101
+ }
102
+
103
+ export default observer(JobsListWidget)
@@ -0,0 +1,5 @@
1
+ import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
+
3
+ export { default as ReactComponent } from './components/JobsListWidget'
4
+ export { default as stateModelFactory } from './model'
5
+ export const configSchema = ConfigurationSchema('JobsListWidget', {})
@@ -0,0 +1,85 @@
1
+ import { types, Instance, SnapshotIn } from 'mobx-state-tree'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+ import { ElementId } from '@jbrowse/core/util/types/mst'
4
+
5
+ export const Job = types
6
+ .model('Job', {
7
+ name: types.string,
8
+ statusMessage: types.maybe(types.string),
9
+ progressPct: types.number,
10
+ })
11
+ .volatile(self => ({
12
+ cancelCallback() {},
13
+ }))
14
+ .actions(self => ({
15
+ setCancelCallback(cancelCallback: () => void) {
16
+ self.cancelCallback = cancelCallback
17
+ },
18
+ setStatusMessage(message?: string) {
19
+ self.statusMessage = message
20
+ },
21
+ setProgressPct(pct: number) {
22
+ self.progressPct = pct
23
+ },
24
+ }))
25
+
26
+ export interface NewJob extends SnapshotIn<typeof Job> {
27
+ cancelCallback(): void
28
+ }
29
+
30
+ export default function f(pluginManager: PluginManager) {
31
+ return types
32
+ .model('JobsListModel', {
33
+ id: ElementId,
34
+ type: types.literal('JobsListWidget'),
35
+ jobs: types.array(Job),
36
+ finished: types.array(Job),
37
+ queued: types.array(Job),
38
+ })
39
+ .actions(self => ({
40
+ addJob(job: NewJob) {
41
+ const { cancelCallback } = job
42
+ const length = self.jobs.push(job)
43
+ const addedJob = self.jobs[length - 1]
44
+ addedJob.setCancelCallback(cancelCallback)
45
+ return addedJob
46
+ },
47
+ removeJob(jobName: string) {
48
+ const indx = self.jobs.findIndex(job => job.name === jobName)
49
+ const removed = self.jobs[indx]
50
+ self.jobs.splice(indx, 1)
51
+ return removed
52
+ },
53
+ addFinishedJob(job: NewJob) {
54
+ self.finished.push(job)
55
+ return self.finished
56
+ },
57
+ addQueuedJob(job: NewJob) {
58
+ self.queued.push(job)
59
+ return self.finished
60
+ },
61
+ removeQueuedJob(jobName: string) {
62
+ const indx = self.queued.findIndex(job => job.name === jobName)
63
+ const removed = self.queued[indx]
64
+ self.queued.splice(indx, 1)
65
+ return removed
66
+ },
67
+ updateJobStatusMessage(jobName: string, message?: string) {
68
+ const job = self.jobs.find(job => job.name === jobName)
69
+ if (!job) {
70
+ throw new Error(`No job found with name ${jobName}`)
71
+ }
72
+ job.setStatusMessage(message)
73
+ },
74
+ updateJobProgressPct(jobName: string, pct: number) {
75
+ const job = self.jobs.find(job => job.name === jobName)
76
+ if (!job) {
77
+ throw new Error(`No job found with name ${jobName}`)
78
+ }
79
+ job.setProgressPct(pct)
80
+ },
81
+ }))
82
+ }
83
+
84
+ export type JobsListStateModel = ReturnType<typeof f>
85
+ export type JobsListModel = Instance<JobsListStateModel>
@@ -0,0 +1,3 @@
1
+ test('easy', () => {
2
+ expect(1).toBe(1)
3
+ })
package/src/index.ts ADDED
@@ -0,0 +1,51 @@
1
+ import { lazy } from 'react'
2
+ import Plugin from '@jbrowse/core/Plugin'
3
+ import PluginManager from '@jbrowse/core/PluginManager'
4
+ import { SessionWithWidgets, isAbstractMenuManager } from '@jbrowse/core/util'
5
+ import { Indexing } from '@jbrowse/core/ui/Icons'
6
+ import WidgetType from '@jbrowse/core/pluggableElementTypes/WidgetType'
7
+ import {
8
+ stateModelFactory as JobsListStateModelFactory,
9
+ configSchema as JobsListConfigSchema,
10
+ } from '../../jobs-management/src/JobsListWidget'
11
+ import { isSessionModelWithWidgets } from '@jbrowse/core/util'
12
+
13
+ export default class extends Plugin {
14
+ name = 'JobsManagementPlugin'
15
+
16
+ install(pluginManager: PluginManager) {
17
+ pluginManager.addWidgetType(() => {
18
+ return new WidgetType({
19
+ name: 'JobsListWidget',
20
+ heading: 'Running jobs',
21
+ configSchema: JobsListConfigSchema,
22
+ stateModel: JobsListStateModelFactory(pluginManager),
23
+ ReactComponent: lazy(
24
+ () =>
25
+ import(
26
+ '../../jobs-management/src/JobsListWidget/components/JobsListWidget'
27
+ ),
28
+ ),
29
+ })
30
+ })
31
+ }
32
+ configure(pluginManager: PluginManager) {
33
+ if (isAbstractMenuManager(pluginManager.rootModel)) {
34
+ pluginManager.rootModel.appendToMenu('Tools', {
35
+ label: 'Jobs list',
36
+ icon: Indexing, // TODO: pick a better icon
37
+ onClick: (session: SessionWithWidgets) => {
38
+ if (isSessionModelWithWidgets(session)) {
39
+ const { widgets } = session
40
+ let jobStatusWidget = widgets.get('JobsList')
41
+ if (!jobStatusWidget) {
42
+ jobStatusWidget = session.addWidget('JobsListWidget', 'JobsList')
43
+ } else {
44
+ session.showWidget(jobStatusWidget)
45
+ }
46
+ }
47
+ },
48
+ })
49
+ }
50
+ }
51
+ }