@jbrowse/plugin-config 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/ConfigurationEditorWidget/components/AddNewField.d.ts +6 -0
- package/esm/ConfigurationEditorWidget/components/AddNewField.js +29 -0
- package/esm/ConfigurationEditorWidget/components/BooleanEditor.d.ts +3 -2
- package/esm/ConfigurationEditorWidget/components/BooleanEditor.js +6 -4
- package/esm/ConfigurationEditorWidget/components/CallbackEditor.d.ts +4 -2
- package/esm/ConfigurationEditorWidget/components/CallbackEditor.js +24 -42
- package/esm/ConfigurationEditorWidget/components/ColorEditor.d.ts +5 -12
- package/esm/ConfigurationEditorWidget/components/ColorEditor.js +47 -22
- package/esm/ConfigurationEditorWidget/components/ConfigurationEditor.d.ts +2 -3
- package/esm/ConfigurationEditorWidget/components/ConfigurationEditor.js +168 -29
- package/esm/ConfigurationEditorWidget/components/ConfigurationTextField.d.ts +1 -1
- package/esm/ConfigurationEditorWidget/components/ConfigurationTextField.js +10 -2
- package/esm/ConfigurationEditorWidget/components/EntryListEditor.d.ts +17 -0
- package/esm/ConfigurationEditorWidget/components/EntryListEditor.js +35 -0
- package/esm/ConfigurationEditorWidget/components/HeadingComponent.d.ts +1 -1
- package/esm/ConfigurationEditorWidget/components/IntegerEditor.d.ts +10 -0
- package/esm/ConfigurationEditorWidget/components/IntegerEditor.js +9 -0
- package/esm/ConfigurationEditorWidget/components/JsonEditor.d.ts +2 -1
- package/esm/ConfigurationEditorWidget/components/JsonEditor.js +24 -41
- package/esm/ConfigurationEditorWidget/components/MapEntryCard.d.ts +8 -0
- package/esm/ConfigurationEditorWidget/components/MapEntryCard.js +23 -0
- package/esm/ConfigurationEditorWidget/components/MapSlotEditor.d.ts +8 -0
- package/esm/ConfigurationEditorWidget/components/MapSlotEditor.js +18 -0
- package/esm/ConfigurationEditorWidget/components/NumberEditor.d.ts +5 -4
- package/esm/ConfigurationEditorWidget/components/NumberEditor.js +15 -15
- package/esm/ConfigurationEditorWidget/components/NumberMapEditor.d.ts +4 -4
- package/esm/ConfigurationEditorWidget/components/NumberMapEditor.js +7 -31
- package/esm/ConfigurationEditorWidget/components/SlotEditor.d.ts +4 -5
- package/esm/ConfigurationEditorWidget/components/SlotEditor.js +88 -49
- package/esm/ConfigurationEditorWidget/components/StringArrayEditor.d.ts +16 -10
- package/esm/ConfigurationEditorWidget/components/StringArrayEditor.js +22 -25
- package/esm/ConfigurationEditorWidget/components/StringArrayMapEditor.d.ts +3 -6
- package/esm/ConfigurationEditorWidget/components/StringArrayMapEditor.js +14 -39
- package/esm/ConfigurationEditorWidget/components/StringMapEditor.d.ts +10 -0
- package/esm/ConfigurationEditorWidget/components/StringMapEditor.js +13 -0
- package/esm/ConfigurationEditorWidget/components/TypeSelector.d.ts +2 -2
- package/esm/ConfigurationEditorWidget/components/TypeSelector.js +2 -2
- package/esm/ConfigurationEditorWidget/components/singularSlotName.d.ts +13 -0
- package/esm/ConfigurationEditorWidget/components/singularSlotName.js +23 -0
- package/esm/ConfigurationEditorWidget/components/useSlotEditorStyles.d.ts +2 -2
- package/esm/ConfigurationEditorWidget/components/useSlotEditorStyles.js +6 -1
- package/esm/ConfigurationEditorWidget/index.js +4 -4
- package/esm/ConfigurationEditorWidget/model.d.ts +8 -1
- package/esm/ConfigurationEditorWidget/model.js +40 -1
- package/esm/FromConfigAdapter/FromConfigAdapter.d.ts +6 -1
- package/esm/FromConfigAdapter/FromConfigAdapter.js +31 -1
- package/esm/FromConfigAdapter/configSchema.d.ts +32 -4
- package/esm/FromConfigAdapter/configSchema.js +34 -2
- package/esm/FromConfigAdapter/index.js +2 -2
- package/esm/FromConfigRegionsAdapter/FromConfigRegionsAdapter.d.ts +8 -0
- package/esm/FromConfigRegionsAdapter/FromConfigRegionsAdapter.js +10 -25
- package/esm/FromConfigRegionsAdapter/configSchema.d.ts +38 -4
- package/esm/FromConfigRegionsAdapter/configSchema.js +39 -2
- package/esm/FromConfigRegionsAdapter/index.js +2 -2
- package/esm/FromConfigSequenceAdapter/FromConfigSequenceAdapter.d.ts +15 -2
- package/esm/FromConfigSequenceAdapter/FromConfigSequenceAdapter.js +32 -40
- package/esm/FromConfigSequenceAdapter/configSchema.d.ts +37 -4
- package/esm/FromConfigSequenceAdapter/configSchema.js +38 -2
- package/esm/FromConfigSequenceAdapter/index.js +2 -2
- package/esm/NcbiSequenceReportAliasAdapter/NcbiSequenceReportAliasAdapter.d.ts +5 -4
- package/esm/NcbiSequenceReportAliasAdapter/NcbiSequenceReportAliasAdapter.js +28 -24
- package/esm/NcbiSequenceReportAliasAdapter/configSchema.d.ts +69 -10
- package/esm/NcbiSequenceReportAliasAdapter/configSchema.js +82 -18
- package/esm/NcbiSequenceReportAliasAdapter/index.js +3 -2
- package/esm/RefNameAliasAdapter/RefNameAliasAdapter.d.ts +4 -3
- package/esm/RefNameAliasAdapter/RefNameAliasAdapter.js +22 -28
- package/esm/RefNameAliasAdapter/configSchema.d.ts +70 -12
- package/esm/RefNameAliasAdapter/configSchema.js +89 -18
- package/esm/RefNameAliasAdapter/index.js +3 -2
- package/esm/aliasUtils.d.ts +4 -0
- package/esm/aliasUtils.js +19 -0
- package/esm/index.d.ts +2 -2
- package/esm/index.js +7 -7
- package/package.json +11 -15
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** #slotEditor numeric text field that rounds to an integer */
|
|
2
|
+
declare const IntegerEditor: ({ slot, }: {
|
|
3
|
+
slot: {
|
|
4
|
+
name?: string;
|
|
5
|
+
value: number;
|
|
6
|
+
description?: string;
|
|
7
|
+
set: (num: number) => void;
|
|
8
|
+
};
|
|
9
|
+
}) => import("react").JSX.Element;
|
|
10
|
+
export default IntegerEditor;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { observer } from 'mobx-react';
|
|
3
|
+
import NumberEditor from './NumberEditor.js';
|
|
4
|
+
// thin wrapper: an integer slot is a number slot that only commits whole values
|
|
5
|
+
/** #slotEditor numeric text field that rounds to an integer */
|
|
6
|
+
const IntegerEditor = observer(function IntegerEditor({ slot, }) {
|
|
7
|
+
return _jsx(NumberEditor, { slot: slot, integer: true });
|
|
8
|
+
});
|
|
9
|
+
export default IntegerEditor;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** #slotEditor monospace textarea holding arbitrary JSON */
|
|
1
2
|
declare const JsonEditor: ({ slot, }: {
|
|
2
3
|
slot: {
|
|
3
4
|
name: string;
|
|
@@ -5,5 +6,5 @@ declare const JsonEditor: ({ slot, }: {
|
|
|
5
6
|
value: unknown;
|
|
6
7
|
set: (arg: unknown) => void;
|
|
7
8
|
};
|
|
8
|
-
}) => import("react
|
|
9
|
+
}) => import("react").JSX.Element;
|
|
9
10
|
export default JsonEditor;
|
|
@@ -1,53 +1,36 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { MonospaceTextField } from '@jbrowse/core/ui';
|
|
4
|
+
import { alpha } from '@jbrowse/core/ui/palette';
|
|
3
5
|
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
|
-
import { InputLabel, TextField } from '@mui/material';
|
|
5
6
|
import { observer } from 'mobx-react';
|
|
6
|
-
const fontSize = '12px';
|
|
7
|
-
const fontFamily = 'Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace';
|
|
8
7
|
const useStyles = makeStyles()(theme => ({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
fontSize: '0.8em',
|
|
12
|
-
},
|
|
13
|
-
callbackEditor: {
|
|
14
|
-
fontFamily,
|
|
15
|
-
fontSize,
|
|
8
|
+
jsonEditor: {
|
|
9
|
+
fontSize: '12px',
|
|
16
10
|
background: theme.palette.background.default,
|
|
17
|
-
width: 800,
|
|
18
|
-
marginTop: '16px',
|
|
19
|
-
border: '1px solid rgba(0,0,0,0.42)',
|
|
20
|
-
},
|
|
21
|
-
callbackContainer: {
|
|
22
11
|
width: '100%',
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
textAreaFont: {
|
|
26
|
-
fontFamily,
|
|
12
|
+
marginTop: '16px',
|
|
13
|
+
border: `1px solid ${alpha(theme.palette.text.primary, 0.42)}`,
|
|
27
14
|
},
|
|
28
15
|
}));
|
|
16
|
+
/** #slotEditor monospace textarea holding arbitrary JSON */
|
|
29
17
|
const JsonEditor = observer(function JsonEditor({ slot, }) {
|
|
30
18
|
const { classes } = useStyles();
|
|
31
|
-
|
|
19
|
+
// A `maybeFrozen` slot is `undefined` when unset, and `JSON.stringify(undefined)`
|
|
20
|
+
// returns the *value* `undefined` rather than a string — which handed
|
|
21
|
+
// MonospaceTextField an undefined `value` and made the field uncontrolled
|
|
22
|
+
// until the first keystroke (React then warns on the switch).
|
|
23
|
+
const [contents, setContents] = useState(() => slot.value === undefined ? '' : JSON.stringify(slot.value, null, 2));
|
|
32
24
|
const [error, setError] = useState();
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return (_jsxs(_Fragment, { children: [error ? _jsx("p", { className: classes.error, children: `${error}` }) : null, _jsxs("div", { className: classes.callbackContainer, children: [_jsx(InputLabel, { shrink: true, htmlFor: "json-editor", children: slot.name }), _jsx(TextField, { id: "json-editor", className: classes.callbackEditor, value: contents, helperText: slot.description, multiline: true, onChange: event => {
|
|
44
|
-
setContents(event.target.value);
|
|
45
|
-
}, style: { background: error ? '#fdd' : undefined }, slotProps: {
|
|
46
|
-
input: {
|
|
47
|
-
classes: {
|
|
48
|
-
input: classes.textAreaFont,
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
} })] })] }));
|
|
25
|
+
return (_jsx(MonospaceTextField, { className: classes.jsonEditor, label: slot.name, value: contents, error: error, helperText: slot.description, onChange: val => {
|
|
26
|
+
setContents(val);
|
|
27
|
+
try {
|
|
28
|
+
slot.set(JSON.parse(val));
|
|
29
|
+
setError(undefined);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
setError(e);
|
|
33
|
+
}
|
|
34
|
+
} }));
|
|
52
35
|
});
|
|
53
36
|
export default JsonEditor;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export default function MapEntryCard({ title, onDelete, children, }: {
|
|
2
|
+
title: string;
|
|
3
|
+
onDelete: () => void;
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
}): import("react").JSX.Element;
|
|
6
|
+
export declare function MapAddCard({ onAdd }: {
|
|
7
|
+
onAdd: (key: string) => void;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
3
|
+
import DeleteIcon from '@mui/icons-material/Delete';
|
|
4
|
+
import { Card, CardContent, CardHeader, IconButton } from '@mui/material';
|
|
5
|
+
import AddNewField from './AddNewField.js';
|
|
6
|
+
const useStyles = makeStyles()(theme => ({
|
|
7
|
+
card: {
|
|
8
|
+
marginTop: theme.spacing(1),
|
|
9
|
+
},
|
|
10
|
+
}));
|
|
11
|
+
// shared card for a single key in a map slot editor: a titled card with a
|
|
12
|
+
// delete button wrapping the per-value editor passed as children
|
|
13
|
+
export default function MapEntryCard({ title, onDelete, children, }) {
|
|
14
|
+
const { classes } = useStyles();
|
|
15
|
+
return (_jsxs(Card, { raised: true, className: classes.card, children: [_jsx(CardHeader, { title: title, action: _jsx(IconButton, { onClick: () => {
|
|
16
|
+
onDelete();
|
|
17
|
+
}, children: _jsx(DeleteIcon, {}) }) }), _jsx(CardContent, { children: children })] }));
|
|
18
|
+
}
|
|
19
|
+
// trailing card in a map slot editor holding the "add new key" field
|
|
20
|
+
export function MapAddCard({ onAdd }) {
|
|
21
|
+
const { classes } = useStyles();
|
|
22
|
+
return (_jsx(Card, { raised: true, className: classes.card, children: _jsx(CardHeader, { disableTypography: true, title: _jsx(AddNewField, { onAdd: onAdd }) }) }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export default function MapSlotEditor<V>({ name, description, entries, emptyValue, setMap, renderValue, }: {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
entries: [string, V][];
|
|
5
|
+
emptyValue: V;
|
|
6
|
+
setMap: (val: Record<string, V>) => void;
|
|
7
|
+
renderValue: (val: V, set: (val: V) => void, key: string) => React.ReactNode;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { FormHelperText, InputLabel } from '@mui/material';
|
|
3
|
+
import MapEntryCard, { MapAddCard } from './MapEntryCard.js';
|
|
4
|
+
// shared shell for map slot editors (numberMap, stringArrayMap): a labelled
|
|
5
|
+
// list of per-key cards plus an "add key" card. The owning wrapper stays the
|
|
6
|
+
// observer and passes plain entries in, so this stays a non-observer generic
|
|
7
|
+
// (which keeps JSX type args working at the call sites).
|
|
8
|
+
export default function MapSlotEditor({ name, description, entries, emptyValue, setMap, renderValue, }) {
|
|
9
|
+
const obj = Object.fromEntries(entries);
|
|
10
|
+
return (_jsxs(_Fragment, { children: [_jsx(InputLabel, { children: name }), entries.map(([key, val]) => (_jsx(MapEntryCard, { title: key, onDelete: () => {
|
|
11
|
+
const { [key]: _omit, ...rest } = obj;
|
|
12
|
+
setMap(rest);
|
|
13
|
+
}, children: renderValue(val, newVal => {
|
|
14
|
+
setMap({ ...obj, [key]: newVal });
|
|
15
|
+
}, key) }, key))), _jsx(MapAddCard, { onAdd: key => {
|
|
16
|
+
setMap({ ...obj, [key]: emptyValue });
|
|
17
|
+
} }), _jsx(FormHelperText, { children: description })] }));
|
|
18
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/** #slotEditor numeric text field */
|
|
2
|
+
declare const NumberEditor: ({ slot, integer, }: {
|
|
2
3
|
slot: {
|
|
3
4
|
name?: string;
|
|
4
|
-
value:
|
|
5
|
+
value: number | undefined;
|
|
5
6
|
description?: string;
|
|
6
7
|
set: (val: number) => void;
|
|
7
|
-
reset?: () => void;
|
|
8
8
|
};
|
|
9
|
-
|
|
9
|
+
integer?: boolean;
|
|
10
|
+
}) => import("react").JSX.Element;
|
|
10
11
|
export default NumberEditor;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useState } from 'react';
|
|
3
3
|
import { observer } from 'mobx-react';
|
|
4
|
-
import ConfigurationTextField from
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
4
|
+
import ConfigurationTextField from './ConfigurationTextField.js';
|
|
5
|
+
/** #slotEditor numeric text field */
|
|
6
|
+
const NumberEditor = observer(function NumberEditor({ slot, integer = false, }) {
|
|
7
|
+
const [val, setVal] = useState(slot.value === undefined ? '' : String(slot.value));
|
|
8
|
+
return (_jsx(ConfigurationTextField, { label: slot.name, helperText: slot.description, value: val, onChange: evt => {
|
|
9
|
+
const v = evt.target.value;
|
|
10
|
+
setVal(v);
|
|
11
|
+
const num = Number(v);
|
|
12
|
+
// commit only valid values; the text buffer preserves in-progress
|
|
13
|
+
// entries like "-" or "1." without writing garbage to the config
|
|
14
|
+
const valid = integer ? Number.isInteger(num) : Number.isFinite(num);
|
|
15
|
+
if (v !== '' && valid) {
|
|
16
|
+
slot.set(num);
|
|
17
|
+
}
|
|
18
18
|
} }));
|
|
19
19
|
});
|
|
20
20
|
export default NumberEditor;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
/** #slotEditor one card per key, each holding that key's numeric field */
|
|
1
2
|
declare const NumberMapEditor: ({ slot, }: {
|
|
2
3
|
slot: {
|
|
3
4
|
name: string;
|
|
4
|
-
value: Map<string,
|
|
5
|
-
|
|
6
|
-
add: (key: string, val: number) => void;
|
|
5
|
+
value: Map<string, number>;
|
|
6
|
+
set: (val: Record<string, number>) => void;
|
|
7
7
|
description: string;
|
|
8
8
|
};
|
|
9
|
-
}) => import("react
|
|
9
|
+
}) => import("react").JSX.Element;
|
|
10
10
|
export default NumberMapEditor;
|
|
@@ -1,35 +1,11 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
|
-
import AddIcon from '@mui/icons-material/Add';
|
|
5
|
-
import DeleteIcon from '@mui/icons-material/Delete';
|
|
6
|
-
import { Card, CardContent, CardHeader, FormHelperText, IconButton, InputAdornment, InputLabel, TextField, } from '@mui/material';
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
2
|
import { observer } from 'mobx-react';
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
marginTop: theme.spacing(1),
|
|
12
|
-
},
|
|
13
|
-
}));
|
|
3
|
+
import MapSlotEditor from './MapSlotEditor.js';
|
|
4
|
+
import NumberEditor from './NumberEditor.js';
|
|
5
|
+
/** #slotEditor one card per key, each holding that key's numeric field */
|
|
14
6
|
const NumberMapEditor = observer(function NumberMapEditor({ slot, }) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
slot.remove(key);
|
|
19
|
-
}, children: _jsx(DeleteIcon, {}) }) }), _jsx(CardContent, { children: _jsx(NumberEditor, { slot: {
|
|
20
|
-
value: val,
|
|
21
|
-
set: (val) => {
|
|
22
|
-
slot.add(key, val);
|
|
23
|
-
},
|
|
24
|
-
} }) })] }, key))), _jsx(Card, { raised: true, className: classes.card, children: _jsx(CardHeader, { disableTypography: true, title: _jsx(TextField, { fullWidth: true, value: value, placeholder: "add new", onChange: event => {
|
|
25
|
-
setValue(event.target.value);
|
|
26
|
-
}, slotProps: {
|
|
27
|
-
input: {
|
|
28
|
-
endAdornment: (_jsx(InputAdornment, { position: "end", children: _jsx(IconButton, { disabled: value === '', onClick: () => {
|
|
29
|
-
slot.add(value, 0);
|
|
30
|
-
setValue('');
|
|
31
|
-
}, children: _jsx(AddIcon, {}) }) })),
|
|
32
|
-
},
|
|
33
|
-
} }) }) }), _jsx(FormHelperText, { children: slot.description })] }));
|
|
7
|
+
return (_jsx(MapSlotEditor, { name: slot.name, description: slot.description, entries: [...slot.value], emptyValue: 0, setMap: val => {
|
|
8
|
+
slot.set(val);
|
|
9
|
+
}, renderValue: (val, set) => _jsx(NumberEditor, { slot: { value: val, set } }) }));
|
|
34
10
|
});
|
|
35
11
|
export default NumberMapEditor;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
declare const SlotEditor: ({ slot,
|
|
3
|
-
slot:
|
|
4
|
-
|
|
5
|
-
}) => import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
import type { SlotFacade } from '@jbrowse/core/configuration';
|
|
2
|
+
declare const SlotEditor: ({ slot, }: {
|
|
3
|
+
slot: SlotFacade;
|
|
4
|
+
}) => import("react").JSX.Element;
|
|
6
5
|
export default SlotEditor;
|
|
@@ -1,86 +1,125 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { isCallbackValue, toCallbackValue, toFixedValue, } from '@jbrowse/core/configuration';
|
|
3
4
|
import { FileSelector } from '@jbrowse/core/ui';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked';
|
|
8
|
-
import { IconButton, MenuItem, Paper, SvgIcon, TextField } from '@mui/material';
|
|
5
|
+
import CodeIcon from '@mui/icons-material/Code';
|
|
6
|
+
import RestartAltIcon from '@mui/icons-material/RestartAlt';
|
|
7
|
+
import { IconButton, MenuItem, Paper, TextField, Tooltip } from '@mui/material';
|
|
9
8
|
import { observer } from 'mobx-react';
|
|
10
|
-
import BooleanEditor from
|
|
11
|
-
import CallbackEditor from
|
|
12
|
-
import ColorEditor from
|
|
13
|
-
import ConfigurationTextField from
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import {
|
|
9
|
+
import BooleanEditor from './BooleanEditor.js';
|
|
10
|
+
import CallbackEditor from './CallbackEditor.js';
|
|
11
|
+
import ColorEditor from './ColorEditor.js';
|
|
12
|
+
import ConfigurationTextField from './ConfigurationTextField.js';
|
|
13
|
+
import { ColorArrayEditor, StringEnumArrayEditor } from './EntryListEditor.js';
|
|
14
|
+
import IntegerEditor from './IntegerEditor.js';
|
|
15
|
+
import JsonEditor from './JsonEditor.js';
|
|
16
|
+
import NumberEditor from './NumberEditor.js';
|
|
17
|
+
import NumberMapEditor from './NumberMapEditor.js';
|
|
18
|
+
import StringArrayEditor, { ExpressionArrayEditor, } from './StringArrayEditor.js';
|
|
19
|
+
import StringArrayMapEditor from './StringArrayMapEditor.js';
|
|
20
|
+
import StringMapEditor from './StringMapEditor.js';
|
|
21
|
+
import { useSlotEditorStyles } from './useSlotEditorStyles.js';
|
|
22
|
+
// Also drives `maybeString`, whose value is `undefined` while unset: clearing
|
|
23
|
+
// the field leaves the empty string, which is a value, and the reset button
|
|
24
|
+
// returns the slot to unset.
|
|
25
|
+
/** #slotEditor single-line text field */
|
|
20
26
|
const StringEditor = observer(function StringEditor({ slot, }) {
|
|
21
|
-
return (_jsx(ConfigurationTextField, { label: slot.name, helperText: slot.description, value: slot.value, onChange: evt => {
|
|
27
|
+
return (_jsx(ConfigurationTextField, { label: slot.name, helperText: slot.description, value: slot.value ?? '', onChange: evt => {
|
|
22
28
|
slot.set(evt.target.value);
|
|
23
29
|
} }));
|
|
24
30
|
});
|
|
31
|
+
/** #slotEditor multi-line textarea */
|
|
25
32
|
const TextEditor = observer(function TextEditor({ slot, }) {
|
|
26
33
|
return (_jsx(TextField, { label: slot.name, helperText: slot.description, multiline: true, value: slot.value, onChange: evt => {
|
|
27
34
|
slot.set(evt.target.value);
|
|
28
35
|
} }));
|
|
29
36
|
});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
} }));
|
|
42
|
-
});
|
|
43
|
-
const StringEnumEditor = observer(function StringEnumEditor({ slot, slotSchema, }) {
|
|
44
|
-
const p = getPropertyMembers(getSubType(slotSchema));
|
|
45
|
-
const choices = getUnionSubTypes(getUnionSubTypes(getSubType(p.properties.value))[1]).map(t => t.value);
|
|
46
|
-
return (_jsx(ConfigurationTextField, { value: slot.value, label: slot.name, select: true, helperText: slot.description, onChange: evt => {
|
|
47
|
-
slot.set(evt.target.value);
|
|
48
|
-
}, children: choices.map(str => (_jsx(MenuItem, { value: str, children: str }, str))) }));
|
|
37
|
+
// Sentinel for "leave the slot unset" in the maybe-enum dropdown. MUI needs a
|
|
38
|
+
// concrete option value, and '' can't collide with an enum member (an empty
|
|
39
|
+
// enumeration member would be unnameable in a menu anyway).
|
|
40
|
+
const UNSET_CHOICE = '';
|
|
41
|
+
/** #slotEditor dropdown of the `model`'s members */
|
|
42
|
+
const StringEnumEditor = observer(function StringEnumEditor({ slot, }) {
|
|
43
|
+
const nullable = slot.type === 'maybeStringEnum';
|
|
44
|
+
return (_jsxs(ConfigurationTextField, { value: slot.value ?? UNSET_CHOICE, label: slot.name, select: true, helperText: slot.description, onChange: evt => {
|
|
45
|
+
const { value } = evt.target;
|
|
46
|
+
slot.set(value === UNSET_CHOICE ? undefined : value);
|
|
47
|
+
}, children: [nullable ? (_jsx(MenuItem, { value: UNSET_CHOICE, children: _jsx("em", { children: "default" }) })) : null, (slot.choices ?? []).map(str => (_jsx(MenuItem, { value: str, children: str }, str)))] }));
|
|
49
48
|
});
|
|
49
|
+
/** #slotEditor URL, local file path (desktop) or file blob (browser) */
|
|
50
50
|
const FileSelectorWrapper = observer(function FileSelectorWrapper({ slot, }) {
|
|
51
51
|
return (_jsx(FileSelector, { location: slot.value, setLocation: location => {
|
|
52
52
|
slot.set(location);
|
|
53
|
-
}, name: slot.name, description: slot.description, rootModel:
|
|
53
|
+
}, name: slot.name, description: slot.description, rootModel: slot.pluginManager.rootModel }));
|
|
54
54
|
});
|
|
55
|
+
// dynamic dispatch from a runtime slot `type` string to a typed editor. The
|
|
56
|
+
// `any` is irreducible here: each editor declares a narrow `slot.value` type
|
|
57
|
+
// (number, boolean, FileLocation, string[], ...) but makeSlotFacade can only
|
|
58
|
+
// type value as `unknown`, so no single registry prop type satisfies them all.
|
|
59
|
+
// The editors stay fully typed internally; only this lookup is untyped.
|
|
55
60
|
const valueComponents = {
|
|
56
61
|
string: StringEditor,
|
|
62
|
+
maybeString: StringEditor,
|
|
63
|
+
featureField: StringEditor,
|
|
57
64
|
text: TextEditor,
|
|
58
65
|
fileLocation: FileSelectorWrapper,
|
|
66
|
+
maybeFileLocation: FileSelectorWrapper,
|
|
59
67
|
stringArray: StringArrayEditor,
|
|
68
|
+
expressionArray: ExpressionArrayEditor,
|
|
69
|
+
colorArray: ColorArrayEditor,
|
|
70
|
+
stringEnumArray: StringEnumArrayEditor,
|
|
60
71
|
stringArrayMap: StringArrayMapEditor,
|
|
61
72
|
numberMap: NumberMapEditor,
|
|
73
|
+
stringMap: StringMapEditor,
|
|
62
74
|
number: NumberEditor,
|
|
75
|
+
maybeNumber: NumberEditor,
|
|
63
76
|
integer: IntegerEditor,
|
|
64
77
|
color: ColorEditor,
|
|
78
|
+
maybeColor: ColorEditor,
|
|
65
79
|
stringEnum: StringEnumEditor,
|
|
80
|
+
maybeStringEnum: StringEnumEditor,
|
|
66
81
|
boolean: BooleanEditor,
|
|
82
|
+
maybeBoolean: BooleanEditor,
|
|
67
83
|
frozen: JsonEditor,
|
|
68
|
-
|
|
84
|
+
maybeFrozen: JsonEditor,
|
|
69
85
|
};
|
|
70
|
-
const SlotEditor = observer(function SlotEditor({ slot,
|
|
86
|
+
const SlotEditor = observer(function SlotEditor({ slot, }) {
|
|
71
87
|
const { classes } = useSlotEditorStyles();
|
|
72
88
|
const { type } = slot;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
89
|
+
// editor mode is UI-only state, derived once from whether the stored value is
|
|
90
|
+
// a jexl callback. Toggling rewrites the value; typing a "jexl:" prefix into a
|
|
91
|
+
// value field does not auto-swap the editor, since this state only changes on
|
|
92
|
+
// the explicit toggle. A featureField's `jexl:` expression is a field, typed
|
|
93
|
+
// in its own text field.
|
|
94
|
+
const callback = slot.contextVariable.length > 0;
|
|
95
|
+
const [callbackMode, setCallbackMode] = useState(() => callback && isCallbackValue(slot.value));
|
|
96
|
+
// bumped on reset to remount the value editor: the buffered editors (number,
|
|
97
|
+
// json, callback) seed internal state from slot.value only on mount, so an
|
|
98
|
+
// external set wouldn't otherwise show in the field
|
|
99
|
+
const [resetNonce, setResetNonce] = useState(0);
|
|
100
|
+
const TypedComponent = valueComponents[type];
|
|
101
|
+
if (!callbackMode && !TypedComponent) {
|
|
78
102
|
console.warn(`no slot editor defined for ${type}, editing as string`);
|
|
79
|
-
ValueComponent = StringEditor;
|
|
80
|
-
}
|
|
81
|
-
if (!(type in valueComponents)) {
|
|
82
|
-
console.warn(`SlotEditor needs to implement ${type}`);
|
|
83
103
|
}
|
|
84
|
-
|
|
104
|
+
const ValueComponent = callbackMode
|
|
105
|
+
? CallbackEditor
|
|
106
|
+
: (TypedComponent ?? StringEditor);
|
|
107
|
+
const { modified } = slot;
|
|
108
|
+
return (_jsxs(Paper, { className: classes.paper, children: [_jsx("div", { className: classes.paperContent, children: _jsx(ValueComponent, { slot: slot }, resetNonce) }), modified ? (_jsx("div", { className: classes.resetButton, children: _jsx(Tooltip, { title: "Reset to default", children: _jsx(IconButton, { "aria-label": "reset to default", onClick: () => {
|
|
109
|
+
slot.set(slot.defaultValue);
|
|
110
|
+
setCallbackMode(callback && isCallbackValue(slot.defaultValue));
|
|
111
|
+
setResetNonce(nonce => nonce + 1);
|
|
112
|
+
}, children: _jsx(RestartAltIcon, {}) }) }) })) : null, callback ? (_jsx("div", { className: classes.slotModeSwitch, children: _jsx(Tooltip, { title: callbackMode
|
|
113
|
+
? 'Editing as a callback (Jexl expression). Click to use a fixed value.'
|
|
114
|
+
: 'Editing as a fixed value. Click to use a callback (Jexl expression).', children: _jsx(IconButton, { color: callbackMode ? 'primary' : 'default', onClick: () => {
|
|
115
|
+
if (callbackMode) {
|
|
116
|
+
slot.set(toFixedValue(slot.value, type, slot.defaultValue, slot.pluginManager.jexl));
|
|
117
|
+
setCallbackMode(false);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
slot.set(toCallbackValue(slot.value));
|
|
121
|
+
setCallbackMode(true);
|
|
122
|
+
}
|
|
123
|
+
}, children: _jsx(CodeIcon, {}) }) }) })) : null] }));
|
|
85
124
|
});
|
|
86
125
|
export default SlotEditor;
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
interface ArraySlot {
|
|
2
|
+
name: string;
|
|
3
|
+
value: string[];
|
|
4
|
+
set: (arg: string[]) => void;
|
|
5
|
+
description: string;
|
|
6
|
+
}
|
|
7
|
+
/** #slotEditor "todolist" of text fields, one per entry, with add and delete */
|
|
8
|
+
declare const StringArrayEditor: ({ slot, prefix, }: {
|
|
9
|
+
slot: ArraySlot;
|
|
10
|
+
prefix?: string;
|
|
11
|
+
}) => import("react").JSX.Element;
|
|
12
|
+
/** #slotEditor "todolist" of text fields, each after a fixed `jexl:` */
|
|
13
|
+
declare const ExpressionArrayEditor: ({ slot, }: {
|
|
14
|
+
slot: ArraySlot;
|
|
15
|
+
}) => import("react").JSX.Element;
|
|
16
|
+
export { ExpressionArrayEditor };
|
|
11
17
|
export default StringArrayEditor;
|
|
@@ -1,34 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { JEXL_PREFIX } from '@jbrowse/core/util/jexlStrings';
|
|
3
3
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
4
|
-
import {
|
|
4
|
+
import { FormHelperText, IconButton, InputAdornment, InputLabel, List, ListItem, TextField, } from '@mui/material';
|
|
5
5
|
import { observer } from 'mobx-react';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
import AddNewField from './AddNewField.js';
|
|
7
|
+
/** #slotEditor "todolist" of text fields, one per entry, with add and delete */
|
|
8
|
+
const StringArrayEditor = observer(function StringArrayEditor({ slot, prefix = '', }) {
|
|
9
|
+
const value = [...slot.value];
|
|
10
|
+
const startAdornment = prefix ? (_jsx(InputAdornment, { position: "start", children: prefix })) : undefined;
|
|
11
|
+
return (_jsxs(_Fragment, { children: [slot.name ? _jsx(InputLabel, { children: slot.name }) : null, _jsxs(List, { disablePadding: true, children: [value.map((val, idx) => (_jsx(ListItem, { disableGutters: true, children: _jsx(TextField, { fullWidth: true, value: val.slice(prefix.length), onChange: evt => {
|
|
12
|
+
slot.set(value.map((v, i) => i === idx ? prefix + evt.target.value : v));
|
|
11
13
|
}, slotProps: {
|
|
12
14
|
input: {
|
|
15
|
+
startAdornment,
|
|
13
16
|
endAdornment: (_jsx(InputAdornment, { position: "end", children: _jsx(IconButton, { onClick: () => {
|
|
14
|
-
slot.
|
|
17
|
+
slot.set(value.filter((_, i) => i !== idx));
|
|
15
18
|
}, children: _jsx(DeleteIcon, {}) }) })),
|
|
16
19
|
},
|
|
17
|
-
} }) },
|
|
18
|
-
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
setAddNew(false);
|
|
27
|
-
setValue('');
|
|
28
|
-
}, children: "Cancel" })] }) })),
|
|
29
|
-
},
|
|
30
|
-
} }) })) : null, _jsx(Button, { color: "primary", variant: "contained", style: { margin: 4 }, disabled: addNew, onClick: () => {
|
|
31
|
-
setAddNew(true);
|
|
32
|
-
}, children: "Add item" })] }), _jsx(FormHelperText, { children: slot.description })] }));
|
|
20
|
+
} }) }, idx))), _jsx(ListItem, { disableGutters: true, children: _jsx(AddNewField, { testid: `stringArrayAdd-${slot.name}`, startAdornment: startAdornment, onAdd: val => {
|
|
21
|
+
slot.set([...value, prefix + val]);
|
|
22
|
+
} }) })] }), _jsx(FormHelperText, { children: slot.description })] }));
|
|
23
|
+
});
|
|
24
|
+
// `jexl:` sits fixed in front of each entry, so no keystroke writes one the
|
|
25
|
+
// slot refuses
|
|
26
|
+
/** #slotEditor "todolist" of text fields, each after a fixed `jexl:` */
|
|
27
|
+
const ExpressionArrayEditor = observer(function ExpressionArrayEditor({ slot, }) {
|
|
28
|
+
return _jsx(StringArrayEditor, { slot: slot, prefix: JEXL_PREFIX });
|
|
33
29
|
});
|
|
30
|
+
export { ExpressionArrayEditor };
|
|
34
31
|
export default StringArrayEditor;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
+
/** #slotEditor one card per key, each holding that key's "todolist" of strings */
|
|
1
2
|
declare const StringArrayMapEditor: ({ slot, }: {
|
|
2
3
|
slot: {
|
|
3
4
|
name: string;
|
|
4
5
|
value: Map<string, string[]>;
|
|
5
|
-
|
|
6
|
-
add: (key: string, val: string[]) => void;
|
|
6
|
+
set: (val: Record<string, string[]>) => void;
|
|
7
7
|
description: string;
|
|
8
|
-
setAtKeyIndex: (key: string, idx: number, val: string) => void;
|
|
9
|
-
removeAtKeyIndex: (key: string, idx: number) => void;
|
|
10
|
-
addToKey: (key: string, val: string) => void;
|
|
11
8
|
};
|
|
12
|
-
}) => import("react
|
|
9
|
+
}) => import("react").JSX.Element;
|
|
13
10
|
export default StringArrayMapEditor;
|