Skip to content

Commit 42d27a6

Browse files
committed
Adds changes for label box selection
1 parent 0d81936 commit 42d27a6

File tree

6 files changed

+76
-99
lines changed

6 files changed

+76
-99
lines changed

src/components/projects/projectId/labeling/sessionId/sub-components/ExtractionDisplay.tsx

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { selectHoverGroupDict, selectSettings, selectTmpHighlightIds, selectTokenLookupSelected, setHoverGroupDict, tmpAddHighlightIds } from "@/src/reduxStore/states/pages/labeling";
1+
import { selectActiveTokenSelection, selectHoverGroupDict, selectSettings, selectTmpHighlightIds, setHoverGroupDict, tmpAddHighlightIds } from "@/src/reduxStore/states/pages/labeling";
22
import { LineBreaksType } from "@/src/types/components/projects/projectId/data-browser/data-browser";
33
import { ExtractionDisplayProps, LabelSourceHover } from "@/src/types/components/projects/projectId/labeling/labeling";
44
import { LabelingPageParts } from "@/src/types/components/projects/projectId/labeling/labeling-main-component";
55
import { Tooltip } from "@nextui-org/react";
66
import { useDispatch, useSelector } from "react-redux";
77
import style from '@/src/styles/components/projects/projectId/labeling.module.css';
88
import { useState, forwardRef, useEffect, useMemo } from "react";
9-
import { useConsoleLog } from "@/submodules/react-components/hooks/useConsoleLog";
109

1110
export function shouldHighlightOn(tmpHighlightIds: string[], comparedId: string[]) {
1211
return tmpHighlightIds.some((id) => comparedId.includes(id));
@@ -21,8 +20,6 @@ const ExtractionDisplay = forwardRef<HTMLInputElement, ExtractionDisplayProps>(f
2120

2221
const [hoverBoxDict, setHoverGroupDictTmp] = useState({});
2322

24-
// useConsoleLog(tokenLookupSelected)
25-
2623
function deleteRecordLabelAssociation(rlaId: string) {
2724
props.deleteRla(rlaId);
2825
}
@@ -109,30 +106,19 @@ const ExtractionDisplay = forwardRef<HTMLInputElement, ExtractionDisplayProps>(f
109106
});
110107

111108
function TokenValue(props: any) {
112-
const tokenLookupSelected = useSelector(selectTokenLookupSelected);
113-
// const saveTokenData = useSelector(selectTokenData)
114-
115-
useConsoleLog(tokenLookupSelected, 'tokenLookupSelected in tkoen value')
109+
const activeTokenSelection = useSelector(selectActiveTokenSelection);
116110

117-
const [findToken, setFindToken] = useState(null);
118111
const isSelected = useMemo(() => {
119-
if (!tokenLookupSelected || !props.attributeId) return false;
120-
// return props.token.idx >= tokenLookupSelected[props.attributeId].tokenStart && token.idx <= saveTokenData.tokenEnd;
121-
// const findToken = tokenLookupSelected[props.attributeId].token.find((token) => token.value == props.token.value && token.idx == props.token.idx);
122-
return false;
123-
}, [tokenLookupSelected, props.attributeId]);
124-
125-
// useEffect(() => {
126-
// if (!tokenLookupSelected || !props.attributeId) return;
127-
// const findToken = tokenLookupSelected[props.attributeId].token.find((token) => token.value == props.token.value && token.idx == props.token.idx);
128-
// setFindToken(findToken);
129-
// }, [tokenLookupSelected, props.attributeId]);
112+
if (!activeTokenSelection || !props.attributeId) return false;
113+
if (activeTokenSelection.attributeId != props.attributeId) return false;
114+
return props.token.idx >= activeTokenSelection.tokenStart && props.token.idx <= activeTokenSelection.tokenEnd;
115+
}, [activeTokenSelection, props.attributeId]);
130116

131117
return (<>
132118
{props.token && props.token.value != '\n' && <label onClick={(e) => props.setSelected(e)}
133119
className={`rounded-lg hover:bg-gray-200 text-sm text-gray-500 leading-5 relative font-normal ${!props.token.nextCloser ? 'pr-1' : ''}`}
134120
data-tokenidx={props.token.idx} data-attributeid={props.attributeId}
135-
style={{ backgroundColor: (findToken && findToken.selected) ? '#3399FF' : null, borderRadius: (findToken && findToken.selected) ? '0' : null, color: (findToken && findToken.selected) ? 'white' : null, zIndex: '100' }}>
121+
style={{ backgroundColor: isSelected ? '#3399FF' : null, borderRadius: isSelected ? '0' : null, color: isSelected ? 'white' : null, zIndex: '100' }}>
136122
{props.token.value}
137123
</label>}
138124
</>)

