react-cheminfo 0.70.0 → 0.71.0
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/README.md +57 -2
- package/lib/about/core/providers.d.ts +6 -0
- package/lib/about/core/providers.d.ts.map +1 -1
- package/lib/about/core/providers.js +7 -0
- package/lib/about/core/providers.js.map +1 -1
- package/lib/about/ui/AboutProvidedBy.js +34 -0
- package/lib/about/ui/AboutProvidedBy.js.map +1 -1
- package/lib/download/core/figurePng.d.ts +14 -0
- package/lib/download/core/figurePng.d.ts.map +1 -1
- package/lib/download/core/figurePng.js +21 -6
- package/lib/download/core/figurePng.js.map +1 -1
- package/lib/download/core/svgToPng.d.ts.map +1 -1
- package/lib/download/core/svgToPng.js +4 -2
- package/lib/download/core/svgToPng.js.map +1 -1
- package/lib/format/core/relativeTime.d.ts +8 -3
- package/lib/format/core/relativeTime.d.ts.map +1 -1
- package/lib/format/core/relativeTime.js +19 -7
- package/lib/format/core/relativeTime.js.map +1 -1
- package/lib/host/core/connectHost.d.ts +25 -34
- package/lib/host/core/connectHost.d.ts.map +1 -1
- package/lib/host/core/connectHost.js +43 -89
- package/lib/host/core/connectHost.js.map +1 -1
- package/lib/host/core/hostOutputs.d.ts +58 -0
- package/lib/host/core/hostOutputs.d.ts.map +1 -0
- package/lib/host/core/hostOutputs.js +151 -0
- package/lib/host/core/hostOutputs.js.map +1 -0
- package/lib/host/core/index.d.ts +9 -3
- package/lib/host/core/index.d.ts.map +1 -1
- package/lib/host/core/index.js +4 -1
- package/lib/host/core/index.js.map +1 -1
- package/lib/host/core/irKinds.d.ts +124 -0
- package/lib/host/core/irKinds.d.ts.map +1 -0
- package/lib/host/core/irKinds.js +46 -0
- package/lib/host/core/irKinds.js.map +1 -0
- package/lib/host/core/kinds.d.ts +13 -5
- package/lib/host/core/kinds.d.ts.map +1 -1
- package/lib/host/core/kinds.js +11 -5
- package/lib/host/core/kinds.js.map +1 -1
- package/lib/host/core/protocol.d.ts +50 -7
- package/lib/host/core/protocol.d.ts.map +1 -1
- package/lib/host/core/protocol.js +10 -6
- package/lib/host/core/protocol.js.map +1 -1
- package/lib/host/core/selectInputs.d.ts +37 -0
- package/lib/host/core/selectInputs.d.ts.map +1 -0
- package/lib/host/core/selectInputs.js +110 -0
- package/lib/host/core/selectInputs.js.map +1 -0
- package/lib/host/testing/sciPeaks.d.ts +31 -0
- package/lib/host/testing/sciPeaks.d.ts.map +1 -1
- package/lib/host/testing/sciPeaks.js +73 -0
- package/lib/host/testing/sciPeaks.js.map +1 -1
- package/lib/host/testing/standInHost.d.ts +9 -1
- package/lib/host/testing/standInHost.d.ts.map +1 -1
- package/lib/host/testing/standInHost.js +19 -1
- package/lib/host/testing/standInHost.js.map +1 -1
- package/lib/host/ui/useHostConnection.d.ts +13 -5
- package/lib/host/ui/useHostConnection.d.ts.map +1 -1
- package/lib/host/ui/useHostConnection.js +4 -3
- package/lib/host/ui/useHostConnection.js.map +1 -1
- package/lib/host-testing.d.ts +2 -2
- package/lib/host-testing.d.ts.map +1 -1
- package/lib/host-testing.js +2 -2
- package/lib/host-testing.js.map +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
- package/lib/ir/core/handPicking.d.ts +58 -0
- package/lib/ir/core/handPicking.d.ts.map +1 -0
- package/lib/ir/core/handPicking.js +130 -0
- package/lib/ir/core/handPicking.js.map +1 -0
- package/lib/ir/core/index.d.ts +3 -0
- package/lib/ir/core/index.d.ts.map +1 -1
- package/lib/ir/core/index.js +3 -0
- package/lib/ir/core/index.js.map +1 -1
- package/lib/ir/core/irBandState.d.ts +57 -0
- package/lib/ir/core/irBandState.d.ts.map +1 -0
- package/lib/ir/core/irBandState.js +119 -0
- package/lib/ir/core/irBandState.js.map +1 -0
- package/lib/ir/core/irCommands.d.ts +11 -0
- package/lib/ir/core/irCommands.d.ts.map +1 -1
- package/lib/ir/core/irCommands.js +6 -0
- package/lib/ir/core/irCommands.js.map +1 -1
- package/lib/ir/core/irPeaks.d.ts +28 -0
- package/lib/ir/core/irPeaks.d.ts.map +1 -0
- package/lib/ir/core/irPeaks.js +66 -0
- package/lib/ir/core/irPeaks.js.map +1 -0
- package/lib/ir/core/irReducer.d.ts +8 -0
- package/lib/ir/core/irReducer.d.ts.map +1 -1
- package/lib/ir/core/irReducer.js +15 -32
- package/lib/ir/core/irReducer.js.map +1 -1
- package/lib/ir/core/irSpectrum.d.ts +15 -0
- package/lib/ir/core/irSpectrum.d.ts.map +1 -1
- package/lib/ir/core/irSpectrum.js.map +1 -1
- package/lib/ir/core/irState.d.ts +9 -6
- package/lib/ir/core/irState.d.ts.map +1 -1
- package/lib/ir/core/irState.js +10 -6
- package/lib/ir/core/irState.js.map +1 -1
- package/lib/ir/core/pickBands.d.ts +14 -0
- package/lib/ir/core/pickBands.d.ts.map +1 -1
- package/lib/ir/core/pickBands.js +39 -33
- package/lib/ir/core/pickBands.js.map +1 -1
- package/lib/ir/core/ramanBands.d.ts +9 -1
- package/lib/ir/core/ramanBands.d.ts.map +1 -1
- package/lib/ir/core/ramanBands.js +2 -2
- package/lib/ir/core/ramanBands.js.map +1 -1
- package/lib/ir/core/spectrumBands.d.ts +46 -0
- package/lib/ir/core/spectrumBands.d.ts.map +1 -0
- package/lib/ir/core/spectrumBands.js +98 -0
- package/lib/ir/core/spectrumBands.js.map +1 -0
- package/lib/ir/ui/BandRow.d.ts +5 -0
- package/lib/ir/ui/BandRow.d.ts.map +1 -1
- package/lib/ir/ui/BandRow.js +4 -3
- package/lib/ir/ui/BandRow.js.map +1 -1
- package/lib/ir/ui/BandsPanel.d.ts +5 -0
- package/lib/ir/ui/BandsPanel.d.ts.map +1 -1
- package/lib/ir/ui/BandsPanel.js +36 -16
- package/lib/ir/ui/BandsPanel.js.map +1 -1
- package/lib/ir/ui/BandsToolbar.d.ts +9 -0
- package/lib/ir/ui/BandsToolbar.d.ts.map +1 -0
- package/lib/ir/ui/BandsToolbar.js +61 -0
- package/lib/ir/ui/BandsToolbar.js.map +1 -0
- package/lib/ir/ui/IrCanvas.d.ts +2 -1
- package/lib/ir/ui/IrCanvas.d.ts.map +1 -1
- package/lib/ir/ui/IrCanvas.js +19 -5
- package/lib/ir/ui/IrCanvas.js.map +1 -1
- package/lib/ir/ui/IrChart.d.ts.map +1 -1
- package/lib/ir/ui/IrChart.js +8 -1
- package/lib/ir/ui/IrChart.js.map +1 -1
- package/lib/ir/ui/IrDocumentationDialog.js +1 -1
- package/lib/ir/ui/IrDocumentationDialog.js.map +1 -1
- package/lib/ir/ui/IrEditor.d.ts +4 -2
- package/lib/ir/ui/IrEditor.d.ts.map +1 -1
- package/lib/ir/ui/IrEditor.js.map +1 -1
- package/lib/ir/ui/IrShell.d.ts.map +1 -1
- package/lib/ir/ui/IrShell.js +6 -0
- package/lib/ir/ui/IrShell.js.map +1 -1
- package/lib/ir/ui/IrStatusBar.d.ts.map +1 -1
- package/lib/ir/ui/IrStatusBar.js +1 -1
- package/lib/ir/ui/IrStatusBar.js.map +1 -1
- package/lib/ir/ui/IrToolbar.d.ts +4 -3
- package/lib/ir/ui/IrToolbar.d.ts.map +1 -1
- package/lib/ir/ui/IrToolbar.js +5 -4
- package/lib/ir/ui/IrToolbar.js.map +1 -1
- package/lib/ir/ui/VibrationalEditor.d.ts +2 -1
- package/lib/ir/ui/VibrationalEditor.d.ts.map +1 -1
- package/lib/ir/ui/VibrationalEditor.js.map +1 -1
- package/lib/ir/ui/irActions.d.ts +5 -0
- package/lib/ir/ui/irActions.d.ts.map +1 -1
- package/lib/ir/ui/irActions.js +6 -0
- package/lib/ir/ui/irActions.js.map +1 -1
- package/lib/ir/ui/irChartProps.d.ts +4 -1
- package/lib/ir/ui/irChartProps.d.ts.map +1 -1
- package/lib/ir/ui/useIrEditor.d.ts +5 -11
- package/lib/ir/ui/useIrEditor.d.ts.map +1 -1
- package/lib/ir/ui/useIrEditor.js +17 -18
- package/lib/ir/ui/useIrEditor.js.map +1 -1
- package/lib/locales/de.json +63 -0
- package/lib/locales/en.json +63 -0
- package/lib/locales/es.json +63 -0
- package/lib/locales/fr.json +63 -0
- package/lib/locales/it.json +63 -0
- package/lib/slides/ui/slideSanitizeSchema.d.ts +3 -2
- package/lib/slides/ui/slideSanitizeSchema.d.ts.map +1 -1
- package/lib/slides/ui/slideSanitizeSchema.js +82 -2
- package/lib/slides/ui/slideSanitizeSchema.js.map +1 -1
- package/package.json +1 -1
- package/src/about/core/providers.ts +7 -0
- package/src/about/ui/AboutProvidedBy.tsx +49 -0
- package/src/download/core/figurePng.ts +21 -8
- package/src/download/core/svgToPng.ts +3 -4
- package/src/format/core/relativeTime.ts +29 -7
- package/src/host/core/connectHost.ts +77 -120
- package/src/host/core/hostOutputs.ts +197 -0
- package/src/host/core/index.ts +13 -7
- package/src/host/core/irKinds.ts +92 -0
- package/src/host/core/kinds.ts +16 -6
- package/src/host/core/protocol.ts +50 -8
- package/src/host/core/selectInputs.ts +145 -0
- package/src/host/testing/sciPeaks.ts +140 -0
- package/src/host/testing/standInHost.ts +30 -5
- package/src/host/ui/useHostConnection.ts +17 -8
- package/src/host-testing.ts +4 -0
- package/src/ir/core/handPicking.ts +154 -0
- package/src/ir/core/index.ts +14 -0
- package/src/ir/core/irBandState.ts +155 -0
- package/src/ir/core/irCommands.ts +7 -0
- package/src/ir/core/irPeaks.ts +79 -0
- package/src/ir/core/irReducer.ts +27 -34
- package/src/ir/core/irSpectrum.ts +16 -0
- package/src/ir/core/irState.ts +15 -8
- package/src/ir/core/pickBands.ts +46 -39
- package/src/ir/core/ramanBands.ts +2 -2
- package/src/ir/core/spectrumBands.ts +113 -0
- package/src/ir/ui/BandRow.tsx +20 -2
- package/src/ir/ui/BandsPanel.tsx +46 -88
- package/src/ir/ui/BandsToolbar.tsx +152 -0
- package/src/ir/ui/IrCanvas.tsx +22 -11
- package/src/ir/ui/IrChart.tsx +10 -1
- package/src/ir/ui/IrDocumentationDialog.tsx +7 -0
- package/src/ir/ui/IrEditor.tsx +4 -2
- package/src/ir/ui/IrShell.tsx +5 -0
- package/src/ir/ui/IrStatusBar.tsx +4 -1
- package/src/ir/ui/IrToolbar.tsx +14 -5
- package/src/ir/ui/VibrationalEditor.tsx +2 -1
- package/src/ir/ui/irActions.ts +11 -0
- package/src/ir/ui/irChartProps.ts +4 -1
- package/src/ir/ui/useIrEditor.ts +21 -21
- package/src/locales/de.json +63 -0
- package/src/locales/en.json +63 -0
- package/src/locales/es.json +63 -0
- package/src/locales/fr.json +63 -0
- package/src/locales/it.json +63 -0
- package/src/slides/ui/slideSanitizeSchema.ts +86 -2
- package/styles/chrome.css +7 -0
- package/styles/slides.css +47 -0
package/src/ir/ui/IrCanvas.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback, useMemo } from 'react';
|
|
2
2
|
|
|
3
|
+
import { editBandsAt } from '../core/handPicking.ts';
|
|
3
4
|
import type { IrBand } from '../core/irBand.ts';
|
|
4
5
|
import type { IrPlotClick } from '../core/irEditorApi.ts';
|
|
5
6
|
import type { IrDomain } from '../core/irSpectrum.ts';
|
|
@@ -35,7 +36,8 @@ export interface IrCanvasProps {
|
|
|
35
36
|
chartId?: string;
|
|
36
37
|
/**
|
|
37
38
|
* Told of a click on the plot — a press let go without travelling, never the
|
|
38
|
-
* end of a drag — with the spectrum selected at that moment.
|
|
39
|
+
* end of a drag — with the spectrum selected at that moment. Not told while
|
|
40
|
+
* bands are picked by hand, which is what a click is then.
|
|
39
41
|
* @default undefined
|
|
40
42
|
*/
|
|
41
43
|
onPlotClick?: (click: IrPlotClick) => void;
|
|
@@ -64,7 +66,8 @@ export function IrCanvas(props: IrCanvasProps) {
|
|
|
64
66
|
chartId,
|
|
65
67
|
onPlotClick,
|
|
66
68
|
} = props;
|
|
67
|
-
const { state, visibleSpectra, assigned } =
|
|
69
|
+
const { state, visibleSpectra, selectedSpectrum, assigned } =
|
|
70
|
+
useIrEditorState();
|
|
68
71
|
const actions = useIrActions();
|
|
69
72
|
const { domain, tool, selectedId } = state.view;
|
|
70
73
|
const { technique, mode, showAssignments, labelLimit } = state.settings;
|
|
@@ -77,15 +80,23 @@ export function IrCanvas(props: IrCanvasProps) {
|
|
|
77
80
|
);
|
|
78
81
|
|
|
79
82
|
// Which spectrum was selected is the viewer's to say, not the chart's: the
|
|
80
|
-
// chart only knows where the press landed.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
// chart only knows where the press landed. While picking by hand a click is
|
|
84
|
+
// a band, and is the viewer's own rather than the host's.
|
|
85
|
+
const onClickAt = useMemo(() => {
|
|
86
|
+
if (tool === 'pick') {
|
|
87
|
+
if (selectedSpectrum === null) return undefined;
|
|
88
|
+
return (wavenumber: number, reach: number) => {
|
|
89
|
+
const bands = editBandsAt(selectedSpectrum, wavenumber, reach);
|
|
90
|
+
if (bands !== selectedSpectrum.bands) {
|
|
91
|
+
actions.setBands(selectedSpectrum.id, bands);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return onPlotClick === undefined
|
|
96
|
+
? undefined
|
|
97
|
+
: (wavenumber: number) =>
|
|
98
|
+
onPlotClick({ wavenumber, spectrumId: selectedId });
|
|
99
|
+
}, [tool, selectedSpectrum, actions, onPlotClick, selectedId]);
|
|
89
100
|
|
|
90
101
|
return (
|
|
91
102
|
<div style={rootStyle}>
|
package/src/ir/ui/IrChart.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import { useChartSize } from '../../chart/ui/useChartSize.ts';
|
|
|
11
11
|
import type { AssignedBand } from '../core/assignBands.ts';
|
|
12
12
|
import type { IrBand } from '../core/irBand.ts';
|
|
13
13
|
import { irModeFor } from '../core/irTechnique.ts';
|
|
14
|
+
import { BAND_HIT_RADIUS } from '../core/nearestBand.ts';
|
|
14
15
|
|
|
15
16
|
import { BandMarks } from './BandMarks.tsx';
|
|
16
17
|
import { IrPointerTracker } from './IrPointerTracker.tsx';
|
|
@@ -83,11 +84,15 @@ export function IrChart(props: IrChartProps): ReactElement {
|
|
|
83
84
|
const frameWidth = plot.right + MARGIN.right;
|
|
84
85
|
const frameHeight = plot.bottom + MARGIN.bottom;
|
|
85
86
|
|
|
87
|
+
// The scale a click is measured against comes out of the zoom the click is
|
|
88
|
+
// handed to, so the handler reads the latest one when the click happens.
|
|
89
|
+
const xFactor = useRef(0);
|
|
86
90
|
const onClick = useMemo(
|
|
87
91
|
() =>
|
|
88
92
|
onPlotClick === undefined
|
|
89
93
|
? undefined
|
|
90
|
-
: (point: ChartPoint) =>
|
|
94
|
+
: (point: ChartPoint) =>
|
|
95
|
+
onPlotClick(point.x, BAND_HIT_RADIUS / Math.abs(xFactor.current)),
|
|
91
96
|
[onPlotClick],
|
|
92
97
|
);
|
|
93
98
|
|
|
@@ -111,6 +116,10 @@ export function IrChart(props: IrChartProps): ReactElement {
|
|
|
111
116
|
// was dragged over.
|
|
112
117
|
const { domain: shown, xScale, yScale, selection, handlers } = zoom;
|
|
113
118
|
|
|
119
|
+
useLayoutEffect(() => {
|
|
120
|
+
xFactor.current = xScale.factor;
|
|
121
|
+
}, [xScale]);
|
|
122
|
+
|
|
114
123
|
const reported = useRef(shown);
|
|
115
124
|
// Before the browser paints, so a host that stores the window and hands it
|
|
116
125
|
// back does so in the frame the gesture landed in rather than the one after.
|
|
@@ -111,6 +111,13 @@ function InfraredGuide() {
|
|
|
111
111
|
a row marks the band on the chart, and hovering the chart lights the
|
|
112
112
|
row.
|
|
113
113
|
</p>
|
|
114
|
+
<p style={paragraphStyle}>
|
|
115
|
+
The bands are found automatically until you pick them by hand: with the
|
|
116
|
+
hand tool a click on the chart adds the band under it, at its top, and a
|
|
117
|
+
click on a mark takes it away, as does the cross at the end of its row.
|
|
118
|
+
From then on the threshold leaves the list alone, until it is found
|
|
119
|
+
automatically again.
|
|
120
|
+
</p>
|
|
114
121
|
<p style={paragraphStyle}>
|
|
115
122
|
A band is reported at the sampled point it peaked on, so on a 4 cm⁻¹
|
|
116
123
|
grid a carbonyl centred at 1710 reads 1708 or 1712. Do not quote one as
|
package/src/ir/ui/IrEditor.tsx
CHANGED
|
@@ -18,7 +18,8 @@ export interface IrEditorProps {
|
|
|
18
18
|
data?: IrSpectrum[];
|
|
19
19
|
/**
|
|
20
20
|
* Called whenever the spectra open change — one loaded, one closed, the chart
|
|
21
|
-
* cleared — with the spectra now open
|
|
21
|
+
* cleared, the bands of one picked — with the spectra now open, each carrying
|
|
22
|
+
* its bands.
|
|
22
23
|
*
|
|
23
24
|
* The document only. A zoom, a selection, a rename and a colour change what is
|
|
24
25
|
* being looked at rather than what is loaded, and a host told about those would
|
|
@@ -50,7 +51,8 @@ export interface IrEditorProps {
|
|
|
50
51
|
panels?: readonly IrHostPanel[];
|
|
51
52
|
/**
|
|
52
53
|
* The plot was clicked at this wavenumber (a press that did not travel, i.e.
|
|
53
|
-
* not a zoom drag), with the spectrum selected at that moment.
|
|
54
|
+
* not a zoom drag), with the spectrum selected at that moment. Not called
|
|
55
|
+
* while bands are picked by hand: a click is a band then.
|
|
54
56
|
* @default undefined
|
|
55
57
|
*/
|
|
56
58
|
onPlotClick?: (click: IrPlotClick) => void;
|
package/src/ir/ui/IrShell.tsx
CHANGED
|
@@ -92,6 +92,11 @@ export function IrShell(props: IrShellProps) {
|
|
|
92
92
|
fullScreen: toggleFullScreen,
|
|
93
93
|
readTool: () => actions.setTool('read'),
|
|
94
94
|
boxTool: () => actions.setTool(tool === 'box' ? 'read' : 'box'),
|
|
95
|
+
// Picking by hand is done on the marks, so they are shown for it.
|
|
96
|
+
pickTool: () => {
|
|
97
|
+
actions.setTool(tool === 'pick' ? 'read' : 'pick');
|
|
98
|
+
if (!pickBands) actions.setSettings({ pickBands: true });
|
|
99
|
+
},
|
|
95
100
|
zoomIn,
|
|
96
101
|
zoomOut,
|
|
97
102
|
resetZoom: () => actions.resetDomain(),
|
|
@@ -63,11 +63,14 @@ export function IrStatusBar() {
|
|
|
63
63
|
{pickBands && assigned.length > 0 ? (
|
|
64
64
|
<span style={itemStyle}>
|
|
65
65
|
{countLabel(assigned.length, 'band', 'bands')}
|
|
66
|
+
{selectedSpectrum?.bandsByHand ? ' picked by hand' : null}
|
|
66
67
|
{assignments ? `, ${countAssigned(assigned)} assigned` : null}
|
|
67
68
|
</span>
|
|
68
69
|
) : null}
|
|
69
70
|
|
|
70
|
-
{
|
|
71
|
+
{tool === 'pick' ? (
|
|
72
|
+
<span style={mutedStyle}>click to add or remove a band</span>
|
|
73
|
+
) : boxZoomOnly(mode) || tool === 'box' ? (
|
|
71
74
|
<span style={mutedStyle}>square zoom: drag a rectangle</span>
|
|
72
75
|
) : null}
|
|
73
76
|
|
package/src/ir/ui/IrToolbar.tsx
CHANGED
|
@@ -22,9 +22,10 @@ export interface IrToolbarProps {
|
|
|
22
22
|
* The tools, down the left of the chart.
|
|
23
23
|
*
|
|
24
24
|
* Only what is done to the spectra: what is asked of the viewer itself — the
|
|
25
|
-
* mark, help, full screen — is in the header. The
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* mark, help, full screen — is in the header. The **tools** — read and square
|
|
26
|
+
* zoom, which say what a drag is running, and picking by hand, which says what
|
|
27
|
+
* a click is — come first, then the zoom commands that act at once, then what
|
|
28
|
+
* is being read: the
|
|
28
29
|
* value axis, the picking, the assignments. Closing every spectrum is last and
|
|
29
30
|
* alone, being the only one that throws something away.
|
|
30
31
|
*
|
|
@@ -64,10 +65,12 @@ export function IrToolbar(props: IrToolbarProps) {
|
|
|
64
65
|
disabled={isEmpty}
|
|
65
66
|
/>
|
|
66
67
|
{/* The read tool drags along one axis, so it is drawn as that; the box
|
|
67
|
-
tool sweeps a rectangle, which is what a marquee icon means.
|
|
68
|
+
tool sweeps a rectangle, which is what a marquee icon means. Picking
|
|
69
|
+
by hand is about a click, and a drag still reads while it is chosen,
|
|
70
|
+
so the two light together. */}
|
|
68
71
|
<Toolbar.Item
|
|
69
72
|
icon="arrows-horizontal"
|
|
70
|
-
active={!settled && tool
|
|
73
|
+
active={!settled && tool !== 'box'}
|
|
71
74
|
{...command('readTool')}
|
|
72
75
|
disabled={isEmpty || settled}
|
|
73
76
|
/>
|
|
@@ -77,6 +80,12 @@ export function IrToolbar(props: IrToolbarProps) {
|
|
|
77
80
|
{...command('boxTool')}
|
|
78
81
|
disabled={isEmpty || settled}
|
|
79
82
|
/>
|
|
83
|
+
<Toolbar.Item
|
|
84
|
+
icon="add-location"
|
|
85
|
+
active={tool === 'pick'}
|
|
86
|
+
{...command('pickTool')}
|
|
87
|
+
disabled={selectedSpectrum === null}
|
|
88
|
+
/>
|
|
80
89
|
|
|
81
90
|
<Toolbar.Item icon="zoom-in" {...command('zoomIn')} disabled={isEmpty} />
|
|
82
91
|
<Toolbar.Item
|
|
@@ -48,7 +48,8 @@ export interface VibrationalEditorProps {
|
|
|
48
48
|
panels?: readonly IrHostPanel[];
|
|
49
49
|
/**
|
|
50
50
|
* The plot was clicked at this wavenumber (a press that did not travel, i.e.
|
|
51
|
-
* not a zoom drag), with the spectrum selected at that moment.
|
|
51
|
+
* not a zoom drag), with the spectrum selected at that moment. Not called
|
|
52
|
+
* while bands are picked by hand.
|
|
52
53
|
* @default undefined
|
|
53
54
|
*/
|
|
54
55
|
onPlotClick?: (click: IrPlotClick) => void;
|
package/src/ir/ui/irActions.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Dispatch } from 'react';
|
|
10
10
|
|
|
11
|
+
import type { IrBand } from '../core/irBand.ts';
|
|
11
12
|
import type { IrAction } from '../core/irReducer.ts';
|
|
12
13
|
import type { IrPanelId } from '../core/irSidePanels.ts';
|
|
13
14
|
import type { IrDomain, IrSpectrum } from '../core/irSpectrum.ts';
|
|
@@ -27,6 +28,10 @@ export interface IrEditorActions {
|
|
|
27
28
|
setSpectrumColor: (id: string, color: string) => void;
|
|
28
29
|
/** Draw one, or stop drawing it. */
|
|
29
30
|
setSpectrumVisible: (id: string, visible: boolean) => void;
|
|
31
|
+
/** Give one these bands, as picked by hand. */
|
|
32
|
+
setBands: (id: string, bands: IrBand[]) => void;
|
|
33
|
+
/** Have one's bands found automatically again, with the settings in force. */
|
|
34
|
+
resetBands: (id: string) => void;
|
|
30
35
|
/** Point the panels at one, or at none. */
|
|
31
36
|
selectSpectrum: (id: string | null) => void;
|
|
32
37
|
/** Show this window. */
|
|
@@ -72,6 +77,12 @@ export function createIrActions(dispatch: Dispatch<IrAction>): IrEditorActions {
|
|
|
72
77
|
setSpectrumVisible(id, visible) {
|
|
73
78
|
dispatch({ type: 'setSpectrumVisible', id, visible });
|
|
74
79
|
},
|
|
80
|
+
setBands(id, bands) {
|
|
81
|
+
dispatch({ type: 'setBands', id, bands });
|
|
82
|
+
},
|
|
83
|
+
resetBands(id) {
|
|
84
|
+
dispatch({ type: 'resetBands', id });
|
|
85
|
+
},
|
|
75
86
|
selectSpectrum(id) {
|
|
76
87
|
dispatch({ type: 'selectSpectrum', id });
|
|
77
88
|
},
|
|
@@ -98,9 +98,12 @@ export interface IrChartProps {
|
|
|
98
98
|
* Told the wavenumber a click on the plot landed at: a press let go over the
|
|
99
99
|
* plot without travelling. The end of a drag is never one, nor is a press let
|
|
100
100
|
* go over the axis labels, which inverts to a value the chart is not drawing.
|
|
101
|
+
*
|
|
102
|
+
* `reach` is how many cm⁻¹ a band's hit radius spans at the zoom the chart is
|
|
103
|
+
* at, so a band the click was aimed at can be told from one it was not.
|
|
101
104
|
* @default undefined
|
|
102
105
|
*/
|
|
103
|
-
onPlotClick?: (wavenumber: number) => void;
|
|
106
|
+
onPlotClick?: (wavenumber: number, reach: number) => void;
|
|
104
107
|
/**
|
|
105
108
|
* What a drag across the plot asks for: the wavenumber axis alone, or exactly
|
|
106
109
|
* the rectangle it sweeps out. A viewer offering a square-zoom tool switches
|
package/src/ir/ui/useIrEditor.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* One viewer's state, and everything derived from it.
|
|
3
3
|
*
|
|
4
|
-
* The bands are
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* is the one drawn on the chart. Derived, a stale band cannot exist.
|
|
9
|
-
*
|
|
10
|
-
* It is memoised on the selected spectrum rather than on all of them: picking
|
|
11
|
-
* runs a peak detection over a few thousand points, and doing it for six loaded
|
|
12
|
-
* spectra when the panels only ever show one would cost six times what it needs
|
|
13
|
-
* to on every change of a threshold.
|
|
4
|
+
* The bands are the selected spectrum's own: the reducer picks them when it
|
|
5
|
+
* arrives and keeps them on it, so a band picked by hand is still there the
|
|
6
|
+
* next time it is selected, and goes to the host with it. What is derived here
|
|
7
|
+
* is what each band could be, which the correlation table answers per band.
|
|
14
8
|
*/
|
|
15
9
|
|
|
16
10
|
import { useEffect, useMemo, useReducer, useRef } from 'react';
|
|
@@ -19,12 +13,12 @@ import type { AssignedBand } from '../core/assignBands.ts';
|
|
|
19
13
|
import { assignBands } from '../core/assignBands.ts';
|
|
20
14
|
import type { BandAssignment } from '../core/bandAssignments.ts';
|
|
21
15
|
import { BAND_ASSIGNMENTS } from '../core/bandAssignments.ts';
|
|
16
|
+
import type { IrBand } from '../core/irBand.ts';
|
|
22
17
|
import { irReducer } from '../core/irReducer.ts';
|
|
23
18
|
import type { IrSpectrum } from '../core/irSpectrum.ts';
|
|
24
19
|
import type { CreateIrStateOptions, IrState } from '../core/irState.ts';
|
|
25
20
|
import { createIrState } from '../core/irState.ts';
|
|
26
21
|
import { IR_TECHNIQUE_RULES } from '../core/irTechnique.ts';
|
|
27
|
-
import { pickBands } from '../core/pickBands.ts';
|
|
28
22
|
|
|
29
23
|
import type { IrEditorActions } from './irActions.ts';
|
|
30
24
|
import { createIrActions } from './irActions.ts';
|
|
@@ -33,7 +27,7 @@ import { createIrActions } from './irActions.ts';
|
|
|
33
27
|
export interface UseIrEditorOptions extends CreateIrStateOptions {
|
|
34
28
|
/**
|
|
35
29
|
* Called whenever the spectra open change — one loaded, one closed, the chart
|
|
36
|
-
* cleared — with the spectra now open.
|
|
30
|
+
* cleared, the bands of one picked — with the spectra now open.
|
|
37
31
|
* @default undefined
|
|
38
32
|
*/
|
|
39
33
|
onChange?: (spectra: IrSpectrum[]) => void;
|
|
@@ -70,8 +64,7 @@ export function useIrEditor(options: UseIrEditorOptions = {}): IrEditorApi {
|
|
|
70
64
|
|
|
71
65
|
const { spectra } = state.data;
|
|
72
66
|
const { selectedId } = state.view;
|
|
73
|
-
const { pickBands: picking,
|
|
74
|
-
const { assignmentTolerance, technique } = state.settings;
|
|
67
|
+
const { pickBands: picking, assignmentTolerance, technique } = state.settings;
|
|
75
68
|
|
|
76
69
|
const visibleSpectra = useMemo(() => {
|
|
77
70
|
const visible: IrSpectrum[] = [];
|
|
@@ -92,9 +85,9 @@ export function useIrEditor(options: UseIrEditorOptions = {}): IrEditorApi {
|
|
|
92
85
|
const bands = useMemo(
|
|
93
86
|
() =>
|
|
94
87
|
selectedSpectrum === null || !picking
|
|
95
|
-
?
|
|
96
|
-
:
|
|
97
|
-
[selectedSpectrum, picking
|
|
88
|
+
? NO_BANDS
|
|
89
|
+
: (selectedSpectrum.bands ?? NO_BANDS),
|
|
90
|
+
[selectedSpectrum, picking],
|
|
98
91
|
);
|
|
99
92
|
|
|
100
93
|
// Assigning is a walk of thirty ranges per band, which is nothing beside the
|
|
@@ -130,8 +123,15 @@ export function useIrEditor(options: UseIrEditorOptions = {}): IrEditorApi {
|
|
|
130
123
|
/** The table a technique the correlation table does not cover is matched against. */
|
|
131
124
|
const NO_ASSIGNMENTS: readonly BandAssignment[] = [];
|
|
132
125
|
|
|
126
|
+
/** What is shown while nothing is selected or picking is off, kept stable. */
|
|
127
|
+
const NO_BANDS: readonly IrBand[] = [];
|
|
128
|
+
|
|
133
129
|
/**
|
|
134
|
-
* Whether two lists hold the same spectra,
|
|
130
|
+
* Whether two lists hold the same spectra, with the same bands, in order.
|
|
131
|
+
*
|
|
132
|
+
* By identity, and the bands by reference: a rename or a colour builds a new
|
|
133
|
+
* spectrum around the same list, so neither is reported, while a band picked
|
|
134
|
+
* builds a new list.
|
|
135
135
|
* @param current - What was reported last.
|
|
136
136
|
* @param next - What is open now.
|
|
137
137
|
* @returns Whether the report can be skipped.
|
|
@@ -143,9 +143,9 @@ function sameSpectra(
|
|
|
143
143
|
if (current === next) return true;
|
|
144
144
|
if (current.length !== next.length) return false;
|
|
145
145
|
for (let index = 0; index < current.length; index++) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
const before = current[index] as IrSpectrum;
|
|
147
|
+
const after = next[index] as IrSpectrum;
|
|
148
|
+
if (before.id !== after.id || before.bands !== after.bands) return false;
|
|
149
149
|
}
|
|
150
150
|
return true;
|
|
151
151
|
}
|
package/src/locales/de.json
CHANGED
|
@@ -8,6 +8,69 @@
|
|
|
8
8
|
"account.signIn": "Anmelden",
|
|
9
9
|
"account.signOut": "Abmelden",
|
|
10
10
|
"account.signedInAs": "Angemeldet als {name}",
|
|
11
|
+
"account.username": "Benutzername",
|
|
12
|
+
"account.password": "Passwort",
|
|
13
|
+
"account.role": "Rolle",
|
|
14
|
+
"account.role.read": "Lesen",
|
|
15
|
+
"account.role.write": "Lesen und Schreiben",
|
|
16
|
+
"account.role.admin": "Administrator",
|
|
17
|
+
"account.you": "Sie",
|
|
18
|
+
"account.envManaged": "in .env festgelegt",
|
|
19
|
+
"account.envManagedTitle": "ADMIN_USERNAME und ADMIN_PASSWORD in der .env des Servers legen dieses Konto fest, es wird dort geändert.",
|
|
20
|
+
"account.accounts": "Konten",
|
|
21
|
+
"account.accountsNote": "Lesen sieht die Daten, Lesen und Schreiben ändert sie auch, und Administrator verwaltet zudem diese Konten.",
|
|
22
|
+
"account.column.added": "Hinzugefügt",
|
|
23
|
+
"account.column.lastSignIn": "Letzte Anmeldung",
|
|
24
|
+
"account.column.passwordChanged": "Passwort geändert",
|
|
25
|
+
"account.column.actions": "Ändern",
|
|
26
|
+
"account.never": "nie",
|
|
27
|
+
"account.add": "Konto hinzufügen",
|
|
28
|
+
"account.addSubmit": "Das Konto hinzufügen",
|
|
29
|
+
"account.added": "{username} kann sich jetzt anmelden.",
|
|
30
|
+
"account.usernameHelp": "Buchstaben, Ziffern, Punkte, Bindestriche und Unterstriche.",
|
|
31
|
+
"account.setPassword": "Passwort setzen",
|
|
32
|
+
"account.setPasswordTitle": "Das Passwort von {username} setzen",
|
|
33
|
+
"account.setPasswordNote": "{username} wird überall abgemeldet und meldet sich ab jetzt mit diesem Passwort an.",
|
|
34
|
+
"account.setPasswordSubmit": "Das Passwort setzen",
|
|
35
|
+
"account.roleOf": "Rolle von {username}",
|
|
36
|
+
"account.changePassword": "Ihr Passwort ändern",
|
|
37
|
+
"account.currentPassword": "Aktuelles Passwort",
|
|
38
|
+
"account.newPassword": "Neues Passwort",
|
|
39
|
+
"account.repeatPassword": "Neues Passwort, noch einmal",
|
|
40
|
+
"account.passwordsDiffer": "Die beiden neuen Passwörter unterscheiden sich.",
|
|
41
|
+
"account.passwordChanged": "Ihr Passwort ist geändert. Andere Browser, die mit Ihrem Konto angemeldet waren, sind abgemeldet.",
|
|
42
|
+
"account.ownEnvManaged": "Die .env des Servers legt Ihr Konto fest: Ändern Sie ADMIN_PASSWORD dort und starten Sie den Server neu.",
|
|
43
|
+
"account.remove": "Entfernen",
|
|
44
|
+
"account.removeQuestion": "{username} entfernen? Das Konto kann sich dann nicht mehr anmelden.",
|
|
45
|
+
"account.needsWrite": "Diese Seite ändert die Daten, und {username} darf sie nur lesen.",
|
|
46
|
+
"account.needsAdmin": "Diese Seite ist für Administratoren, und {username} ist keiner.",
|
|
47
|
+
"account.switchAccount": "Mit einem anderen Konto anmelden",
|
|
48
|
+
"account.unreachable": "Der Server ist nicht erreichbar. Versuchen Sie es gleich noch einmal.",
|
|
49
|
+
"account.refusal.wrongCredentials": "Falscher Benutzername oder falsches Passwort.",
|
|
50
|
+
"account.refusal.tooManyAttempts": "Zu viele Anmeldeversuche von hier. Versuchen Sie es in 15 Minuten wieder.",
|
|
51
|
+
"account.refusal.signInElsewhere": "Die Anmeldung geschieht auf den Seiten dieser Website.",
|
|
52
|
+
"account.refusal.signOutElsewhere": "Die Abmeldung geschieht auf den Seiten dieser Website.",
|
|
53
|
+
"account.refusal.changeElsewhere": "Änderungen geschehen von den Seiten dieser Website aus.",
|
|
54
|
+
"account.refusal.signInRequired": "Dies ist für die Konten dieser Website: Melden Sie sich an.",
|
|
55
|
+
"account.refusal.sessionEnded": "Die Sitzung ist zu Ende: Melden Sie sich erneut an.",
|
|
56
|
+
"account.refusal.wrongToken": "Das ist nicht das ADMIN_TOKEN dieses Servers.",
|
|
57
|
+
"account.refusal.noAdminToken": "Auf diesem Server ist kein ADMIN_TOKEN gesetzt: Melden Sie sich stattdessen an.",
|
|
58
|
+
"account.refusal.roleTooLow": "Ihr Konto darf das nicht: Fragen Sie einen Administrator.",
|
|
59
|
+
"account.refusal.usernameLength": "Ein Benutzername hat {min} bis {max} Zeichen.",
|
|
60
|
+
"account.refusal.usernameCharacters": "Ein Benutzername enthält Buchstaben, Ziffern, Punkte, Bindestriche und Unterstriche und beginnt mit einem Buchstaben oder einer Ziffer.",
|
|
61
|
+
"account.refusal.usernameTaken": "Dieser Benutzername ist vergeben.",
|
|
62
|
+
"account.refusal.passwordEmpty": "Ein Passwort darf nicht leer sein.",
|
|
63
|
+
"account.refusal.passwordTooLong": "Ein Passwort hat höchstens {max} Zeichen.",
|
|
64
|
+
"account.refusal.noSuchAccount": "Dieses Konto gibt es nicht mehr.",
|
|
65
|
+
"account.refusal.nothingToChange": "Senden Sie ein neues Passwort, eine neue Rolle oder beides.",
|
|
66
|
+
"account.refusal.useChangePassword": "Ändern Sie Ihr eigenes Passwort mit POST /password, das nach dem aktuellen fragt.",
|
|
67
|
+
"account.refusal.ownRole": "Sie können Ihre eigene Rolle nicht ändern.",
|
|
68
|
+
"account.refusal.removeYourself": "Sie können das Konto, das Sie verwenden, nicht entfernen.",
|
|
69
|
+
"account.refusal.lastAdmin": "Der letzte Administrator kann weder entfernt noch herabgestuft werden.",
|
|
70
|
+
"account.refusal.envManaged": "Die .env des Servers legt dieses Konto fest, es wird dort geändert.",
|
|
71
|
+
"account.refusal.tokenCannotChangePassword": "Ein Passwort ändert das angemeldete Konto, nicht das ADMIN_TOKEN.",
|
|
72
|
+
"account.refusal.wrongCurrentPassword": "Das aktuelle Passwort ist nicht dieses.",
|
|
73
|
+
"account.refusal.accountRemoved": "Das angemeldete Konto wurde entfernt.",
|
|
11
74
|
"ecosystem.tools": "Werkzeuge",
|
|
12
75
|
"ecosystem.menuHeading": "Unsere Werkzeuge, alle im Browser",
|
|
13
76
|
"ecosystem.otherTools": "Unsere weiteren Werkzeuge",
|
package/src/locales/en.json
CHANGED
|
@@ -8,6 +8,69 @@
|
|
|
8
8
|
"account.signIn": "Sign in",
|
|
9
9
|
"account.signOut": "Sign out",
|
|
10
10
|
"account.signedInAs": "Signed in as {name}",
|
|
11
|
+
"account.username": "Username",
|
|
12
|
+
"account.password": "Password",
|
|
13
|
+
"account.role": "Role",
|
|
14
|
+
"account.role.read": "Read",
|
|
15
|
+
"account.role.write": "Read and write",
|
|
16
|
+
"account.role.admin": "Administrator",
|
|
17
|
+
"account.you": "you",
|
|
18
|
+
"account.envManaged": "defined in .env",
|
|
19
|
+
"account.envManagedTitle": "ADMIN_USERNAME and ADMIN_PASSWORD in the server's .env define this account, so it is changed there.",
|
|
20
|
+
"account.accounts": "Accounts",
|
|
21
|
+
"account.accountsNote": "Read sees the data, Read and write also changes it, and Administrator also manages these accounts.",
|
|
22
|
+
"account.column.added": "Added",
|
|
23
|
+
"account.column.lastSignIn": "Last sign-in",
|
|
24
|
+
"account.column.passwordChanged": "Password changed",
|
|
25
|
+
"account.column.actions": "Change",
|
|
26
|
+
"account.never": "never",
|
|
27
|
+
"account.add": "Add an account",
|
|
28
|
+
"account.addSubmit": "Add the account",
|
|
29
|
+
"account.added": "{username} can sign in now.",
|
|
30
|
+
"account.usernameHelp": "Letters, digits, dots, dashes and underscores.",
|
|
31
|
+
"account.setPassword": "Set password",
|
|
32
|
+
"account.setPasswordTitle": "Set the password of {username}",
|
|
33
|
+
"account.setPasswordNote": "{username} is signed out everywhere, and signs in with this password from now on.",
|
|
34
|
+
"account.setPasswordSubmit": "Set the password",
|
|
35
|
+
"account.roleOf": "Role of {username}",
|
|
36
|
+
"account.changePassword": "Change your password",
|
|
37
|
+
"account.currentPassword": "Current password",
|
|
38
|
+
"account.newPassword": "New password",
|
|
39
|
+
"account.repeatPassword": "New password, again",
|
|
40
|
+
"account.passwordsDiffer": "The two new passwords differ.",
|
|
41
|
+
"account.passwordChanged": "Your password is changed. Other browsers signed in as you are signed out.",
|
|
42
|
+
"account.ownEnvManaged": "The server's .env defines your account: change ADMIN_PASSWORD there, then restart the server.",
|
|
43
|
+
"account.remove": "Remove",
|
|
44
|
+
"account.removeQuestion": "Remove {username}? It can no longer sign in.",
|
|
45
|
+
"account.needsWrite": "This page changes the data, and {username} can only read it.",
|
|
46
|
+
"account.needsAdmin": "This page is for administrators, and {username} is not one.",
|
|
47
|
+
"account.switchAccount": "Sign in as somebody else",
|
|
48
|
+
"account.unreachable": "The server cannot be reached. Try again in a moment.",
|
|
49
|
+
"account.refusal.wrongCredentials": "Wrong username or password.",
|
|
50
|
+
"account.refusal.tooManyAttempts": "Too many sign-ins from here. Try again in 15 minutes.",
|
|
51
|
+
"account.refusal.signInElsewhere": "Signing in happens on this site's own pages.",
|
|
52
|
+
"account.refusal.signOutElsewhere": "Signing out happens on this site's own pages.",
|
|
53
|
+
"account.refusal.changeElsewhere": "Changes are made from this site's own pages.",
|
|
54
|
+
"account.refusal.signInRequired": "This is for the accounts of this site: sign in.",
|
|
55
|
+
"account.refusal.sessionEnded": "The session has ended: sign in again.",
|
|
56
|
+
"account.refusal.wrongToken": "That is not the ADMIN_TOKEN of this server.",
|
|
57
|
+
"account.refusal.noAdminToken": "No ADMIN_TOKEN is set on this server: sign in instead.",
|
|
58
|
+
"account.refusal.roleTooLow": "Your account cannot do this: ask an administrator.",
|
|
59
|
+
"account.refusal.usernameLength": "A username has {min} to {max} characters.",
|
|
60
|
+
"account.refusal.usernameCharacters": "A username holds letters, digits, dots, dashes and underscores, and starts with a letter or a digit.",
|
|
61
|
+
"account.refusal.usernameTaken": "That username is taken.",
|
|
62
|
+
"account.refusal.passwordEmpty": "A password cannot be empty.",
|
|
63
|
+
"account.refusal.passwordTooLong": "A password has at most {max} characters.",
|
|
64
|
+
"account.refusal.noSuchAccount": "That account no longer exists.",
|
|
65
|
+
"account.refusal.nothingToChange": "Send a new password, a new role, or both.",
|
|
66
|
+
"account.refusal.useChangePassword": "Change your own password with POST /password, which asks for the current one.",
|
|
67
|
+
"account.refusal.ownRole": "You cannot change your own role.",
|
|
68
|
+
"account.refusal.removeYourself": "You cannot remove the account you are using.",
|
|
69
|
+
"account.refusal.lastAdmin": "The last administrator can be neither removed nor demoted.",
|
|
70
|
+
"account.refusal.envManaged": "The server's .env defines this account, so it is changed there.",
|
|
71
|
+
"account.refusal.tokenCannotChangePassword": "A password is changed by the account signed in, not with the ADMIN_TOKEN.",
|
|
72
|
+
"account.refusal.wrongCurrentPassword": "The current password is not that one.",
|
|
73
|
+
"account.refusal.accountRemoved": "The account signed in was removed.",
|
|
11
74
|
"ecosystem.tools": "Tools",
|
|
12
75
|
"ecosystem.menuHeading": "Our tools, all in the browser",
|
|
13
76
|
"ecosystem.otherTools": "Our other tools",
|
package/src/locales/es.json
CHANGED
|
@@ -8,6 +8,69 @@
|
|
|
8
8
|
"account.signIn": "Iniciar sesión",
|
|
9
9
|
"account.signOut": "Cerrar sesión",
|
|
10
10
|
"account.signedInAs": "Sesión iniciada como {name}",
|
|
11
|
+
"account.username": "Nombre de usuario",
|
|
12
|
+
"account.password": "Contraseña",
|
|
13
|
+
"account.role": "Rol",
|
|
14
|
+
"account.role.read": "Lectura",
|
|
15
|
+
"account.role.write": "Lectura y escritura",
|
|
16
|
+
"account.role.admin": "Administrador",
|
|
17
|
+
"account.you": "usted",
|
|
18
|
+
"account.envManaged": "definida en .env",
|
|
19
|
+
"account.envManagedTitle": "ADMIN_USERNAME y ADMIN_PASSWORD, en el .env del servidor, definen esta cuenta, que se cambia allí.",
|
|
20
|
+
"account.accounts": "Cuentas",
|
|
21
|
+
"account.accountsNote": "Lectura ve los datos, Lectura y escritura también los cambia, y Administrador también gestiona estas cuentas.",
|
|
22
|
+
"account.column.added": "Añadida",
|
|
23
|
+
"account.column.lastSignIn": "Último inicio de sesión",
|
|
24
|
+
"account.column.passwordChanged": "Contraseña cambiada",
|
|
25
|
+
"account.column.actions": "Cambiar",
|
|
26
|
+
"account.never": "nunca",
|
|
27
|
+
"account.add": "Añadir una cuenta",
|
|
28
|
+
"account.addSubmit": "Añadir la cuenta",
|
|
29
|
+
"account.added": "{username} ya puede iniciar sesión.",
|
|
30
|
+
"account.usernameHelp": "Letras, cifras, puntos, guiones y guiones bajos.",
|
|
31
|
+
"account.setPassword": "Fijar contraseña",
|
|
32
|
+
"account.setPasswordTitle": "Fijar la contraseña de {username}",
|
|
33
|
+
"account.setPasswordNote": "{username} queda desconectado en todas partes, e inicia sesión con esta contraseña a partir de ahora.",
|
|
34
|
+
"account.setPasswordSubmit": "Fijar la contraseña",
|
|
35
|
+
"account.roleOf": "Rol de {username}",
|
|
36
|
+
"account.changePassword": "Cambiar su contraseña",
|
|
37
|
+
"account.currentPassword": "Contraseña actual",
|
|
38
|
+
"account.newPassword": "Nueva contraseña",
|
|
39
|
+
"account.repeatPassword": "Nueva contraseña, otra vez",
|
|
40
|
+
"account.passwordsDiffer": "Las dos contraseñas nuevas no coinciden.",
|
|
41
|
+
"account.passwordChanged": "Su contraseña ha cambiado. Los demás navegadores con su sesión quedan desconectados.",
|
|
42
|
+
"account.ownEnvManaged": "El .env del servidor define su cuenta: cambie ADMIN_PASSWORD allí y reinicie el servidor.",
|
|
43
|
+
"account.remove": "Eliminar",
|
|
44
|
+
"account.removeQuestion": "¿Eliminar {username}? Ya no podrá iniciar sesión.",
|
|
45
|
+
"account.needsWrite": "Esta página cambia los datos, y {username} solo puede leerlos.",
|
|
46
|
+
"account.needsAdmin": "Esta página es para administradores, y {username} no lo es.",
|
|
47
|
+
"account.switchAccount": "Iniciar sesión con otra cuenta",
|
|
48
|
+
"account.unreachable": "No se puede contactar con el servidor. Inténtelo de nuevo en un momento.",
|
|
49
|
+
"account.refusal.wrongCredentials": "Nombre de usuario o contraseña incorrectos.",
|
|
50
|
+
"account.refusal.tooManyAttempts": "Demasiados intentos de inicio de sesión desde aquí. Inténtelo de nuevo dentro de 15 minutos.",
|
|
51
|
+
"account.refusal.signInElsewhere": "El inicio de sesión se hace desde las páginas de este sitio.",
|
|
52
|
+
"account.refusal.signOutElsewhere": "El cierre de sesión se hace desde las páginas de este sitio.",
|
|
53
|
+
"account.refusal.changeElsewhere": "Los cambios se hacen desde las páginas de este sitio.",
|
|
54
|
+
"account.refusal.signInRequired": "Esto es para las cuentas de este sitio: inicie sesión.",
|
|
55
|
+
"account.refusal.sessionEnded": "La sesión ha terminado: vuelva a iniciar sesión.",
|
|
56
|
+
"account.refusal.wrongToken": "Ese no es el ADMIN_TOKEN de este servidor.",
|
|
57
|
+
"account.refusal.noAdminToken": "Este servidor no tiene ningún ADMIN_TOKEN: inicie sesión en su lugar.",
|
|
58
|
+
"account.refusal.roleTooLow": "Su cuenta no puede hacer esto: pídaselo a un administrador.",
|
|
59
|
+
"account.refusal.usernameLength": "Un nombre de usuario tiene de {min} a {max} caracteres.",
|
|
60
|
+
"account.refusal.usernameCharacters": "Un nombre de usuario contiene letras, cifras, puntos, guiones y guiones bajos, y empieza por una letra o una cifra.",
|
|
61
|
+
"account.refusal.usernameTaken": "Ese nombre de usuario ya existe.",
|
|
62
|
+
"account.refusal.passwordEmpty": "Una contraseña no puede estar vacía.",
|
|
63
|
+
"account.refusal.passwordTooLong": "Una contraseña tiene como máximo {max} caracteres.",
|
|
64
|
+
"account.refusal.noSuchAccount": "Esa cuenta ya no existe.",
|
|
65
|
+
"account.refusal.nothingToChange": "Envíe una contraseña nueva, un rol nuevo, o ambos.",
|
|
66
|
+
"account.refusal.useChangePassword": "Cambie su propia contraseña con POST /password, que pide la actual.",
|
|
67
|
+
"account.refusal.ownRole": "No puede cambiar su propio rol.",
|
|
68
|
+
"account.refusal.removeYourself": "No puede eliminar la cuenta que está usando.",
|
|
69
|
+
"account.refusal.lastAdmin": "El último administrador no puede eliminarse ni degradarse.",
|
|
70
|
+
"account.refusal.envManaged": "El .env del servidor define esta cuenta, que se cambia allí.",
|
|
71
|
+
"account.refusal.tokenCannotChangePassword": "Una contraseña la cambia la cuenta con la sesión iniciada, no el ADMIN_TOKEN.",
|
|
72
|
+
"account.refusal.wrongCurrentPassword": "La contraseña actual no es esa.",
|
|
73
|
+
"account.refusal.accountRemoved": "La cuenta con la sesión iniciada fue eliminada.",
|
|
11
74
|
"ecosystem.tools": "Herramientas",
|
|
12
75
|
"ecosystem.menuHeading": "Nuestras herramientas, todas en el navegador",
|
|
13
76
|
"ecosystem.otherTools": "Nuestras otras herramientas",
|