Skip to content

Commit

Permalink
Wrapper for card iframe
Browse files Browse the repository at this point in the history
  • Loading branch information
obgibson committed Dec 19, 2023
1 parent 63a1374 commit e940cda
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 11 deletions.
15 changes: 9 additions & 6 deletions src/components/MFCard/CardIframe.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactEventHandler, useEffect, useRef, useState } from 'react';
import React, { ReactEventHandler, forwardRef, useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import { MESSAGE_NAME } from '../Plugins/PluginManager';
import { apiHttp } from '../../constants';
Expand All @@ -16,8 +16,11 @@ const FALLBACK_HEIGHT = 750; // arbitrary height that should show enough
// Render single card in iframe.
//

const CardIframe: React.FC<Props> = ({ path }) => {
const ref = useRef<HTMLIFrameElement>(null);
const CardIframe = forwardRef(function (
{ path }: Props,
ref: React.RefObject<HTMLIFrameElement> | ((instance: HTMLIFrameElement | null) => void) | null | undefined,
) {
// const ref = useRef<HTMLIFrameElement>(null);
const [elementHeight, setElementHeight] = useState(0);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
Expand All @@ -29,7 +32,7 @@ const CardIframe: React.FC<Props> = ({ path }) => {
// Listen for a message from the iframe to check the height.
const listener = (e: MessageEvent) => {
// ensure the message is from the iframe we're interested in
if (e.source === ref.current?.contentWindow) {
if (e.source === (ref as React.RefObject<HTMLIFrameElement>)?.current?.contentWindow) {
if (e.data.type === MESSAGE_NAME.HEIGHT_CHECK) {
if (typeof e.data.height === 'number') {
// Stop checking iframe periodically if it tells us what height it is.
Expand All @@ -47,7 +50,7 @@ const CardIframe: React.FC<Props> = ({ path }) => {
// If not, wait for a postMessage from the iframe to set the height.
const checkHeight = () => {
try {
body = ref.current?.contentWindow?.document.body;
body = (ref as React.RefObject<HTMLIFrameElement>)?.current?.contentWindow?.document.body;
if (body) {
const h = Math.max(body?.scrollHeight ?? 0, body?.clientHeight ?? 0, body?.offsetHeight ?? 0);
if (h) {
Expand Down Expand Up @@ -102,7 +105,7 @@ const CardIframe: React.FC<Props> = ({ path }) => {
/>
</div>
);
};
});

const StyledCardIframe = styled.iframe`
width: 100%;
Expand Down
62 changes: 62 additions & 0 deletions src/components/MFCard/DynamicCardIframe.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { useEffect } from 'react';
import { apiHttp } from '../../constants';
import { taskCardPath } from '../../components/MFCard/useTaskCards';
import { Task } from '../../types';
import CardIframe from './CardIframe';

type Props = {
task: Task;
hash: string;
};

const INTERVAL = 1000;

//
// Render single card in iframe.
//

const DynamicCardIframe: React.FC<Props> = ({ task, hash }) => {
let ref: React.Ref<HTMLIFrameElement> | undefined;
let timeout: ReturnType<typeof setTimeout> | undefined;

const taskCardsPath = (task: Task): string => {
return `/flows/${task.flow_id}/runs/${task.run_number}/steps/${task.step_name}/tasks/${task.task_id}/cards/${hash}/data`;
};

const getNewData = (token: string, updateFn: (payload: object) => void) => {
fetch(`${apiHttp(taskCardsPath(task))}?invalidate=true`)
.then((result) => result.json())
.then((result) => {
if (token === result.payload?.reload_token) {
updateFn(result.payload);
if (!result.is_complete) {
timeout = setTimeout(() => {
getNewData(token, updateFn);
}, INTERVAL);
}
}
})
.catch((err) => {
console.error(err);
});
};

useEffect(() => {
const token = (ref as React.RefObject<HTMLIFrameElement>)?.current?.contentWindow?.METAFLOW_RELOAD_TOKEN;
const updateFn = (ref as React.RefObject<HTMLIFrameElement>)?.current?.contentWindow?.metaflow_card_update;

if (updateFn) {
timeout = setTimeout(() => {
getNewData(token, updateFn);
}, INTERVAL);
}

return () => {
clearTimeout(timeout);
};
}, []);

return <CardIframe path={`${taskCardPath(task, hash)}?embed=true`} ref={ref} />;
};

export default DynamicCardIframe;
6 changes: 3 additions & 3 deletions src/components/Timeline/TaskListLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ const StepCount = styled.span`
`;

const RowLabelContent = styled.div<{ type?: 'step' }>`
// In case of step row, lets remove icon width from total width so it aligns nicely
width: ${(p) => (p.type === 'step' ? 'calc(100% - 30px)' : '100%')};
// In case of step row, lets remove icon and caret width from total width so it aligns nicely
width: ${(p) => (p.type === 'step' ? 'calc(100% - 1.875rem - 1.875rem)' : 'calc(100% - 1.875rem - 1.875rem)')};
display: flex;
justify-content: space-between;
`;
Expand Down Expand Up @@ -215,5 +215,5 @@ const StepLabel = styled.div<{ isLoading: boolean }>`
`;

const Padding = styled.div`
width: 2.5rem;
width: 1.875rem;
`;
4 changes: 2 additions & 2 deletions src/pages/Task/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { apiHttp } from '../../constants';
import useTaskMetadata from './useTaskMetadata';
import { getTagOfType } from '../../utils/run';
import useTaskCards, { taskCardPath } from '../../components/MFCard/useTaskCards';
import CardIframe from '../../components/MFCard/CardIframe';
import DynamicCardIframe from '../../components/MFCard/DynamicCardIframe';
import Button from '../../components/Button';
import Icon from '../../components/Icon';

Expand Down Expand Up @@ -457,7 +457,7 @@ const Task: React.FC<TaskViewProps> = ({
</a>
</>
),
component: <CardIframe path={`${taskCardPath(task, def.hash)}?embed=true`} />,
component: <DynamicCardIframe task={task} hash={def.hash} />,
}))
: []),
// Show spinner if any cards are still loading
Expand Down

0 comments on commit e940cda

Please sign in to comment.