src/components/projects/projectId/labeling/sessionId/sub-components/LabelSelectionBox.tsx

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,15 @@ export default function LabelSelectionBox(props: LabelSelectionBoxProps) {
2424
const clearSelectedRef = useRef(props.clearSelected);
2525

2626
useEffect(() => {
27-
console.log("active tasks changed", props.activeTasks)
2827
if (props.activeTasks && props.activeTasks.length > 0) {
2928
setCurrentActiveTasks(props.activeTasks);
3029
} else {
3130
clearSelectedRef.current();
32-
console.log("called current ref")
33-
3431
}
3532
}, [props.activeTasks]);
3633

37-
useEffect(() => {
38-
return () => {
39-
clearSelectedRef.current();
40-
console.log("destruction evennt")
41-
}
42-
}, []);
43-
4434
useEffect(() => {
4535
clearSelectedRef.current = props.clearSelected;
46-
console.log("updated current ref")
4736
}, [props.clearSelected]);
4837

4938
useEffect(() => {

src/components/projects/projectId/labeling/sessionId/sub-components/LabelingSuiteLabeling.tsx

Lines changed: 30 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import LoadingIcon from "@/src/components/shared/loading/LoadingIcon"
22
import { selectUser } from "@/src/reduxStore/states/general"
3-
import { removeFromRlaById, selectDisplayUserRole, selectHoverGroupDict, selectRecordRequests, selectRecordRequestsRecord, selectSettings, selectTmpHighlightIds, selectTokenLookupSelected, selectUserDisplayId, setHoverGroupDict, setTokenLookupSelected, tmpAddHighlightIds } from "@/src/reduxStore/states/pages/labeling"
3+
import { removeFromRlaById, selectDisplayUserRole, selectHoverGroupDict, selectRecordRequests, selectRecordRequestsRecord, selectSettings, selectTmpHighlightIds, selectUserDisplayId, setActiveTokenSelection, tmpAddHighlightIds } from "@/src/reduxStore/states/pages/labeling"
44
import { selectLabelingTasksAll, selectVisibleAttributesLabeling } from "@/src/reduxStore/states/pages/settings"
55
import { selectProjectId } from "@/src/reduxStore/states/project"
66
import { HotkeyLookup, LabelSourceHover, LabelingVars, TokenLookup } from "@/src/types/components/projects/projectId/labeling/labeling"
@@ -27,6 +27,7 @@ import { filterRlaDataForUser } from "@/src/util/components/projects/projectId/l
2727
import { LabelingPageParts } from "@/src/types/components/projects/projectId/labeling/labeling-main-component"
2828
import style from '@/src/styles/components/projects/projectId/labeling.module.css';
2929
import { useConsoleLog } from "@/submodules/react-components/hooks/useConsoleLog"
30+
import { getStoreSnapshotValue } from "@/src/reduxStore/store"
3031

3132
const L_VARS = getDefaultLabelingVars();
3233

@@ -60,7 +61,6 @@ export default function LabelingSuiteLabeling() {
6061
const [activeTasks, setActiveTasks] = useState<any[]>(null);
6162
const [position, setPosition] = useState({ top: 0, left: 0 });
6263
const [labelHotkeys, setLabelHotkeys] = useState<HotkeyLookup>({});
63-
const [saveTokenData, setSaveTokenData] = useState<any>(null);
6464

6565
const extractionRef = useRef(null);
6666

@@ -100,10 +100,7 @@ export default function LabelingSuiteLabeling() {
100100

101101
useEffect(() => {
102102
const handleMouseDown = (event) => {
103-
console.log("closing the box?")
104-
if (!event.target.closest('.label-selection-box')) {
105-
setActiveTasksFunc([]);
106-
}
103+
setActiveTasksFuncRef.current([]);
107104
};
108105
window.addEventListener('mousedown', handleMouseDown);
109106
return () => {
@@ -123,8 +120,7 @@ export default function LabelingSuiteLabeling() {
123120
if (!tokenLookup || !extractionRef.current) return;
124121
const handleMouseUp = (e) => {
125122
const [check, attributeIdStart, tokenStart, tokenEnd, startEl] = parseSelectionData();
126-
setSaveTokenData({ attributeIdStart, tokenStart, tokenEnd, startEl });
127-
123+
dispatch(setActiveTokenSelection({ attributeId: attributeIdStart, tokenStart, tokenEnd }));
128124
if (!check) {
129125
clearSelected();
130126
} else {
@@ -240,7 +236,7 @@ export default function LabelingSuiteLabeling() {
240236
for (const key in lVars.taskLookup) {
241237
const found = lVars.taskLookup[key].lookup.filter(t => activeTaskIds.includes(t.task.id));
242238
if (found.length != 0) {
243-
setActiveTasksFunc(found);
239+
setActiveTasksFuncRef.current(found);
244240
break;
245241
}
246242
}
@@ -257,7 +253,7 @@ export default function LabelingSuiteLabeling() {
257253
setLabelHotkeys(labelHotkeysCopy);
258254
}
259255

260-
function setActiveTasksFunc(tasks: any | any[]) {
256+
const setActiveTasksFunc = useCallback((tasks: any | any[]) => {
261257
if (!canEditLabels && user?.role != UserRole.ANNOTATOR && userDisplayRole != UserRole.ANNOTATOR) {
262258
if (activeTasks) setActiveTasks([]);
263259
return;
@@ -268,7 +264,12 @@ export default function LabelingSuiteLabeling() {
268264
setActiveTasks([tasks]);
269265
}
270266
checkLabelVisibleInSearch(labelLookup);
271-
}
267+
}, [canEditLabels, user, activeTasks, userDisplayRole, labelLookup]);
268+
269+
const setActiveTasksFuncRef = useRef(null);
270+
useEffect(() => { setActiveTasksFuncRef.current = setActiveTasksFunc }, [setActiveTasksFunc]);
271+
272+
272273

273274
function toggleGoldStar(taskId: string, currentState: boolean) {
274275
if (currentState) {
@@ -444,15 +445,15 @@ export default function LabelingSuiteLabeling() {
444445
}
445446
}
446447

447-
function addRla(task: any, labelId: string, tokenLookupCopy?: TokenLookup) {
448+
function addRla(task: any, labelId: string) {
448449
if (!canEditLabels) return;
449450
if (task.taskType == LabelingTaskTaskType.MULTICLASS_CLASSIFICATION) {
450451
addLabelToTask(task.id, labelId);
451452
} else {
452-
addLabelToSelection(task.attribute.id, task.id, labelId, tokenLookupCopy);
453+
addLabelToSelection(task.attribute.id, task.id, labelId);
453454
}
454455
if (settings.labeling.closeLabelBoxAfterLabel) {
455-
setActiveTasksFunc([]);
456+
setActiveTasksFuncRef.current([]);
456457
clearSelected();
457458
}
458459
}
@@ -482,25 +483,17 @@ export default function LabelingSuiteLabeling() {
482483
});
483484
}
484485

485-
function addLabelToSelection(attributeId: string, labelingTaskId: string, labelId: string, tokenLookupCopy?: TokenLookup) {
486-
const tokenLookupFinal = tokenLookupCopy ? tokenLookupCopy : tokenLookup;
487-
const selectionData = collectSelectionData(attributeId, tokenLookupFinal, attributes, recordRequests);
486+
function addLabelToSelection(attributeId: string, labelingTaskId: string, labelId: string) {
487+
488+
const currentSelection = getStoreSnapshotValue(['labeling', 'activeTokenSelection']);
489+
const selectionData = collectSelectionData(attributeId, currentSelection, attributes, recordRequests);
488490
if (!selectionData) return;
489491
const sourceId = SessionManager.getSourceId();
490492
addExtractionLabelToRecordMut({ variables: { projectId: projectId, recordId: record.id, labelingTaskId: labelingTaskId, labelId: labelId, tokenStartIndex: selectionData.startIdx, tokenEndIndex: selectionData.endIdx, value: selectionData.value, sourceId: sourceId } }).then((res) => { });
491493
}
492494

493495
const clearSelected = useCallback(() => {
494-
console.log("clearSelected called")
495-
// const tokenLookupCopy = jsonCopy(tokenLookup);
496-
// for (const attributeId in tokenLookupCopy) {
497-
// if (!tokenLookupCopy[attributeId].token) continue;
498-
// for (const token of tokenLookupCopy[attributeId].token) {
499-
// if ('selected' in token) delete token.selected;
500-
// }
501-
// }
502-
// setTokenLookup(tokenLookupCopy);
503-
dispatch(setTokenLookupSelected(null));
496+
dispatch(setActiveTokenSelection(null));
504497
}, [tokenLookup]);
505498

506499
function setSelected(attributeId: string, tokenStart: number, tokenEnd: number, e?: any) {
@@ -510,14 +503,12 @@ export default function LabelingSuiteLabeling() {
510503
labelBoxPosition(e);
511504
return;
512505
}
513-
// for (const token of tokenLookupCopy[attributeId]?.token) {
514-
// token.selected = token.idx >= tokenStart && token.idx <= tokenEnd;
515-
// }
506+
dispatch(setActiveTokenSelection({ attributeId, tokenStart, tokenEnd }));
516507
if (lVars.taskLookup[attributeId].lookup[0].task.taskType == LabelingTaskTaskType.INFORMATION_EXTRACTION) {
517508
const extractionTasks = lVars.taskLookup[attributeId].lookup.filter(t => t.task.taskType == LabelingTaskTaskType.INFORMATION_EXTRACTION);
518-
setActiveTasksFunc(extractionTasks);
509+
setActiveTasksFuncRef.current(extractionTasks);
519510
} else {
520-
setActiveTasksFunc(lVars.taskLookup[attributeId].lookup);
511+
setActiveTasksFuncRef.current(lVars.taskLookup[attributeId].lookup);
521512
}
522513
setTokenLookup(tokenLookupCopy);
523514
labelBoxPosition(e);
@@ -542,7 +533,7 @@ export default function LabelingSuiteLabeling() {
542533
function handleKeyboardEvent(event) {
543534
const labelSelection = document.getElementById('label-selection-box');
544535
if (event.key == 'ArrowRight' || event.key == 'ArrowLeft') {
545-
setActiveTasksFunc([]);
536+
setActiveTasksFuncRef.current([]);
546537
}
547538
if (labelSelection && !labelSelection.classList.contains('hidden')) return;
548539
for (const key in labelHotkeys) {
@@ -582,7 +573,7 @@ export default function LabelingSuiteLabeling() {
582573
{task.task.taskType == LabelingTaskTaskType.INFORMATION_EXTRACTION ? (<ExtractionDisplay ref={extractionRef} attributeId={attribute.id} tokenLookup={tokenLookup} labelLookup={labelLookup}
583574
deleteRla={(rlaId) => {
584575
deleteRecordLabelAssociation(rlaId);
585-
setActiveTasksFunc([]);
576+
setActiveTasksFuncRef.current([]);
586577
}}
587578
setSelected={(start, end, e) => setSelected(attribute.id, start, end, e)} />) : (<>
588579
{(recordRequests.record.data[lVars.taskLookup[attribute.id].attribute.name] != null && recordRequests.record.data[lVars.taskLookup[attribute.id].attribute.name] !== '') ?
@@ -605,7 +596,7 @@ export default function LabelingSuiteLabeling() {
605596
</div>))}
606597
<Tooltip content={TOOLTIPS_DICT.LABELING.CHOOSE_LABELS} color="invert" placement="top">
607598
<button onClick={(event) => {
608-
setActiveTasksFunc(task);
599+
setActiveTasksFuncRef.current(task);
609600
labelBoxPosition(event);
610601
}} className="flex flex-row flex-nowrap bg-white text-gray-700 text-sm font-medium mr-3 px-2 py-0.5 rounded-md border border-gray-300 hover:bg-gray-50 focus:outline-none">
611602
<span>other</span>
@@ -647,23 +638,17 @@ export default function LabelingSuiteLabeling() {
647638
</div>}
648639
</>}
649640
</div>
650-
{activeTasks && activeTasks.length > 0 ? (
641+
<div className={activeTasks && activeTasks.length > 0 ? null : "hidden"}>
651642
<LabelSelectionBox activeTasks={activeTasks} position={position} labelLookup={labelLookup} labelAddButtonDisabledDict={labelAddButtonDisabledDict}
652643
clearSelected={clearSelected}
653644
addRla={(task, labelId) => {
654-
// const tokenLookupCopy = jsonCopy(tokenLookup);
655-
// if (saveTokenData && tokenLookupCopy[saveTokenData.attributeIdStart]) {
656-
// for (const token of tokenLookupCopy[saveTokenData.attributeIdStart]?.token) {
657-
// token.selected = token.idx >= saveTokenData.tokenStart && token.idx <= saveTokenData.tokenEnd;
658-
// }
659-
// }
660-
addRla(task, labelId, tokenLookup);
645+
addRla(task, labelId);
661646
}}
662647
addNewLabelToTask={(newLabel, task) => addNewLabelToTask(newLabel, task)}
663648
checkLabelVisibleInSearch={(newLabel, task) => checkLabelVisibleInSearch(labelLookup, newLabel, task)}
664649
labelHotkeys={labelHotkeys}
665-
/>)
666-
: null}
650+
/>
651+
</div>
667652
</div>}
668653
</Fragment>))}
669654
</Fragment>))}

src/reduxStore/states/pages/labeling.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import { RecordManager } from "@/src/util/classes/labeling/record-manager";
88
import { ComponentType, LabelingSuiteSettings } from "@/src/types/components/projects/projectId/labeling/settings";
99
import { UserRole } from "@/src/types/shared/sidebar";
1010

11+
export type CurrentSelection = {
12+
attributeId: string,
13+
tokenStart: number,
14+
tokenEnd: number
15+
}
16+
1117

1218
type LabelingSuiteState = {
1319
links: {
@@ -28,7 +34,7 @@ type LabelingSuiteState = {
2834
displayUserId: string;
2935
displayUserRole: UserRole;
3036
hoverGroupDict: { [key: string]: any };
31-
tokenLookupSelected: any;
37+
activeTokenSelection: CurrentSelection;
3238
}
3339

3440
function getInitState(): LabelingSuiteState {
@@ -51,7 +57,7 @@ function getInitState(): LabelingSuiteState {
5157
displayUserId: null,
5258
displayUserRole: null,
5359
hoverGroupDict: {},
54-
tokenLookupSelected: null
60+
activeTokenSelection: null,
5561
};
5662
}
5763

@@ -202,10 +208,9 @@ const labelingSlice = createSlice({
202208
if (action.payload) state.displayUserRole = action.payload;
203209
else state.displayUserRole = null;
204210
},
205-
setTokenLookupSelected(state, action: PayloadAction<any>) {
206-
console.log("setTokenLookupSelected", action.payload)
207-
if (action.payload) state.tokenLookupSelected = action.payload;
208-
else state.tokenLookupSelected = null;
211+
setActiveTokenSelection(state, action: PayloadAction<CurrentSelection>) {
212+
if (action.payload) state.activeTokenSelection = action.payload;
213+
else state.activeTokenSelection = null;
209214
}
210215

211216
},
@@ -225,10 +230,11 @@ export const selectTmpHighlightIds = (state: any) => state.labeling.tmpHighlight
225230
export const selectUserDisplayId = (state: any) => state.labeling.displayUserId;
226231
export const selectHoverGroupDict = (state: any) => state.labeling.hoverGroupDict;
227232
export const selectDisplayUserRole = (state: any) => state.labeling.displayUserRole;
228-
export const selectTokenLookupSelected = (state: any) => state.labeling.tokenLookupSelected;
233+
export const selectActiveTokenSelection = (state: any) => state.labeling.activeTokenSelection;
229234

230235
export const { setAvailableLinks, setSelectedLink, updateRecordRequests, updateUsers, setSettings, updateSettings,
231-
removeFromRlaById, tmpAddHighlightIds, setUserDisplayId, setHoverGroupDict, initOnLabelPageDestruction, setDisplayUserRole, setTokenLookupSelected } = labelingSlice.actions;
236+
removeFromRlaById, tmpAddHighlightIds, setUserDisplayId, setHoverGroupDict, initOnLabelPageDestruction, setDisplayUserRole,
237+
setActiveTokenSelection } = labelingSlice.actions;
232238

233239
export const labelingReducer = labelingSlice.reducer;
234240

src/reduxStore/store.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,13 @@ const store = configureStore({
3131
});
3232

3333
export default store;
34+
35+
export function getStoreSnapshotValue(access: string[]): any {
36+
// access via getState (current snapshot) when we don't need to subscribe to future updates
37+
const currentState = store.getState();
38+
let value = currentState;
39+
for (let i = 0; i < access.length; i++) {
40+
value = value[access[i]];
41+
}
42+
return value;
43+
}

0 commit comments

Comments
 (0)