Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 95 additions & 14 deletions packages/embed-widget/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,17 @@ const LAYOUT_SETTINGS = {
function App(): JSX.Element {
const [error, setError] = useState<string>();
const [definition, setDefinition] = useState<dh.ide.VariableDefinition>();
const [sharedReady, setSharedReady] = useState<boolean>(false);
const searchParams = useMemo(
() => new URLSearchParams(window.location.search),
[]
);
// Get the widget name from the query param `name`.
const name = searchParams.get('name');
// Get the type of shared object from the query param,
// which is necessary if the widget is shared.
const type = searchParams.get('type');
const isShared = searchParams.get('isShared');
const api = useApi();
const connection = useConnection();
const client = useClient();
Expand Down Expand Up @@ -115,34 +120,86 @@ function App(): JSX.Element {
)
);

log.debug(`Loading widget definition for ${name}...`);
if (isShared === 'true') {
log.debug(`Checking if shared parameters are valid...`);

const newDefinition = await fetchVariableDefinition(connection, name);
if (type == null) {
throw new Error('Missing URL parameter "type"');
}

setDefinition(newDefinition);
setSharedReady(true);

log.debug(`Widget definition successfully loaded for ${name}`);
log.debug(`Shared parameters are valid`);
} else {
log.debug(`Loading widget definition for ${name}...`);

const newDefinition = await fetchVariableDefinition(
connection,
name
);

setDefinition(newDefinition);

log.debug(`Widget definition successfully loaded for ${name}`);
}
} catch (e: unknown) {
log.error(`Unable to load widget definition for ${name}`, e);
setError(`${e}`);
}
}
initApp();
},
[api, client, connection, dispatch, name, serverConfig, user]
[
api,
client,
connection,
dispatch,
name,
serverConfig,
user,
isShared,
type,
]
);

const isLoaded = definition != null && error == null;
const isLoading = definition == null && error == null;
const isLoaded =
(definition != null || sharedReady != false) && error == null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(definition != null || sharedReady != false) && error == null;
(definition != null || sharedReady) && error == null;

const isLoading = definition == null && sharedReady == false && error == null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const isLoading = definition == null && sharedReady == false && error == null;
const isLoading = definition == null && !sharedReady && error == null;


type ConnectionWithGetSharedObject = dh.IdeConnection & {
getSharedObject(name: string, type: string): Promise<unknown>;
};

function isConnectionWithGetSharedObject(
connection: dh.IdeConnection
): connection is ConnectionWithGetSharedObject {
return (
'getSharedObject' in connection &&
typeof connection.getSharedObject === 'function'
);
}
Comment on lines +169 to +180
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the type definition and typePredicate outside of/above this functional component.


const fetch = useMemo(() => {
if (definition == null) {
if (definition == null && !sharedReady) {
return async () => {
throw new Error('Definition is null');
};
}
return () => connection.getObject(definition);
}, [connection, definition]);
return () => {
if (name != null && type != null) {
if (isConnectionWithGetSharedObject(connection)) {
return connection.getSharedObject(name, type);
}
throw new Error(
'Connection does not have getSharedObject method. Cannot fetch shared object.'
);
}
if (definition != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd personally put the definition != null case first.

return connection.getObject(definition);
}
throw new Error('Definition is null or shared parameters are not set');
};
}, [connection, definition, sharedReady, name, type]);

const [goldenLayout, setGoldenLayout] = useState<GoldenLayout | null>(null);
const [dashboardId, setDashboardId] = useState('default-embed-widget'); // Can't be DEFAULT_DASHBOARD_ID because its dashboard layout is not stored in dashboardData
Expand Down Expand Up @@ -175,16 +232,40 @@ function App(): JSX.Element {
const [hasEmittedWidget, setHasEmittedWidget] = useState(false);

const handleDashboardInitialized = useCallback(() => {
if (goldenLayout == null || definition == null || hasEmittedWidget) {
if (
goldenLayout == null ||
(definition == null && sharedReady == null) ||
hasEmittedWidget
) {
return;
}

setHasEmittedWidget(true);

let widget = null;
if (sharedReady != null) {
widget = {
type,
name,
} as dh.ide.VariableDescriptor;
} else if (definition != null) {
widget = getVariableDescriptor(definition);
} else {
return;
}

emitPanelOpen(goldenLayout.eventHub, {
fetch,
widget: getVariableDescriptor(definition),
widget,
});
}, [goldenLayout, definition, fetch, hasEmittedWidget]);
}, [
goldenLayout,
definition,
fetch,
hasEmittedWidget,
name,
type,
sharedReady,
]);

const allDashboardData = useSelector(getAllDashboardsData);

Expand Down