Skip to content

Commit

Permalink
add spaces context to operators
Browse files Browse the repository at this point in the history
  • Loading branch information
imanjra committed Oct 10, 2024
1 parent 881f1fb commit e5a2dc1
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 8 deletions.
4 changes: 4 additions & 0 deletions app/packages/operators/src/CustomPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ export function defineCustomPanel({
on_change_selected_labels,
on_change_extended_selection,
on_change_group_slice,
on_change_spaces,
on_change_workspace,
panel_name,
panel_label,
}) {
Expand All @@ -132,6 +134,8 @@ export function defineCustomPanel({
onChangeSelectedLabels={on_change_selected_labels}
onChangeExtendedSelection={on_change_extended_selection}
onChangeGroupSlice={on_change_group_slice}
onChangeSpaces={on_change_spaces}
onChangeWorkspace={on_change_workspace}
dimensions={dimensions}
panelName={panel_name}
panelLabel={panel_label}
Expand Down
6 changes: 6 additions & 0 deletions app/packages/operators/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ function useOperatorThrottledContextSetter() {
const groupSlice = useRecoilValue(fos.groupSlice);
const currentSample = useCurrentSample();
const setContext = useSetRecoilState(operatorThrottledContext);
const spaces = useRecoilValue(fos.sessionSpaces);
const workspaceName = spaces._name;
const setThrottledContext = useMemo(() => {
return debounce(
(context) => {
Expand All @@ -49,6 +51,8 @@ function useOperatorThrottledContextSetter() {
currentSample,
viewName,
groupSlice,
spaces,
workspaceName,
});
}, [
setThrottledContext,
Expand All @@ -61,6 +65,8 @@ function useOperatorThrottledContextSetter() {
currentSample,
viewName,
groupSlice,
spaces,
workspaceName,
]);
}

Expand Down
21 changes: 20 additions & 1 deletion app/packages/operators/src/operators.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AnalyticsInfo, usingAnalytics } from "@fiftyone/analytics";
import { ServerError, getFetchFunction, isNullish } from "@fiftyone/utilities";
import { SpaceNode, spaceNodeFromJSON, SpaceNodeJSON } from "@fiftyone/spaces";
import { getFetchFunction, isNullish, ServerError } from "@fiftyone/utilities";
import { CallbackInterface } from "recoil";
import { QueueItemStatus } from "./constants";
import * as types from "./types";
Expand Down Expand Up @@ -92,6 +93,8 @@ export type RawContext = {
};
groupSlice: string;
queryPerformance?: boolean;
spaces: SpaceNodeJSON;
workspaceName: string;
};

export class ExecutionContext {
Expand Down Expand Up @@ -140,6 +143,12 @@ export class ExecutionContext {
public get queryPerformance(): boolean {
return Boolean(this._currentContext.queryPerformance);
}
public get spaces(): SpaceNode {
return spaceNodeFromJSON(this._currentContext.spaces);
}
public get workspaceName(): string {
return this._currentContext.workspaceName;
}

getCurrentPanelId(): string | null {
return this.params.panel_id || this.currentPanel?.id || null;
Expand Down Expand Up @@ -548,6 +557,8 @@ async function executeOperatorAsGenerator(
view: currentContext.view,
view_name: currentContext.viewName,
group_slice: currentContext.groupSlice,
spaces: currentContext.spaces,
workspace_name: currentContext.workspaceName,
},
"json-stream"
);
Expand Down Expand Up @@ -712,6 +723,8 @@ export async function executeOperatorWithContext(
view_name: currentContext.viewName,
group_slice: currentContext.groupSlice,
query_performance: currentContext.queryPerformance,
spaces: currentContext.spaces,
workspace_name: currentContext.workspaceName,
}
);
result = serverResult.result;
Expand Down Expand Up @@ -815,6 +828,8 @@ export async function resolveRemoteType(
view: currentContext.view,
view_name: currentContext.viewName,
group_slice: currentContext.groupSlice,
spaces: currentContext.spaces,
workspace_name: currentContext.workspaceName,
}
);

Expand Down Expand Up @@ -889,6 +904,8 @@ export async function resolveExecutionOptions(
view: currentContext.view,
view_name: currentContext.viewName,
group_slice: currentContext.groupSlice,
spaces: currentContext.spaces,
workspace_name: currentContext.workspaceName,
}
);

Expand Down Expand Up @@ -920,6 +937,8 @@ export async function fetchRemotePlacements(ctx: ExecutionContext) {
current_sample: currentContext.currentSample,
view_name: currentContext.viewName,
group_slice: currentContext.groupSlice,
spaces: currentContext.spaces,
workspace_name: currentContext.workspaceName,
}
);
if (result && result.error) {
Expand Down
10 changes: 10 additions & 0 deletions app/packages/operators/src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ const globalContextSelector = selector({
const extendedSelection = get(fos.extendedSelection);
const groupSlice = get(fos.groupSlice);
const queryPerformance = typeof get(fos.lightningThreshold) === "number";
const spaces = get(fos.sessionSpaces);
const workspaceName = spaces?._name;

return {
datasetName,
Expand All @@ -107,6 +109,8 @@ const globalContextSelector = selector({
extendedSelection,
groupSlice,
queryPerformance,
spaces,
workspaceName,
};
},
});
Expand Down Expand Up @@ -148,6 +152,8 @@ const useExecutionContext = (operatorName, hooks = {}) => {
extendedSelection,
groupSlice,
queryPerformance,
spaces,
workspaceName,
} = curCtx;
const [analyticsInfo] = useAnalyticsInfo();
const ctx = useMemo(() => {
Expand All @@ -166,6 +172,8 @@ const useExecutionContext = (operatorName, hooks = {}) => {
analyticsInfo,
groupSlice,
queryPerformance,
spaces,
workspaceName,
},
hooks
);
Expand All @@ -182,6 +190,8 @@ const useExecutionContext = (operatorName, hooks = {}) => {
currentSample,
groupSlice,
queryPerformance,
spaces,
workspaceName,
]);

return ctx;
Expand Down
9 changes: 9 additions & 0 deletions app/packages/operators/src/useCustomPanelHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export interface CustomPanelProps {
onChangeSelectedLabels?: string;
onChangeExtendedSelection?: string;
onChangeGroupSlice?: string;
onChangeSpaces?: string;
onChangeWorkspace?: string;
dimensions: DimensionsType | null;
panelName?: string;
panelLabel?: string;
Expand Down Expand Up @@ -136,6 +138,13 @@ export function useCustomPanelHooks(props: CustomPanelProps): CustomPanelHooks {
ctx.groupSlice,
props.onChangeGroupSlice
);
useCtxChangePanelEvent(isLoaded, panelId, ctx.spaces, props.onChangeSpaces);
useCtxChangePanelEvent(
isLoaded,
panelId,
ctx.workspaceName,
props.onChangeWorkspace
);

useEffect(() => {
onLoad();
Expand Down
27 changes: 27 additions & 0 deletions docs/source/plugins/developing_plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,7 @@ contains the following properties:
if any
- `ctx.results` - a dict containing the outputs of the `execute()` method, if
it has been called
- `ctx.spaces` - The current workspace or the state of spaces in the app.
- `ctx.hooks` **(JS only)** - the return value of the operator's `useHooks()`
method

Expand Down Expand Up @@ -2060,6 +2061,32 @@ subsequent sections.
ctx.panel.set_state("event", "on_change_group_slice")
ctx.panel.set_data("event_data", event)
def on_change_spaces(self, ctx):
"""Implement this method to set panel state/data when the current
state of spaces changes in the app.
The current state of spaces will be available via ``ctx.spaces``.
"""
event = {
"data": ctx.spaces,
"description": "the current state of spaces",
}
ctx.panel.set_state("event", "on_change_spaces")
ctx.panel.set_data("event_data", event)
def on_change_workspace(self, ctx):
"""Implement this method to set panel state/data when the current
workspace changes in the app.
The current workspace will be available via ``ctx.workspace``.
"""
event = {
"data": ctx.workspace,
"description": "the current workspace",
}
ctx.panel.set_state("event", "on_change_workspace")
ctx.panel.set_data("event_data", event)
#######################################################################
# Custom events
# These events are defined by user code above and, just like builtin
Expand Down
13 changes: 7 additions & 6 deletions fiftyone/operators/builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1939,18 +1939,18 @@ def resolve_input(self, ctx):
),
)

# @todo infer this automatically from current App spaces
current_spaces = ctx.spaces.to_json(True) if ctx.spaces else None
spaces_prop = inputs.oneof(
"spaces",
[types.String(), types.Object()],
default=None,
default=current_spaces,
required=True,
label="Spaces",
description=(
"JSON description of the workspace to save: "
"`print(session.spaces.to_json(True))`"
),
view=types.CodeView(),
view=types.CodeView(language="json"),
)

spaces = ctx.params.get("spaces", None)
Expand Down Expand Up @@ -2034,11 +2034,12 @@ def _edit_workspace_info_inputs(ctx, inputs):
for key in workspaces:
workspace_selector.add_choice(key, label=key)

# @todo default to current workspace name, if one is currently open
current_workspace = ctx.spaces.name if ctx.spaces else None
inputs.enum(
"name",
workspace_selector.values(),
required=True,
default=current_workspace,
label="Workspace",
description="The workspace to edit",
view=workspace_selector,
Expand Down Expand Up @@ -2102,11 +2103,11 @@ def resolve_input(self, ctx):
workspace_selector = types.AutocompleteView()
for key in workspaces:
workspace_selector.add_choice(key, label=key)

current_workspace = ctx.spaces.name if ctx.spaces else None
inputs.enum(
"name",
workspace_selector.values(),
default=None,
default=current_workspace,
required=True,
label="Workspace",
description="The workspace to delete",
Expand Down
12 changes: 12 additions & 0 deletions fiftyone/operators/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,18 @@ def query_performance(self):
"""Whether query performance is enabled."""
return self.request_params.get("query_performance", None)

@property
def spaces(self):
"""The current workspace or the state of spaces in the app."""
workspace_name = self.request_params.get("workspace_name", None)
if workspace_name is not None:
return self.dataset.load_workspace(workspace_name)

spaces_dict = self.request_params.get("spaces", None)
if spaces_dict is None:
return None
return fo.Space.from_dict(spaces_dict)

def prompt(
self,
operator_uri,
Expand Down
2 changes: 2 additions & 0 deletions fiftyone/operators/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ def register_panel(
current extended selection changes
on_change_group_slice (None): an operator to invoke when the group
slice changes
on_change_spaces (None): an operator to invoke when the current spaces changes
on_change_workspace (None): an operator to invoke when the current workspace changes
allow_duplicates (False): whether to allow multiple instances of
the panel to the opened
"""
Expand Down
2 changes: 2 additions & 0 deletions fiftyone/operators/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ def on_startup(self, ctx):
"on_change_selected_labels",
"on_change_extended_selection",
"on_change_group_slice",
"on_change_spaces",
"on_change_workspace",
]
for method in methods + ctx_change_events:
if hasattr(self, method) and callable(getattr(self, method)):
Expand Down
3 changes: 2 additions & 1 deletion fiftyone/server/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ def default(self, o):

async def create_response(response: dict):
return Response(
await run_sync_task(lambda: json_util.dumps(response, cls=Encoder))
await run_sync_task(lambda: json_util.dumps(response, cls=Encoder)),
media_type="application/json",
)


Expand Down

0 comments on commit e5a2dc1

Please sign in to comment.