Skip to content

Commit 2c5f491

Browse files
committed
fix: BROS-136: Don't allow to create regions in View All (#7907)
1 parent f393e7c commit 2c5f491

File tree

10 files changed

+49
-58
lines changed

10 files changed

+49
-58
lines changed

web/libs/editor/src/components/TimeSeries/TimeSeriesVisualizer.jsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class TimeSeriesVisualizerD3 extends React.Component {
9797
} = this.props;
9898

9999
const activeStates = parent?.activeStates();
100-
const statesSelected = activeStates && activeStates.length;
100+
const statesSelected = activeStates?.length;
101101
const readonly = parent?.annotation?.isReadOnly();
102102

103103
// skip if event fired by .move() - prevent recursion and bugs
@@ -108,10 +108,13 @@ class TimeSeriesVisualizerD3 extends React.Component {
108108
const x = d3.mouse(d3.event.sourceEvent.target)[0];
109109
const newRegion = this.newRegion;
110110

111+
// double click handler to create instant region
111112
// when 2nd click happens during 300ms after 1st click and in the same place
112113
if (newRegion && Math.abs(newRegion.x - x) < 4) {
113114
clearTimeout(this.newRegionTimer);
114-
parent?.regionChanged(newRegion.range, ranges.length, newRegion.states);
115+
if (!readonly) {
116+
parent?.regionChanged(newRegion.range, ranges.length, newRegion.states);
117+
}
115118
this.newRegion = null;
116119
this.newRegionTimer = null;
117120
} else if (statesSelected) {

web/libs/editor/src/components/Timeline/Timeline.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const TimelineComponent: FC<TimelineProps> = ({
3232
speed,
3333
className,
3434
formatPosition,
35+
readonly = false,
3536
...props
3637
}) => {
3738
const View = Views[mode];
@@ -106,8 +107,9 @@ const TimelineComponent: FC<TimelineProps> = ({
106107
seekOffset,
107108
settings: View.settings,
108109
visibleWidth: seekVisibleWidth,
110+
readonly,
109111
}),
110-
[position, seekOffset, seekVisibleWidth, length, regions, step, playing, View.settings, data],
112+
[position, seekOffset, seekVisibleWidth, length, regions, step, playing, View.settings, data, readonly],
111113
);
112114

113115
useEffect(() => {

web/libs/editor/src/components/Timeline/Types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface TimelineProps<D extends ViewTypes = "frames"> {
3232
controlsOnTop?: boolean;
3333
controls?: TimelineControls;
3434
customControls?: TimelineCustomControls[];
35+
readonly?: boolean;
3536
onReady?: (data: Record<string, any>) => void;
3637
onPlay?: () => void;
3738
onPause?: () => void;
@@ -121,6 +122,7 @@ export interface TimelineContextValue {
121122
settings?: TimelineSettings;
122123
changeSetting?: (key: string, value: any) => void;
123124
data?: any;
125+
readonly?: boolean;
124126
}
125127

126128
export interface TimelineMinimapProps {

web/libs/editor/src/components/Timeline/Views/Frames/Controls.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type DataType = {
1010
};
1111

1212
export const Controls: FC<TimelineExtraControls<Actions, DataType>> = ({ onAction }) => {
13-
const { position, regions } = useContext(TimelineContext);
13+
const { position, regions, readonly } = useContext(TimelineContext);
1414
const hasSelectedRegion = regions.some(({ selected, timeline }) => selected && !timeline);
1515
const closestKeypoint = useMemo(() => {
1616
const region = regions.find((r) => r.selected && !r.timeline);
@@ -69,11 +69,11 @@ export const Controls: FC<TimelineExtraControls<Actions, DataType>> = ({ onActio
6969

7070
return (
7171
<>
72-
<ControlButton onClick={onKeypointToggle} disabled={!hasSelectedRegion} tooltip="Toggle Keypoint">
72+
<ControlButton onClick={onKeypointToggle} disabled={!hasSelectedRegion || readonly} tooltip="Toggle Keypoint">
7373
{keypointIcon}
7474
</ControlButton>
7575

76-
<ControlButton onClick={onLifespanToggle} disabled={!closestKeypoint} tooltip="Toggle Interpolation">
76+
<ControlButton onClick={onLifespanToggle} disabled={!closestKeypoint || readonly} tooltip="Toggle Interpolation">
7777
{interpolationIcon}
7878
</ControlButton>
7979
</>

web/libs/editor/src/tags/object/AudioUltra/model.js

Lines changed: 14 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ import { observe } from "mobx";
22
import { getEnv, getRoot, getType, types } from "mobx-state-tree";
33
import { createRef } from "react";
44
import { customTypes } from "../../../core/CustomTypes";
5-
import { guidGenerator } from "../../../core/Helpers.ts";
65
import { AnnotationMixin } from "../../../mixins/AnnotationMixin";
76
import IsReadyMixin from "../../../mixins/IsReadyMixin";
87
import ProcessAttrsMixin from "../../../mixins/ProcessAttrs";
98
import { SyncableMixin } from "../../../mixins/Syncable";
109
import { AudioRegionModel } from "../../../regions/AudioRegion";
11-
import Utils from "../../../utils";
1210
import { FF_LSDV_E_278, isFF } from "../../../utils/feature-flags";
1311
import { isDefined } from "../../../utils/utilities";
1412
import ObjectBase from "../Base";
@@ -155,13 +153,13 @@ export const AudioModel = types.compose(
155153
activeStates() {
156154
const states = self.states();
157155

158-
return states && states.filter((s) => getType(s).name === "LabelsModel" && s.isSelected);
156+
return states?.filter((s) => getType(s).name === "LabelsModel" && s.isSelected);
159157
},
160158

161159
get activeState() {
162160
const states = self.states();
163161

164-
return states && states.filter((s) => getType(s).name === "LabelsModel" && s.isSelected)[0];
162+
return states?.filter((s) => getType(s).name === "LabelsModel" && s.isSelected)[0];
165163
},
166164

167165
get activeLabel() {
@@ -175,6 +173,9 @@ export const AudioModel = types.compose(
175173
// use label to generate a unique key to ensure that adding/deleting can trigger changes
176174
return labels ? labels.join(",") : "";
177175
},
176+
get readonly() {
177+
return self.annotation.isReadOnly();
178+
},
178179
}))
179180
////// Sync actions
180181
.actions((self) => ({
@@ -218,9 +219,9 @@ export const AudioModel = types.compose(
218219
////// Incoming
219220

220221
registerSyncHandlers() {
221-
["play", "pause", "seek"].forEach((event) => {
222+
for (const event of ["play", "pause", "seek"]) {
222223
self.syncHandlers.set(event, self.handleSync);
223-
});
224+
}
224225
self.syncHandlers.set("speed", self.handleSyncSpeed);
225226
},
226227

@@ -287,13 +288,13 @@ export const AudioModel = types.compose(
287288
const selectedColor = activeState?.selectedColor;
288289
const labels = activeState?.selectedValues();
289290

290-
selectedRegions.forEach((r) => {
291+
for (const r of selectedRegions) {
291292
r.update({ color: selectedColor, labels: labels ?? [] });
292293

293294
const region = r.isRegion ? self.updateRegion(r) : self.addRegion(r);
294295

295296
self.annotation.selectArea(region);
296-
});
297+
}
297298

298299
if (selectedRegions.length) {
299300
self.requestWSUpdate();
@@ -340,7 +341,7 @@ export const AudioModel = types.compose(
340341
(target) => target.type === "paragraphs" && target.contextscroll,
341342
);
342343

343-
syncedParagraphs.forEach((paragraph) => {
344+
for (const paragraph of syncedParagraphs) {
344345
const segments = Object.values(paragraph.regionsStartEnd).map(({ start, end }) => ({
345346
start,
346347
end,
@@ -350,7 +351,7 @@ export const AudioModel = types.compose(
350351
}));
351352

352353
self._ws.addRegions(segments);
353-
});
354+
}
354355
},
355356

356357
handleNewRegions() {
@@ -380,7 +381,7 @@ export const AudioModel = types.compose(
380381
},
381382

382383
onHotKey(e) {
383-
e && e.preventDefault();
384+
e?.preventDefault();
384385
self._ws.togglePlay();
385386
return false;
386387
},
@@ -393,34 +394,6 @@ export const AudioModel = types.compose(
393394
self.playBackRate = val;
394395
},
395396

396-
createRegion(wsRegion, states) {
397-
let bgColor = self.selectedregionbg;
398-
const st = states.find((s) => s.type === "labels");
399-
400-
if (st) bgColor = Utils.Colors.convertToRGBA(st.getSelectedColor(), 0.3);
401-
402-
const r = AudioRegionModel.create({
403-
id: wsRegion.id ? wsRegion.id : guidGenerator(),
404-
pid: wsRegion.pid ? wsRegion.pid : guidGenerator(),
405-
parentID: wsRegion.parent_id === null ? "" : wsRegion.parent_id,
406-
start: wsRegion.start,
407-
end: wsRegion.end,
408-
score: wsRegion.score,
409-
readonly: wsRegion.readonly,
410-
regionbg: self.regionbg,
411-
selectedregionbg: bgColor,
412-
normalization: wsRegion.normalization,
413-
states,
414-
});
415-
416-
r.setWSRegion(wsRegion);
417-
418-
self.regions.push(r);
419-
self.annotation.addRegion(r);
420-
421-
return r;
422-
},
423-
424397
addRegion(wsRegion) {
425398
// area id is assigned to WS region during deserealization
426399
const find_r = self.annotation.areas.get(wsRegion.id);
@@ -484,9 +457,9 @@ export const AudioModel = types.compose(
484457
},
485458

486459
clearRegionMappings() {
487-
self.regs.forEach((r) => {
460+
for (const r of self.regs) {
488461
r.setWSRegion(null);
489-
});
462+
}
490463
},
491464

492465
onLoad(ws) {

web/libs/editor/src/tags/object/AudioUltra/view.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ const AudioUltraView: FC<AudioUltraProps> = ({ item, children, settings = {}, ch
7171
onError: item.onError,
7272
regions: {
7373
createable: !item.readonly,
74-
updateable: !item.readonly,
75-
deleteable: !item.readonly,
7674
},
7775
timeline: {
7876
backgroundColor: isDarkMode ? "rgb(38, 37, 34)" : "rgba(255,255,255,0.8)",

web/libs/editor/src/tags/object/Paragraphs/HtxParagraphs.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ class HtxParagraphsView extends Component {
303303
if (!states || states.length === 0 || ev.ctrlKey || ev.metaKey)
304304
return this._selectRegions(ev.ctrlKey || ev.metaKey);
305305

306+
if (item.annotation.isReadOnly()) {
307+
return;
308+
}
309+
306310
const selectedRanges = this.captureDocumentSelection();
307311

308312
if (selectedRanges.length === 0) {

web/libs/editor/src/tags/object/TimeSeries/Channel.jsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ class ChannelD3 extends React.Component {
199199
} = this.props;
200200

201201
const activeStates = parent?.activeStates();
202-
const statesSelected = activeStates && activeStates.length;
202+
const statesSelected = activeStates?.length;
203203
const readonly = parent?.annotation?.isReadOnly();
204204

205205
// skip if event fired by .move() - prevent recursion and bugs
@@ -210,10 +210,13 @@ class ChannelD3 extends React.Component {
210210
const x = d3.mouse(d3.event.sourceEvent.target)[0];
211211
const newRegion = this.newRegion;
212212

213+
// double click handler to create instant region
213214
// when 2nd click happens during 300ms after 1st click and in the same place
214215
if (newRegion && Math.abs(newRegion.x - x) < 4) {
215216
clearTimeout(this.newRegionTimer);
216-
parent?.regionChanged(newRegion.range, ranges.length, newRegion.states);
217+
if (!readonly) {
218+
parent?.regionChanged(newRegion.range, ranges.length, newRegion.states);
219+
}
217220
this.newRegion = null;
218221
this.newRegionTimer = null;
219222
} else if (statesSelected) {
@@ -364,7 +367,7 @@ class ChannelD3 extends React.Component {
364367
const block = this.gCreator;
365368
const getRegion = this.getRegion;
366369
const x = this.x;
367-
const brush = (this.brushCreator = d3
370+
const brush = d3
368371
.brushX()
369372
.extent([
370373
[0, 0],
@@ -381,7 +384,9 @@ class ChannelD3 extends React.Component {
381384
// replacing default filter to allow ctrl-click action
382385
.filter(() => {
383386
return !d3.event.button;
384-
}));
387+
});
388+
389+
this.brushCreator = brush;
385390

386391
this.gCreator.call(this.brushCreator);
387392
}

web/libs/editor/src/tags/object/Video/HtxVideo.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ const HtxVideoView = ({ item, store }) => {
556556
disableView={!supportsTimelineRegions && !supportsRegions}
557557
framerate={item.framerate}
558558
controls={{ FramesControl: true }}
559+
readonly={item.annotation?.isReadOnly()}
559560
customControls={[
560561
{
561562
position: "left",

web/libs/editor/src/tags/object/Video/Video.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ const Model = types
140140
// normalize framerate — should be string with number of frames per second
141141
const framerate = Number(parseValue(self.framerate, self.store.task?.dataObj));
142142

143-
if (!framerate || isNaN(framerate)) self.framerate = "24";
143+
if (!framerate || Number.isNaN(framerate)) self.framerate = "24";
144144
else if (framerate < 1) self.framerate = String(1 / framerate);
145145
else self.framerate = String(framerate);
146146
},
@@ -178,9 +178,9 @@ const Model = types
178178
////// Incoming
179179

180180
registerSyncHandlers() {
181-
["play", "pause", "seek"].forEach((event) => {
181+
for (const event of ["play", "pause", "seek"]) {
182182
self.syncHandlers.set(event, self.handleSync);
183-
});
183+
}
184184
self.syncHandlers.set("speed", self.handleSyncSpeed);
185185
},
186186

@@ -260,9 +260,9 @@ const Model = types
260260
const area = self.annotation.createResult({ sequence }, {}, control, self);
261261

262262
// add labels
263-
self.activeStates().forEach((tag) => {
263+
for (const tag of self.activeStates()) {
264264
area.setValue(tag);
265-
});
265+
}
266266

267267
return area;
268268
},
@@ -304,6 +304,9 @@ const Model = types
304304
* @returns {Object} created region
305305
*/
306306
startDrawing({ frame, region: id }) {
307+
// don't create or edit regions in read-only mode
308+
if (self.annotation.isReadOnly()) return null;
309+
307310
if (id) {
308311
const region = self.annotation.regions.find((r) => r.cleanId === id);
309312
const range = region?.ranges?.[0];

0 commit comments

Comments
 (0)