Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

Commit

Permalink
Merge branch 'master' into fb-lsdv-4864/magic-wand-mig
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasrq committed Jan 9, 2024
2 parents efb7311 + 08aa5b5 commit 283e0a7
Show file tree
Hide file tree
Showing 16 changed files with 546 additions and 118 deletions.
2 changes: 1 addition & 1 deletion src/components/RelationsOverlay/RelationsOverlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ const RelationItemObserver = observer(({ relation, startNode, endNode, visible,
endNode={endNode}
direction={relation.direction}
visible={visibility}
labels={relation.selectedValues}
{...rest}
/>
) : null;
Expand Down Expand Up @@ -229,7 +230,6 @@ class RelationsOverlay extends PureComponent {
rootRef={this.rootNode}
startNode={relation.node1}
endNode={relation.node2}
labels={relation.relations?.selectedValues()}
dimm={hasHighlight && !highlighted}
highlight={highlighted}
visible={highlighted || visible}
Expand Down
1 change: 1 addition & 0 deletions src/components/SidePanels/DetailsPanel/Relations.styl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

&__icon
width 24px
min-height 24px
display flex
flex none
position relative
Expand Down
27 changes: 13 additions & 14 deletions src/components/SidePanels/DetailsPanel/Relations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ const RelationItem: FC<{relation: any}> = observer(({ relation }) => {
const { direction } = relation;

switch (direction) {
case 'left': return <IconRelationLeft/>;
case 'right': return <IconRelationRight/>;
case 'bi': return <IconRelationBi/>;
case 'left': return <IconRelationLeft data-direction={relation.direction}/>;
case 'right': return <IconRelationRight data-direction={relation.direction}/>;
case 'bi': return <IconRelationBi data-direction={relation.direction}/>;
default: return null;
}
}, [relation.direction]);
Expand Down Expand Up @@ -92,6 +92,7 @@ const RelationItem: FC<{relation: any}> = observer(({ relation }) => {
{(hovered || relation.showMeta) && relation.hasRelations && (
<Button
primary={relation.showMeta}
aria-label={`${relation.showMeta ? 'Hide' : 'Show'} Relation Labels`}
type={relation.showMeta ? undefined : 'text'}
onClick={relation.toggleMeta}
style={{ padding: 0 }}
Expand All @@ -102,14 +103,14 @@ const RelationItem: FC<{relation: any}> = observer(({ relation }) => {
</Elem>
<Elem name="action">
{(hovered || !relation.visible) && (
<Button type="text" onClick={relation.toggleVisibility}>
<Button type="text" onClick={relation.toggleVisibility} aria-label={`${relation.visible ? 'Hide' : 'Show'} Relation`}>
{relation.visible ? <IconEyeOpened/> : <IconEyeClosed />}
</Button>
)}
</Elem>
<Elem name="action">
{hovered && (
<Button type="text" danger onClick={() => {
<Button type="text" danger aria-label="Delete Relation" onClick={() => {
relation.node1.setHighlight(false);
relation.node2.setHighlight(false);
relation.parent.deleteRelation(relation);
Expand All @@ -127,10 +128,9 @@ const RelationItem: FC<{relation: any}> = observer(({ relation }) => {
);
});

const RelationMeta: FC<any> = ({ relation }) => {
const { relations } = relation;
const { children, choice } = relations;
const selected = relations.getSelected().map((v: any) => v.value);
const RelationMeta: FC<any> = observer(({ relation }) => {
const { selectedValues, control } = relation;
const { children, choice } = control;

const selectionMode = useMemo(() => {
return choice === 'multiple' ? 'multiple' : undefined;
Expand All @@ -139,17 +139,16 @@ const RelationMeta: FC<any> = ({ relation }) => {
const onChange = useCallback((val: any) => {
const values: any[] = wrapArray(val);

relations.unselectAll();
values.forEach(v => relations.findRelation(v).setSelected(true));
}, []);
relation.setRelations(values);
}, [relation]);

return (
<Block name="relation-meta">
<Select
mode={selectionMode}
style={{ width: '100%' }}
placeholder="Select labels"
defaultValue={selected}
value={selectedValues}
onChange={onChange}
>
{children.map((c: any) => (
Expand All @@ -160,6 +159,6 @@ const RelationMeta: FC<any> = ({ relation }) => {
</Select>
</Block>
);
};
});

export const Relations = observer(RealtionsComponent);
1 change: 1 addition & 0 deletions src/components/TopBar/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const Actions = ({ store }) => {
const isViewAll = annotationStore.viewingAll;

const onToggleVisibility = useCallback(() => {
!isViewAll && entity.saveDraftImmediatelyWithResults({ useToast: true });
annotationStore.toggleViewingAllAnnotations();
}, [annotationStore]);

Expand Down
7 changes: 6 additions & 1 deletion src/components/TopBar/TopBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ export const TopBar = observer(({ store }) => {

const isViewAll = annotationStore?.viewingAll === true;

const toggleViewAll = () => {
!isViewAll && entity.saveDraftImmediatelyWithResults({ useToast: true });
annotationStore.toggleViewingAllAnnotations();
};

return store ? (
<Block name="topbar" mod={{ newLabelingUI: isFF(FF_DEV_3873) }}>
{isFF(FF_DEV_3873) ? (
Expand All @@ -31,7 +36,7 @@ export const TopBar = observer(({ store }) => {
icon={<IconViewAll />}
type="text"
aria-label="View All"
onClick={() => annotationStore.toggleViewingAllAnnotations()}
onClick={toggleViewAll}
primary={ isViewAll }
style={{
height: 36,
Expand Down
3 changes: 2 additions & 1 deletion src/core/TimeTraveller.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const TimeTraveller = types
undoIdx: 0,
targetPath: '',
skipNextUndoState: types.optional(types.boolean, false),

lastAdditionTime: types.optional(types.Date, new Date()),
createdIdx: 0,
})
.volatile(() => ({
Expand Down Expand Up @@ -102,6 +102,7 @@ const TimeTraveller = types
self.undoIdx = self.history.length - 1;
replaceNextUndoState = false;
changesDuringFreeze = false;
self.lastAdditionTime = new Date();
},

reinit(force = true) {
Expand Down
55 changes: 38 additions & 17 deletions src/stores/Annotation/Annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ import { UserExtended } from '../UserStore';

const hotkeys = Hotkey('Annotations', 'Annotations');

const TrackedState = types
.model('TrackedState', {
areas: types.map(Area),
relationStore: types.optional(RelationStore, {}),
});

export const Annotation = types
.model('Annotation', {
id: types.identifier,
Expand Down Expand Up @@ -70,19 +76,19 @@ export const Annotation = types
ground_truth: types.optional(types.boolean, false),
skipped: false,

history: types.optional(TimeTraveller, { targetPath: '../areas' }),
// This field stores all data that affects undo/redo history
// It should contain real objects to be able to work with them through snapshots
// Annotation will use getters to get them at the top level
// This data is never redefined directly, it's empty at the start
trackedState: types.optional(TrackedState, {}),
history: types.optional(TimeTraveller, { targetPath: '../trackedState' }),

dragMode: types.optional(types.boolean, false),

editable: types.optional(types.boolean, true),
readonly: types.optional(types.boolean, false),

relationMode: types.optional(types.boolean, false),
relationStore: types.optional(RelationStore, {
relations: [],
}),

areas: types.map(Area),

suggestions: types.map(Area),

Expand All @@ -98,6 +104,14 @@ export const Annotation = types

...(isFF(FF_DEV_3391) ? { root: Types.allModelsTypes() } : {}),
})
.views(self => ({
get areas() {
return self.trackedState.areas;
},
get relationStore() {
return self.trackedState.relationStore;
},
}))
.preProcessSnapshot(sn => {
// sn.draft = Boolean(sn.draft);
let user = sn.user ?? sn.completed_by ?? undefined;
Expand Down Expand Up @@ -181,6 +195,16 @@ export const Annotation = types
return results;
},

get serialized() {
// Dirty hack to force MST track changes
self.areas.toJSON();

return self.results
.map(r => r.serialize())
.filter(Boolean)
.concat(self.relationStore.serializeAnnotation());
},

get serializedSelection() {
// Dirty hack to force MST track changes
self.areas.toJSON();
Expand Down Expand Up @@ -457,7 +481,7 @@ export const Annotation = types
validate() {
let ok = true;

self.traverseTree(function (node) {
self.traverseTree(function(node) {
ok = node.validate?.();
if (ok === false) {
return TRAVERSE_STOP;
Expand Down Expand Up @@ -686,11 +710,11 @@ export const Annotation = types
if (self.autosave) self.autosave.flush();
},

async saveDraftImmediatelyWithResults() {
async saveDraftImmediatelyWithResults(params) {
// There is no draft to save as it was already saved as an annotation
if (self.submissionStarted || self.isDraftSaving) return {};
self.setDraftSaving(true);
const res = await self.saveDraft(null);
const res = await self.saveDraft(params);

return res;
},
Expand Down Expand Up @@ -912,15 +936,12 @@ export const Annotation = types

async serializeAnnotation(options) {
document.body.style.cursor = 'wait';
let result = [];

for (const singleResult of self.results) {
const serialized = await singleResult.serialize();

if (serialized) result.push(serialized);
}

result = result.concat(self.relationStore.serializeAnnotation(options));
const result = (await Promise.all(
self.results.map(r => r.serialize(options)))
)
.filter(Boolean)
.concat(self.relationStore.serialize(options));

document.body.style.cursor = 'default';

Expand Down
Loading

0 comments on commit 283e0a7

Please sign in to comment.