@jbrowse/plugin-jobs-management 4.3.0 → 5.0.0-beta.10
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.
- package/esm/JobsListWidget/components/CurrentJobCard.d.ts +3 -3
- package/esm/JobsListWidget/components/CurrentJobCard.js +11 -9
- package/esm/JobsListWidget/components/JobCard.d.ts +3 -3
- package/esm/JobsListWidget/components/JobsListWidget.d.ts +1 -1
- package/esm/JobsListWidget/components/JobsListWidget.js +9 -9
- package/esm/JobsListWidget/components/JobsSection.d.ts +10 -0
- package/esm/JobsListWidget/components/JobsSection.js +21 -0
- package/esm/JobsListWidget/index.d.ts +1 -1
- package/esm/JobsListWidget/index.js +3 -3
- package/esm/JobsListWidget/jobModel.d.ts +27 -8
- package/esm/JobsListWidget/jobModel.js +38 -11
- package/esm/JobsListWidget/model.d.ts +52 -172
- package/esm/JobsListWidget/model.js +50 -66
- package/esm/getOrCreateJobsListWidget.d.ts +8 -0
- package/esm/getOrCreateJobsListWidget.js +10 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +12 -11
- package/package.json +10 -13
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { JobModel } from '../jobModel.ts';
|
|
2
2
|
declare const CurrentJobCard: ({ job, }: {
|
|
3
|
-
job:
|
|
4
|
-
}) => import("react
|
|
3
|
+
job: JobModel;
|
|
4
|
+
}) => import("react").JSX.Element;
|
|
5
5
|
export default CurrentJobCard;
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { StatusProgressBar } from '@jbrowse/core/ui';
|
|
4
|
+
import { Box, Button, Card, CardActions, CardContent, Typography, } from '@mui/material';
|
|
4
5
|
import { observer } from 'mobx-react';
|
|
5
6
|
const CurrentJobCard = observer(function CurrentJobCard({ job, }) {
|
|
6
7
|
const [clicked, setClicked] = useState(false);
|
|
7
|
-
|
|
8
|
+
const { progressPct } = job;
|
|
9
|
+
return (_jsxs(Card, { variant: "outlined", children: [_jsxs(CardContent, { children: [_jsxs(Typography, { variant: "body1", children: [_jsx("strong", { children: 'Name: ' }), job.name] }), _jsxs(Typography, { variant: "body1", children: [_jsx("strong", { children: 'Message: ' }), job.statusMessage || 'No message provided'] }), _jsxs(Box, { sx: {
|
|
8
10
|
display: 'flex',
|
|
9
11
|
alignItems: 'center',
|
|
10
|
-
marginTop:
|
|
11
|
-
marginBottom:
|
|
12
|
-
marginLeft:
|
|
13
|
-
}, children:
|
|
14
|
-
job.
|
|
12
|
+
marginTop: 1,
|
|
13
|
+
marginBottom: 1,
|
|
14
|
+
marginLeft: 1,
|
|
15
|
+
}, children: [_jsx(Box, { sx: { width: '100%' }, "data-testid": "job-progress", children: _jsx(StatusProgressBar, { fraction: progressPct === undefined ? undefined : progressPct / 100 }) }), progressPct === undefined ? null : (_jsx(Box, { sx: { m: 1 }, children: _jsx(Typography, { children: `${Math.round(progressPct)}%` }) }))] })] }), _jsx(CardActions, { children: _jsx(Button, { variant: "contained", color: "inherit", disabled: clicked, onClick: () => {
|
|
16
|
+
job.update({ statusMessage: 'Cancelling…' });
|
|
15
17
|
job.cancelCallback();
|
|
16
18
|
setClicked(true);
|
|
17
|
-
}, children:
|
|
19
|
+
}, children: clicked ? 'Cancelling…' : 'Cancel' }) })] }));
|
|
18
20
|
});
|
|
19
21
|
export default CurrentJobCard;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { JobModel } from '../jobModel.ts';
|
|
2
2
|
declare const JobCard: ({ job }: {
|
|
3
|
-
job:
|
|
4
|
-
}) => import("react
|
|
3
|
+
job: JobModel;
|
|
4
|
+
}) => import("react").JSX.Element;
|
|
5
5
|
export default JobCard;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
3
|
-
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
4
|
-
import { Accordion, AccordionSummary, Card, CardContent, Typography, } from '@mui/material';
|
|
5
3
|
import { observer } from 'mobx-react';
|
|
6
|
-
import CurrentJobCard from
|
|
7
|
-
import JobCard from
|
|
4
|
+
import CurrentJobCard from './CurrentJobCard.js';
|
|
5
|
+
import JobCard from './JobCard.js';
|
|
6
|
+
import JobsSection from './JobsSection.js';
|
|
8
7
|
const useStyles = makeStyles()(theme => ({
|
|
9
8
|
root: {
|
|
10
9
|
margin: theme.spacing(1),
|
|
11
10
|
},
|
|
12
|
-
expandIcon: {
|
|
13
|
-
color: theme.palette.tertiary.contrastText,
|
|
14
|
-
},
|
|
15
11
|
}));
|
|
16
12
|
const JobsListWidget = observer(function JobsListWidget({ model, }) {
|
|
17
13
|
const { classes } = useStyles();
|
|
18
|
-
const { jobs
|
|
19
|
-
return (_jsxs("div", { className: classes.root, children: [
|
|
14
|
+
const { jobs } = model;
|
|
15
|
+
return (_jsxs("div", { className: classes.root, children: [_jsx(JobsSection, { title: "Running jobs", jobs: jobs.filter(j => j.state === 'running'), emptyText: "No running jobs", renderCard: job => _jsx(CurrentJobCard, { job: job }, job.name) }), _jsx(JobsSection, { title: "Queued jobs", jobs: jobs.filter(j => j.state === 'queued'), emptyText: "No queued jobs", renderCard: job => _jsx(JobCard, { job: job }, job.name) }), _jsx(JobsSection, { title: "Completed jobs", jobs: jobs.filter(j => j.state === 'finished'), emptyText: "No completed jobs", renderCard: job => _jsx(JobCard, { job: job }, job.name), onClear: () => {
|
|
16
|
+
model.clearJobs('finished');
|
|
17
|
+
} }), _jsx(JobsSection, { title: "Aborted jobs", jobs: jobs.filter(j => j.state === 'aborted'), emptyText: "No aborted jobs", renderCard: job => _jsx(JobCard, { job: job }, job.name), onClear: () => {
|
|
18
|
+
model.clearJobs('aborted');
|
|
19
|
+
} })] }));
|
|
20
20
|
});
|
|
21
21
|
export default JobsListWidget;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JobModel } from '../jobModel.ts';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
declare const JobsSection: ({ title, jobs, emptyText, renderCard, onClear, }: {
|
|
4
|
+
title: string;
|
|
5
|
+
jobs: JobModel[];
|
|
6
|
+
emptyText: string;
|
|
7
|
+
renderCard: (job: JobModel) => ReactNode;
|
|
8
|
+
onClear?: () => void;
|
|
9
|
+
}) => import("react").JSX.Element;
|
|
10
|
+
export default JobsSection;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
3
|
+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
4
|
+
import { Accordion, AccordionDetails, AccordionSummary, Button, Card, CardContent, Typography, } from '@mui/material';
|
|
5
|
+
import { observer } from 'mobx-react';
|
|
6
|
+
const useStyles = makeStyles()({
|
|
7
|
+
summaryTitle: {
|
|
8
|
+
flexGrow: 1,
|
|
9
|
+
},
|
|
10
|
+
clearRow: {
|
|
11
|
+
display: 'flex',
|
|
12
|
+
justifyContent: 'flex-end',
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
const JobsSection = observer(function JobsSection({ title, jobs, emptyText, renderCard, onClear, }) {
|
|
16
|
+
const { classes } = useStyles();
|
|
17
|
+
return (_jsxs(Accordion, { defaultExpanded: true, children: [_jsx(AccordionSummary, { expandIcon: _jsx(ExpandMoreIcon, {}), children: _jsx(Typography, { variant: "h5", className: classes.summaryTitle, children: title }) }), _jsxs(AccordionDetails, { children: [onClear && jobs.length ? (_jsx("div", { className: classes.clearRow, children: _jsx(Button, { size: "small", onClick: () => {
|
|
18
|
+
onClear();
|
|
19
|
+
}, children: "Clear" }) })) : null, jobs.length ? (jobs.map(job => renderCard(job))) : (_jsx(Card, { variant: "outlined", children: _jsx(CardContent, { children: _jsx(Typography, { variant: "body1", children: emptyText }) }) }))] })] }));
|
|
20
|
+
});
|
|
21
|
+
export default JobsSection;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type PluginManager from '@jbrowse/core/PluginManager';
|
|
2
|
-
export declare const configSchema: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
|
|
2
|
+
export declare const configSchema: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
|
|
3
3
|
export default function JobsListWidgetF(pluginManager: PluginManager): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { lazy } from 'react';
|
|
2
1
|
import { ConfigurationSchema } from '@jbrowse/core/configuration';
|
|
3
2
|
import { WidgetType } from '@jbrowse/core/pluggableElementTypes';
|
|
4
|
-
import {
|
|
3
|
+
import { lazyWithPreload } from '@jbrowse/core/util/lazyWithPreload';
|
|
4
|
+
import { stateModelFactory } from './model.js';
|
|
5
5
|
export const configSchema = ConfigurationSchema('JobsListWidget', {});
|
|
6
6
|
export default function JobsListWidgetF(pluginManager) {
|
|
7
7
|
pluginManager.addWidgetType(() => {
|
|
@@ -10,7 +10,7 @@ export default function JobsListWidgetF(pluginManager) {
|
|
|
10
10
|
heading: 'Jobs list',
|
|
11
11
|
configSchema,
|
|
12
12
|
stateModel: stateModelFactory(pluginManager),
|
|
13
|
-
ReactComponent:
|
|
13
|
+
ReactComponent: lazyWithPreload(() => import('./components/JobsListWidget.js')),
|
|
14
14
|
});
|
|
15
15
|
});
|
|
16
16
|
}
|
|
@@ -1,11 +1,30 @@
|
|
|
1
|
+
import type { Instance } from '@jbrowse/mobx-state-tree';
|
|
2
|
+
export type JobState = 'running' | 'queued' | 'finished' | 'aborted';
|
|
3
|
+
export interface JobFields {
|
|
4
|
+
state: JobState;
|
|
5
|
+
statusMessage?: string;
|
|
6
|
+
progressPct?: number;
|
|
7
|
+
cancelCallback: () => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* #stateModel
|
|
11
|
+
* #internal desktop text-indexing queue internals — kept out of the website docs
|
|
12
|
+
* #category widget
|
|
13
|
+
*
|
|
14
|
+
* Created standalone by `JobsListModel` and held in its volatile list rather
|
|
15
|
+
* than attached under it — nothing here belongs in a saved session.
|
|
16
|
+
*/
|
|
1
17
|
export declare const Job: import("@jbrowse/mobx-state-tree").IModelType<{
|
|
18
|
+
/**
|
|
19
|
+
* #property
|
|
20
|
+
*/
|
|
2
21
|
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
setProgressPct(pct: number): void;
|
|
22
|
+
}, JobFields & {
|
|
23
|
+
/**
|
|
24
|
+
* #action
|
|
25
|
+
* A key that is present is written, so `{statusMessage: undefined}` clears
|
|
26
|
+
* the message and `{}` touches nothing.
|
|
27
|
+
*/
|
|
28
|
+
update(fields: Partial<JobFields>): void;
|
|
11
29
|
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
30
|
+
export type JobModel = Instance<typeof Job>;
|
|
@@ -1,21 +1,48 @@
|
|
|
1
1
|
import { types } from '@jbrowse/mobx-state-tree';
|
|
2
|
+
/**
|
|
3
|
+
* #stateModel
|
|
4
|
+
* #internal desktop text-indexing queue internals — kept out of the website docs
|
|
5
|
+
* #category widget
|
|
6
|
+
*
|
|
7
|
+
* Created standalone by `JobsListModel` and held in its volatile list rather
|
|
8
|
+
* than attached under it — nothing here belongs in a saved session.
|
|
9
|
+
*/
|
|
2
10
|
export const Job = types
|
|
3
11
|
.model('Job', {
|
|
12
|
+
/**
|
|
13
|
+
* #property
|
|
14
|
+
*/
|
|
4
15
|
name: types.string,
|
|
5
|
-
statusMessage: types.maybe(types.string),
|
|
6
|
-
progressPct: types.number,
|
|
7
16
|
})
|
|
8
17
|
.volatile(() => ({
|
|
9
|
-
|
|
18
|
+
/**
|
|
19
|
+
* #volatile
|
|
20
|
+
* which of the widget's four sections the job is filed under. One field
|
|
21
|
+
* rather than membership of one of four lists, so it cannot be in two.
|
|
22
|
+
*/
|
|
23
|
+
state: 'queued',
|
|
24
|
+
/**
|
|
25
|
+
* #volatile
|
|
26
|
+
*/
|
|
27
|
+
statusMessage: undefined,
|
|
28
|
+
/**
|
|
29
|
+
* #volatile
|
|
30
|
+
* undefined when the current phase has no fraction to report, which the
|
|
31
|
+
* card draws as an indeterminate bar
|
|
32
|
+
*/
|
|
33
|
+
progressPct: undefined,
|
|
34
|
+
/**
|
|
35
|
+
* #volatile
|
|
36
|
+
*/
|
|
37
|
+
cancelCallback: () => { },
|
|
10
38
|
}))
|
|
11
39
|
.actions(self => ({
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
self.progressPct = pct;
|
|
40
|
+
/**
|
|
41
|
+
* #action
|
|
42
|
+
* A key that is present is written, so `{statusMessage: undefined}` clears
|
|
43
|
+
* the message and `{}` touches nothing.
|
|
44
|
+
*/
|
|
45
|
+
update(fields) {
|
|
46
|
+
Object.assign(self, fields);
|
|
20
47
|
},
|
|
21
48
|
}));
|
|
@@ -1,186 +1,66 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { JobFields, JobState } from './jobModel.ts';
|
|
2
2
|
import type PluginManager from '@jbrowse/core/PluginManager';
|
|
3
|
-
import type { Instance
|
|
4
|
-
export interface
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import type { Instance } from '@jbrowse/mobx-state-tree';
|
|
4
|
+
export interface JobInput extends Partial<JobFields> {
|
|
5
|
+
name: string;
|
|
6
|
+
state: JobState;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* #stateModel JobsListModel
|
|
10
|
+
* #internal desktop text-indexing queue internals — kept out of the website docs
|
|
11
|
+
* #category widget
|
|
12
|
+
*/
|
|
8
13
|
export declare function stateModelFactory(_pluginManager: PluginManager): import("@jbrowse/mobx-state-tree").IModelType<{
|
|
14
|
+
/**
|
|
15
|
+
* #property
|
|
16
|
+
*/
|
|
9
17
|
id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
progressPct: import("@jbrowse/mobx-state-tree").ISimpleType<number>;
|
|
15
|
-
}, {
|
|
16
|
-
cancelCallback(): void;
|
|
17
|
-
} & {
|
|
18
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
19
|
-
setStatusMessage(message?: string): void;
|
|
20
|
-
setProgressPct(pct: number): void;
|
|
21
|
-
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>;
|
|
22
|
-
finished: import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IModelType<{
|
|
23
|
-
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
24
|
-
statusMessage: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
25
|
-
progressPct: import("@jbrowse/mobx-state-tree").ISimpleType<number>;
|
|
26
|
-
}, {
|
|
27
|
-
cancelCallback(): void;
|
|
28
|
-
} & {
|
|
29
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
30
|
-
setStatusMessage(message?: string): void;
|
|
31
|
-
setProgressPct(pct: number): void;
|
|
32
|
-
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>;
|
|
33
|
-
queued: import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IModelType<{
|
|
34
|
-
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
35
|
-
statusMessage: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
36
|
-
progressPct: import("@jbrowse/mobx-state-tree").ISimpleType<number>;
|
|
37
|
-
}, {
|
|
38
|
-
cancelCallback(): void;
|
|
39
|
-
} & {
|
|
40
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
41
|
-
setStatusMessage(message?: string): void;
|
|
42
|
-
setProgressPct(pct: number): void;
|
|
43
|
-
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>;
|
|
44
|
-
aborted: import("@jbrowse/mobx-state-tree").IArrayType<import("@jbrowse/mobx-state-tree").IModelType<{
|
|
45
|
-
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
46
|
-
statusMessage: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
47
|
-
progressPct: import("@jbrowse/mobx-state-tree").ISimpleType<number>;
|
|
48
|
-
}, {
|
|
49
|
-
cancelCallback(): void;
|
|
50
|
-
} & {
|
|
51
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
52
|
-
setStatusMessage(message?: string): void;
|
|
53
|
-
setProgressPct(pct: number): void;
|
|
54
|
-
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>;
|
|
18
|
+
/**
|
|
19
|
+
* #property
|
|
20
|
+
*/
|
|
21
|
+
type: import("@jbrowse/mobx-state-tree").ILiteralType<"JobsListWidget">;
|
|
55
22
|
}, {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
64
|
-
setStatusMessage(message?: string): void;
|
|
65
|
-
setProgressPct(pct: number): void;
|
|
66
|
-
} & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/mobx-state-tree").IModelType<{
|
|
67
|
-
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
68
|
-
statusMessage: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
69
|
-
progressPct: import("@jbrowse/mobx-state-tree").ISimpleType<number>;
|
|
70
|
-
}, {
|
|
71
|
-
cancelCallback(): void;
|
|
72
|
-
} & {
|
|
73
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
74
|
-
setStatusMessage(message?: string): void;
|
|
75
|
-
setProgressPct(pct: number): void;
|
|
76
|
-
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>;
|
|
77
|
-
removeJob(jobName: string): ({
|
|
78
|
-
name: string;
|
|
79
|
-
statusMessage: string | undefined;
|
|
80
|
-
progressPct: number;
|
|
81
|
-
} & import("@jbrowse/mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
82
|
-
cancelCallback(): void;
|
|
83
|
-
} & {
|
|
84
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
85
|
-
setStatusMessage(message?: string): void;
|
|
86
|
-
setProgressPct(pct: number): void;
|
|
87
|
-
} & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/mobx-state-tree").IModelType<{
|
|
23
|
+
/**
|
|
24
|
+
* #volatile
|
|
25
|
+
* Volatile like the `jobsQueue` it mirrors: persisted, a session saved
|
|
26
|
+
* mid-index came back with a permanent "Running" card whose Cancel called
|
|
27
|
+
* the default no-op, and a "Queued" card in no queue.
|
|
28
|
+
*/
|
|
29
|
+
jobs: import("mobx").IObservableArray<import("@jbrowse/mobx-state-tree").ModelInstanceTypeProps<{
|
|
88
30
|
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}, {
|
|
92
|
-
cancelCallback(): void;
|
|
93
|
-
} & {
|
|
94
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
95
|
-
setStatusMessage(message?: string): void;
|
|
96
|
-
setProgressPct(pct: number): void;
|
|
97
|
-
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>) | undefined;
|
|
98
|
-
addFinishedJob(job: NewJob): ({
|
|
99
|
-
name: string;
|
|
100
|
-
statusMessage: string | undefined;
|
|
101
|
-
progressPct: number;
|
|
102
|
-
} & import("@jbrowse/mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
103
|
-
cancelCallback(): void;
|
|
104
|
-
} & {
|
|
105
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
106
|
-
setStatusMessage(message?: string): void;
|
|
107
|
-
setProgressPct(pct: number): void;
|
|
31
|
+
}> & JobFields & {
|
|
32
|
+
update(fields: Partial<JobFields>): void;
|
|
108
33
|
} & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/mobx-state-tree").IModelType<{
|
|
109
34
|
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
statusMessage: string | undefined;
|
|
122
|
-
progressPct: number;
|
|
123
|
-
} & import("@jbrowse/mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
124
|
-
cancelCallback(): void;
|
|
125
|
-
} & {
|
|
126
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
127
|
-
setStatusMessage(message?: string): void;
|
|
128
|
-
setProgressPct(pct: number): void;
|
|
129
|
-
} & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/mobx-state-tree").IModelType<{
|
|
130
|
-
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
131
|
-
statusMessage: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
132
|
-
progressPct: import("@jbrowse/mobx-state-tree").ISimpleType<number>;
|
|
133
|
-
}, {
|
|
134
|
-
cancelCallback(): void;
|
|
135
|
-
} & {
|
|
136
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
137
|
-
setStatusMessage(message?: string): void;
|
|
138
|
-
setProgressPct(pct: number): void;
|
|
139
|
-
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>) | undefined;
|
|
140
|
-
addAbortedJob(job: NewJob): ({
|
|
141
|
-
name: string;
|
|
142
|
-
statusMessage: string | undefined;
|
|
143
|
-
progressPct: number;
|
|
144
|
-
} & import("@jbrowse/mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
145
|
-
cancelCallback(): void;
|
|
146
|
-
} & {
|
|
147
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
148
|
-
setStatusMessage(message?: string): void;
|
|
149
|
-
setProgressPct(pct: number): void;
|
|
150
|
-
} & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/mobx-state-tree").IModelType<{
|
|
35
|
+
}, JobFields & {
|
|
36
|
+
update(fields: Partial<JobFields>): void;
|
|
37
|
+
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>>;
|
|
38
|
+
} & {
|
|
39
|
+
/**
|
|
40
|
+
* #action
|
|
41
|
+
* Files a job under `state`, or moves the one already named that and
|
|
42
|
+
* refreshes whatever fields came with it. A job runs, finishes and is
|
|
43
|
+
* retried under one name, so this is the only way a card is filed.
|
|
44
|
+
*/
|
|
45
|
+
addJob({ name, ...fields }: JobInput): import("@jbrowse/mobx-state-tree").ModelInstanceTypeProps<{
|
|
151
46
|
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}, {
|
|
155
|
-
cancelCallback(): void;
|
|
156
|
-
} & {
|
|
157
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
158
|
-
setStatusMessage(message?: string): void;
|
|
159
|
-
setProgressPct(pct: number): void;
|
|
160
|
-
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>) | undefined;
|
|
161
|
-
removeQueuedJob(jobName: string): ({
|
|
162
|
-
name: string;
|
|
163
|
-
statusMessage: string | undefined;
|
|
164
|
-
progressPct: number;
|
|
165
|
-
} & import("@jbrowse/mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
166
|
-
cancelCallback(): void;
|
|
167
|
-
} & {
|
|
168
|
-
setCancelCallback(cancelCallback: () => void): void;
|
|
169
|
-
setStatusMessage(message?: string): void;
|
|
170
|
-
setProgressPct(pct: number): void;
|
|
47
|
+
}> & JobFields & {
|
|
48
|
+
update(fields: Partial<JobFields>): void;
|
|
171
49
|
} & import("@jbrowse/mobx-state-tree").IStateTreeNode<import("@jbrowse/mobx-state-tree").IModelType<{
|
|
172
50
|
name: import("@jbrowse/mobx-state-tree").ISimpleType<string>;
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
},
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
51
|
+
}, JobFields & {
|
|
52
|
+
update(fields: Partial<JobFields>): void;
|
|
53
|
+
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>>;
|
|
54
|
+
/**
|
|
55
|
+
* #action
|
|
56
|
+
* A phase carrying no fraction clears the old one rather than leaving
|
|
57
|
+
* the bar where the last phase left it.
|
|
58
|
+
*/
|
|
59
|
+
updateJobStatus(name: string, statusMessage?: string, pct?: number): void;
|
|
60
|
+
/**
|
|
61
|
+
* #action
|
|
62
|
+
*/
|
|
63
|
+
clearJobs(state: JobState): void;
|
|
184
64
|
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
185
65
|
export type JobsListStateModel = ReturnType<typeof stateModelFactory>;
|
|
186
66
|
export type JobsListModel = Instance<JobsListStateModel>;
|
|
@@ -1,81 +1,65 @@
|
|
|
1
1
|
import { ElementId } from '@jbrowse/core/util/types/mst';
|
|
2
2
|
import { types } from '@jbrowse/mobx-state-tree';
|
|
3
|
-
import {
|
|
3
|
+
import { observable } from 'mobx';
|
|
4
|
+
import { Job } from './jobModel.js';
|
|
5
|
+
/**
|
|
6
|
+
* #stateModel JobsListModel
|
|
7
|
+
* #internal desktop text-indexing queue internals — kept out of the website docs
|
|
8
|
+
* #category widget
|
|
9
|
+
*/
|
|
4
10
|
export function stateModelFactory(_pluginManager) {
|
|
5
11
|
return types
|
|
6
12
|
.model('JobsListModel', {
|
|
13
|
+
/**
|
|
14
|
+
* #property
|
|
15
|
+
*/
|
|
7
16
|
id: ElementId,
|
|
17
|
+
/**
|
|
18
|
+
* #property
|
|
19
|
+
*/
|
|
8
20
|
type: types.literal('JobsListWidget'),
|
|
9
|
-
jobs: types.array(Job),
|
|
10
|
-
finished: types.array(Job),
|
|
11
|
-
queued: types.array(Job),
|
|
12
|
-
aborted: types.array(Job),
|
|
13
21
|
})
|
|
22
|
+
.volatile(() => ({
|
|
23
|
+
/**
|
|
24
|
+
* #volatile
|
|
25
|
+
* Volatile like the `jobsQueue` it mirrors: persisted, a session saved
|
|
26
|
+
* mid-index came back with a permanent "Running" card whose Cancel called
|
|
27
|
+
* the default no-op, and a "Queued" card in no queue.
|
|
28
|
+
*/
|
|
29
|
+
jobs: observable.array([], { deep: false }),
|
|
30
|
+
}))
|
|
14
31
|
.actions(self => ({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
addedJob.setCancelCallback(cancelCallback);
|
|
24
|
-
return addedJob;
|
|
25
|
-
},
|
|
26
|
-
removeJob(jobName) {
|
|
27
|
-
const index = self.jobs.findIndex(job => job.name === jobName);
|
|
28
|
-
if (index === -1) {
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
31
|
-
const removed = self.jobs.splice(index, 1);
|
|
32
|
-
return removed[0];
|
|
33
|
-
},
|
|
34
|
-
addFinishedJob(job) {
|
|
35
|
-
const existing = self.finished.find(finishedJob => finishedJob.name === job.name);
|
|
36
|
-
if (existing) {
|
|
37
|
-
return existing;
|
|
38
|
-
}
|
|
39
|
-
const length = self.finished.push(job);
|
|
40
|
-
return self.finished[length - 1];
|
|
41
|
-
},
|
|
42
|
-
addQueuedJob(job) {
|
|
43
|
-
const existing = self.queued.find(queuedJob => queuedJob.name === job.name);
|
|
44
|
-
if (existing) {
|
|
45
|
-
return existing;
|
|
46
|
-
}
|
|
47
|
-
const length = self.queued.push(job);
|
|
48
|
-
return self.queued[length - 1];
|
|
49
|
-
},
|
|
50
|
-
addAbortedJob(job) {
|
|
51
|
-
const existing = self.aborted.find(abortedJob => abortedJob.name === job.name);
|
|
52
|
-
if (existing) {
|
|
53
|
-
return existing;
|
|
54
|
-
}
|
|
55
|
-
const length = self.aborted.push(job);
|
|
56
|
-
return self.aborted[length - 1];
|
|
57
|
-
},
|
|
58
|
-
removeQueuedJob(jobName) {
|
|
59
|
-
const index = self.queued.findIndex(job => job.name === jobName);
|
|
60
|
-
if (index === -1) {
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
const removed = self.queued.splice(index, 1);
|
|
64
|
-
return removed[0];
|
|
65
|
-
},
|
|
66
|
-
updateJobStatusMessage(jobName, message) {
|
|
67
|
-
const job = self.jobs.find(job => job.name === jobName);
|
|
32
|
+
/**
|
|
33
|
+
* #action
|
|
34
|
+
* Files a job under `state`, or moves the one already named that and
|
|
35
|
+
* refreshes whatever fields came with it. A job runs, finishes and is
|
|
36
|
+
* retried under one name, so this is the only way a card is filed.
|
|
37
|
+
*/
|
|
38
|
+
addJob({ name, ...fields }) {
|
|
39
|
+
let job = self.jobs.find(j => j.name === name);
|
|
68
40
|
if (!job) {
|
|
69
|
-
|
|
41
|
+
job = Job.create({ name });
|
|
42
|
+
self.jobs.push(job);
|
|
70
43
|
}
|
|
71
|
-
job.
|
|
44
|
+
job.update(fields);
|
|
45
|
+
return job;
|
|
72
46
|
},
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
47
|
+
/**
|
|
48
|
+
* #action
|
|
49
|
+
* A phase carrying no fraction clears the old one rather than leaving
|
|
50
|
+
* the bar where the last phase left it.
|
|
51
|
+
*/
|
|
52
|
+
updateJobStatus(name, statusMessage, pct) {
|
|
53
|
+
// absent if the widget was rebuilt while a status callback was in flight
|
|
54
|
+
self.jobs
|
|
55
|
+
.find(j => j.name === name)
|
|
56
|
+
?.update({ statusMessage, progressPct: pct });
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* #action
|
|
60
|
+
*/
|
|
61
|
+
clearJobs(state) {
|
|
62
|
+
self.jobs.replace(self.jobs.filter(j => j.state !== state));
|
|
79
63
|
},
|
|
80
64
|
}));
|
|
81
65
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { JobsListModel } from './JobsListWidget/model.ts';
|
|
2
|
+
import type { SessionWithWidgets } from '@jbrowse/core/util';
|
|
3
|
+
/**
|
|
4
|
+
* Get the singleton JobsList widget for a session, creating it if absent. The
|
|
5
|
+
* widget map is untyped (`Widget`), so the result is cast to the concrete
|
|
6
|
+
* model that this plugin registers.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getOrCreateJobsListWidget(session: SessionWithWidgets): JobsListModel;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the singleton JobsList widget for a session, creating it if absent. The
|
|
3
|
+
* widget map is untyped (`Widget`), so the result is cast to the concrete
|
|
4
|
+
* model that this plugin registers.
|
|
5
|
+
*/
|
|
6
|
+
export function getOrCreateJobsListWidget(session) {
|
|
7
|
+
const existing = session.widgets.get('JobsList');
|
|
8
|
+
return (existing ??
|
|
9
|
+
session.addWidget('JobsListWidget', 'JobsList'));
|
|
10
|
+
}
|
package/esm/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Plugin from '@jbrowse/core/Plugin';
|
|
2
2
|
import type PluginManager from '@jbrowse/core/PluginManager';
|
|
3
|
+
export { getOrCreateJobsListWidget } from './getOrCreateJobsListWidget.ts';
|
|
3
4
|
export type { JobsListModel } from './JobsListWidget/model.ts';
|
|
4
5
|
export default class JobsManagementPlugin extends Plugin {
|
|
5
6
|
name: string;
|
package/esm/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import Plugin from '@jbrowse/core/Plugin';
|
|
2
2
|
import { Indexing } from '@jbrowse/core/ui/Icons';
|
|
3
3
|
import { isAbstractMenuManager, isSessionModelWithWidgets, } from '@jbrowse/core/util';
|
|
4
|
-
import JobsListWidgetF from
|
|
4
|
+
import JobsListWidgetF from './JobsListWidget/index.js';
|
|
5
|
+
import { getOrCreateJobsListWidget } from './getOrCreateJobsListWidget.js';
|
|
6
|
+
export { getOrCreateJobsListWidget } from './getOrCreateJobsListWidget.js';
|
|
5
7
|
export default class JobsManagementPlugin extends Plugin {
|
|
6
8
|
name = 'JobsManagementPlugin';
|
|
7
9
|
install(pluginManager) {
|
|
@@ -11,18 +13,17 @@ export default class JobsManagementPlugin extends Plugin {
|
|
|
11
13
|
if (isAbstractMenuManager(pluginManager.rootModel)) {
|
|
12
14
|
pluginManager.rootModel.appendToMenu('Tools', {
|
|
13
15
|
label: 'Jobs list',
|
|
14
|
-
icon: Indexing,
|
|
16
|
+
icon: Indexing, // TODO: pick a better icon
|
|
17
|
+
// `unknown`, not SessionWithWidgets: MenuItemClickHandler is
|
|
18
|
+
// `(...args: any[]) => void`, so annotating the parameter asserts a
|
|
19
|
+
// shape rather than checking one, and it made the guard below read as
|
|
20
|
+
// redundant with its own signature. It is not — it is the only check
|
|
21
|
+
// there is. Every JBrowse app happens to pass an AppSession, which has
|
|
22
|
+
// widgets, but that is a fact about the app on the other side of a
|
|
23
|
+
// package boundary and an untyped callback contract.
|
|
15
24
|
onClick: (session) => {
|
|
16
25
|
if (isSessionModelWithWidgets(session)) {
|
|
17
|
-
|
|
18
|
-
let jobStatusWidget = widgets.get('JobsList');
|
|
19
|
-
if (!jobStatusWidget) {
|
|
20
|
-
jobStatusWidget = session.addWidget('JobsListWidget', 'JobsList');
|
|
21
|
-
session.showWidget(jobStatusWidget);
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
session.showWidget(jobStatusWidget);
|
|
25
|
-
}
|
|
26
|
+
session.showWidget(getOrCreateJobsListWidget(session));
|
|
26
27
|
}
|
|
27
28
|
},
|
|
28
29
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-jobs-management",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-beta.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "JBrowse 2 jobs management",
|
|
6
6
|
"keywords": [
|
|
@@ -21,15 +21,15 @@
|
|
|
21
21
|
"esm"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@jbrowse/mobx-state-tree": "^
|
|
25
|
-
"@mui/icons-material": "^
|
|
26
|
-
"@mui/material": "^
|
|
27
|
-
"mobx": "^
|
|
28
|
-
"mobx-react": "^
|
|
29
|
-
"@jbrowse/core": "^
|
|
24
|
+
"@jbrowse/mobx-state-tree": "^6.6.1",
|
|
25
|
+
"@mui/icons-material": "^9.4.0",
|
|
26
|
+
"@mui/material": "^9.4.0",
|
|
27
|
+
"mobx": "^7.0.5",
|
|
28
|
+
"mobx-react": "^10.0.2",
|
|
29
|
+
"@jbrowse/core": "^5.0.0-beta.10"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"react": ">=
|
|
32
|
+
"react": ">=19.0.0"
|
|
33
33
|
},
|
|
34
34
|
"publishConfig": {
|
|
35
35
|
"access": "public"
|
|
@@ -39,14 +39,11 @@
|
|
|
39
39
|
"build": "pnpm run /^build:/",
|
|
40
40
|
"test": "cd ../..; jest --passWithNoTests plugins/jobs-management",
|
|
41
41
|
"prebuild": "pnpm clean",
|
|
42
|
-
"build:esm": "tsc
|
|
42
|
+
"build:esm": "node ../../node_modules/typescript7/bin/tsc --build tsconfig.build.esm.json",
|
|
43
43
|
"clean": "rimraf esm *.tsbuildinfo"
|
|
44
44
|
},
|
|
45
45
|
"types": "esm/index.d.ts",
|
|
46
46
|
"exports": {
|
|
47
|
-
".":
|
|
48
|
-
"types": "./esm/index.d.ts",
|
|
49
|
-
"import": "./esm/index.js"
|
|
50
|
-
}
|
|
47
|
+
".": "./esm/index.js"
|
|
51
48
|
}
|
|
52
49
|
}
|