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

Commit

Permalink
Merge remote-tracking branch 'origin/master' into fb-optic-107/save-d…
Browse files Browse the repository at this point in the history
…raft-view-all
  • Loading branch information
Travis1282 committed Jan 8, 2024
2 parents 8c3fcea + eb1194c commit 5bbe35e
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 9 deletions.
5 changes: 5 additions & 0 deletions src/components/App/Grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ This triggers next rerender with next annotation until all the annotations are r
class Item extends Component {
componentDidMount() {
Promise.all(this.props.annotation.objects.map(o => {
// as the image has lazy load, and the image is not being added to the viewport
// until it's loaded we need to skip the validation assuming that it's always ready,
// otherwise we'll get a blank canvas
if (o.type === 'image') return Promise.resolve();

return o.isReady
? Promise.resolve(o.isReady)
: new Promise(resolve => {
Expand Down
32 changes: 23 additions & 9 deletions src/core/Hotkey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ keymaster.filter = function(event) {
const ALIASES = {
'plus': '=', // "ctrl plus" is actually a "ctrl =" because shift is not used
'minus': '-',
// Here is a magic trick. Keymaster doesn't work with comma correctly (it breaks down everything upon unbinding), but the key code for comma it expects is 188
// And the magic is that '¼' has the same keycode. So we are going to trick keymaster to handle this in the right way.
',': '¼',
};

export const Hotkey = (
Expand Down Expand Up @@ -144,17 +147,27 @@ export const Hotkey = (
});
};

const getKeys = (key: string) => {
const tokenRegex = /((?:\w+\+)*(?:[^,]+|,)),?/g;

return [...key.replace(/\s/,'').matchAll(tokenRegex)].map(match => match[1]);
};

const unbind = () => {
for (const scope of [DEFAULT_SCOPE, INPUT_SCOPE]) {
for (const key of Object.keys(_hotkeys_map)) {
if (isFF(FF_LSDV_1148)) {
removeKeyHandlerRef(scope, key);
keymaster.unbind(key, scope);
rebindKeyHandlers(scope, key);
} else {
keymaster.unbind(key, scope);
const keys = getKeys(key);

for (const key of keys) {
if (isFF(FF_LSDV_1148)) {
removeKeyHandlerRef(scope, key);
keymaster.unbind(key, scope);
rebindKeyHandlers(scope, key);
} else {
keymaster.unbind(key, scope);
}
delete _hotkeys_desc[key];
}
delete _hotkeys_desc[key];
}
}

Expand All @@ -165,8 +178,9 @@ export const Hotkey = (

return {
applyAliases(key: string) {
return key
.split(',')
const keys = getKeys(key);

return keys
.map(k => k.split('+').map(k => ALIASES[k.trim()] ?? k).join('+'))
.join(',');
},
Expand Down
6 changes: 6 additions & 0 deletions tests/functional/data/core/hotkeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const createConfigWithHotkey = (hotkey: string) => `<View>
<Image name="img" value="$image"/>
<RectangleLabels name="tag" toName="img">
<Label value="Label" hotkey="${hotkey}" />
</RectangleLabels>
</View>`;
68 changes: 68 additions & 0 deletions tests/functional/specs/core/hotkeys.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Labels, LabelStudio } from '@heartexlabs/ls-test/helpers/LSF';
import {
createConfigWithHotkey
} from '../../data/core/hotkeys';
import { Generator } from '@heartexlabs/ls-test/helpers/common/Generator';

describe('Hotkeys', () => {
const hotkeysToCheck = [
['L', 'r'],
['ctrl+L', 'ctrl+r'],
[','],
[',',',',','], // it won't work with odd number of commas 'cause 2 calls of selecting label cancel each other
['a',','],
[',','b'],
['a',',','b'],
['ctrl+,','ctrl+.'],
['ctrl+.','ctrl+,'],
];

for (const hotkeys of hotkeysToCheck) {
const hotkeyString = hotkeys.join(',');

it(`should be able to use hotkey ${hotkeyString}`, () => {
Generator.generateImageUrl({ width: 800, height: 50 })
.then(imageUrl => {
LabelStudio.params()
.config(createConfigWithHotkey(hotkeyString))
.data({ image: imageUrl })
.withResult([])
.init();
});

LabelStudio.waitForObjectsReady();
Labels.label.should('have.length', 1);

cy.log('Check that hotkeys work');
for (const hotkey of hotkeys) {
const hotkeyInput = hotkey.includes('+') ? `{${hotkey}}` : `${hotkey}`;

// try to use hotkey
cy.get('body').type(hotkeyInput);
Labels.selectedLabel.contains('Label');
// deselect
cy.get('body').type('{esc}');
}

cy.log('Reload LS');
cy.window().then(win => {
win.LabelStudio.destroyAll();
new win.LabelStudio('label-studio', win.LSF_CONFIG);
});

LabelStudio.waitForObjectsReady();
Labels.label.should('have.length', 1);

cy.log('Check that hotkeys still work');
for (const hotkey of hotkeys) {
const hotkeyInput = hotkey.includes('+') ? `{${hotkey}}` : `${hotkey}`;

// try to use hotkey
cy.get('body').type(hotkeyInput);
Labels.selectedLabel.contains('Label');
// deselect
cy.get('body').type('{esc}');
}
});
}
});

0 comments on commit 5bbe35e

Please sign in to comment.