There are a few hits about those APIs in those places:
https://github.com/palantir/workshop-iframe-custom-widget/blob/d8d5230cbc3f3ad35768dfa13ed0f5abcdb497f2/src/example/Example.tsx#L83
Here is an example of setup, to pass an Object set from Workshop to your custom react application:
Home.tsx
import React from "react";
import {
MockPivotData,
} from "@hydrateobjectsetfromrid-example/sdk";
import Layout from "./Layout";
import {
IAsyncValue,
IWorkshopContext,
useWorkshopContext,
visitLoadingState,
isAsyncValue_Loaded,
} from "@osdk/workshop-iframe-custom-widget";
import { EXAMPLE_CONFIG } from "./config";
import {
// createAndFetchTempObjectSetRid,
hydrateObjectSetFromRid,
} from "@osdk/client/internal";
import client from "./client";
// eslint-disable-next-line import/named
import { Osdk, Result } from "@osdk/client";
// ========= Wrapper widget =========
// Application wrapper for Workshop state loading
export const WidgetWrapper = () => {
// useWorkshopContext() is imported from an npm library:
// - it takes in the definition of input values required from Workshop, and the outputs values that are sent to Workshop, and events that should be configured in Workshop
// - Returns a context object with an API that can be called to get values or set Workshop variables or execute Workshop events
//
// Example of getting an input value from Workshop:
// workshopContext["title"].getValue() -> returns string
//
// Example of setting an output value in Workshop:
// workshopContext["selectedTimelineObject"].set(value) -> void
//
// Example of executing an event in Workshop:
// workshopContext["eventOnTimelineClick"].executeEvent() -> void
//
const workshopContext = useWorkshopContext(EXAMPLE_CONFIG);
console.log(workshopContext.status)
// Note: we can have a proper management of the state on loading etc.
return visitLoadingState(workshopContext, {
loading: () => <>LOADING...</>,
// If the Workshop context was loaded successfully, we pass it to our custom widget
succeeded: (value) => {
console.log("Workshop context loaded successfully:", value);
return <MyCustomWidget loadedWorkshopContext={value} />
},
reloading: (previousValue) => {
console.log("Workshop context is reloading:", previousValue);
return <MyCustomWidget loadedWorkshopContext={previousValue} />
},
failed: (err) => {
console.error("Failed to load workshop context:", err);
return <div>SOMETHING WENT WRONG...</div>;
},
});
};
// ========= Utils functions =========
// Loads the value from the Workshop context. It will validate the value is present and has been loaded.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getValueFromAsyncValue = (asyncVal: IAsyncValue<any> | undefined) => {
if (asyncVal != null && isAsyncValue_Loaded(asyncVal)) {
const value = asyncVal.value;
if (typeof value === "string") {
return value; // return string as-is, no extra quotes
}
return JSON.stringify(value); // stringify non-string values
}
return undefined;
};
// ========= Custom widget =========
// Defines the interface of our "MyCustomWidget" widget
interface MyCustomWidgetProps {
loadedWorkshopContext: IWorkshopContext<typeof EXAMPLE_CONFIG>;
}
// Defines the custom widget itself
const MyCustomWidget: React.FC<MyCustomWidgetProps> = props => {
// We populat variables from the properties passed to the widget
const { loadedWorkshopContext } = props;
const [aggregationCount, setAggregationCount] = React.useState<number | null>(null);
// If Workshop context updates, then re-run the aggregation
React.useEffect(() => {
// Async function as we need it for the aggregation itself
const resoveObjectSetAndRunAggregation = async () => {
console.log("New Workshop state detected", loadedWorkshopContext)
const temporaryObjectSetRidFieldValue: IAsyncValue<string | undefined> = loadedWorkshopContext.temporaryObjectSetRidField.fieldValue;
const temporaryObjectSetString = getValueFromAsyncValue(temporaryObjectSetRidFieldValue);
console.log("Extracted temp object set string", temporaryObjectSetString)
// Check if client works
console.log("trying client usage")
const response: Result<Osdk.Instance<MockPivotData>> = await client(MockPivotData).fetchOneWithErrors("6d95f183-dce5-4d82-b20a-7ebf393293b8");
console.log("trying to load one random object", response)
// DEBUG
// temporaryObjectSetString = "ri.object-set.main.temporary-object-set.d33663f3-e3f8-4abd-8a37-b3267da6a803"
if (temporaryObjectSetString !== undefined) {
console.log("Valid temporary object set rid", temporaryObjectSetString)
// We have a valid object set rid, so we actually get the ObjectSet from it
const potentialObjectSet = hydrateObjectSetFromRid(
client,
MockPivotData,
temporaryObjectSetString
);
console.log("Object set retrieved. Running aggregation.", potentialObjectSet)
// We run the aggregation on our object set
const result2 = await potentialObjectSet.fetchOne("6d95f183-dce5-4d82-b20a-7ebf393293b8");
console.log("Fetch one object result", result2)
const result = await potentialObjectSet.aggregate({
$select: { $count: "unordered" },
});
console.log("Aggregation result", result)
// Do something with result here, e.g. set state
setAggregationCount(result.$count);
} else {
console.log("Invalid temp object set string. Aborting.")
}
};
resoveObjectSetAndRunAggregation();
}, [loadedWorkshopContext]);
return <Layout>
<h1>@hydrateobjectsetfromrid-example/sdk</h1>
<p>
Welcome to your Ontology SDK! Try using any of the following methods
now.
</p>
<p>Number of object in object set: {aggregationCount}</p>
</Layout>
};
config.tsx
import { IConfigDefinition } from "@osdk/workshop-iframe-custom-widget";
export const EXAMPLE_CONFIG = [
{
// Only compatible with https://www.npmjs.com/package/@osdk/client > 2.0
fieldId: "temporaryObjectSetRidField",
field: {
type: "single",
label: "Object set field (via temporary object set rid)",
fieldValue: {
type: "inputOutput",
variableType: {
type: "temporaryObjectSetRid",
}
}
}
},
] as const satisfies IConfigDefinition;
router.tsx
import { createBrowserRouter } from "react-router-dom";
import AuthCallback from "./AuthCallback";
import {WidgetWrapper} from "./Home";
export const router = createBrowserRouter(
[
{
path: "/",
element: <WidgetWrapper />,
},
{
// This is the route defined in your application's redirect URL
path: "/auth/callback",
element: <AuthCallback />,
},
],
{ basename: import.meta.env.BASE_URL },
);
Don’t forget, in package.json:
...
"dependencies": {
"@hydrateobjectsetfromrid-example/sdk": "latest",
"@osdk/client": "^2.2.0",
"@osdk/foundry": "^2.6.0",
"@osdk/oauth": "^1.1.0",
"@osdk/react": "^0.3.0",
"@osdk/workshop-iframe-custom-widget": "^1.1.0",
"react": "^18",
"react-dom": "^18",
"react-router-dom": "^6.23.1"
},
...
Then in Workshop, the object set will be passed to the widget, which will then have access to the object set “as an object set” which means, running aggregations, etc.