diff --git a/app/packages/operators/src/built-in-operators.ts b/app/packages/operators/src/built-in-operators.ts index 3edea7378c3..67e7ff6b096 100644 --- a/app/packages/operators/src/built-in-operators.ts +++ b/app/packages/operators/src/built-in-operators.ts @@ -1361,6 +1361,54 @@ export class EnableQueryPerformance extends Operator { } } +class OpenSample extends Operator { + _builtIn = true; + get config(): OperatorConfig { + return new OperatorConfig({ + name: "open_sample", + label: "Open Sample", + unlisted: true, + }); + } + async resolveInput(): Promise { + const inputs = new types.Object(); + inputs.str("id", { label: "Sample ID" }); + inputs.str("group_id", { label: "Group ID" }); + + return new types.Property(inputs); + } + useHooks(): object { + return { + setExpanded: fos.useSetExpandedSample(), + }; + } + async execute({ hooks, params }: ExecutionContext) { + hooks.setExpanded({ + id: params.id, + group_id: params.group_id, + }); + } +} + +class CloseSample extends Operator { + _builtIn = true; + get config(): OperatorConfig { + return new OperatorConfig({ + name: "close_sample", + label: "Close Sample", + unlisted: true, + }); + } + useHooks(): object { + return { + close: fos.useClearModal(), + }; + } + async execute({ hooks, params }: ExecutionContext) { + hooks.close(); + } +} + export function registerBuiltInOperators() { try { _registerBuiltInOperator(CopyViewAsJSON); @@ -1412,6 +1460,8 @@ export function registerBuiltInOperators() { _registerBuiltInOperator(SetFrameNumber); _registerBuiltInOperator(DisableQueryPerformance); _registerBuiltInOperator(EnableQueryPerformance); + _registerBuiltInOperator(OpenSample); + _registerBuiltInOperator(CloseSample); } catch (e) { console.error("Error registering built-in operators"); console.error(e); diff --git a/fiftyone/operators/operations.py b/fiftyone/operators/operations.py index f10c0a00f41..e0038aadfea 100644 --- a/fiftyone/operators/operations.py +++ b/fiftyone/operators/operations.py @@ -665,6 +665,21 @@ def set_group_slice(self, slice): """ return self._ctx.trigger("set_group_slice", {"slice": slice}) + def open_sample(self, id=None, group_id=None): + """Opens the specified sample or group in the App's sample modal. + + Args: + id (None): a sample ID to open in the modal + group_id (None): a group ID to open in the modal + """ + return self._ctx.trigger( + "open_sample", {"id": id, "group_id": group_id} + ) + + def close_sample(self): + """Closes the App's sample modal.""" + return self._ctx.trigger("close_sample") + def _serialize_view(view): return json.loads(json_util.dumps(view._serialize()))