Skip to content

Commit

Permalink
feat(docgen-sidebar): add polling to tags loading in dogen sidebar (#…
Browse files Browse the repository at this point in the history
…3858)

* fix(content-explorer): Migrated Date (#3800)

* fix(docgen): add auto refetching of tags if they're being processed

* fix(docgen): address code review comments

* fix(docgen): address code review comments

* fix(docgen): update tests

* fix(docgen): add extra test case

* Update src/elements/content-sidebar/DocGenSidebar/DocGenSidebar.tsx

Co-authored-by: Trevor <7311041+tjuanitas@users.noreply.github.com>

* Update src/elements/content-sidebar/DocGenSidebar/DocGenSidebar.tsx

Co-authored-by: Trevor <7311041+tjuanitas@users.noreply.github.com>

* chore(docgen): address code review comments

* fix(docgen): bad merge

* fix(docgen): address code review comments

* fix(docgen): remove Promise.all

* fix(docgen): remove timeout

---------

Co-authored-by: greg-in-a-box <103291617+greg-in-a-box@users.noreply.github.com>
Co-authored-by: Trevor <7311041+tjuanitas@users.noreply.github.com>
  • Loading branch information
3 people authored Feb 6, 2025
1 parent 50d6c3f commit fcf335a
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 40 deletions.
89 changes: 50 additions & 39 deletions src/elements/content-sidebar/DocGenSidebar/DocGenSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React, { useState, useCallback, useEffect } from 'react';
import classNames from 'classnames';
import flow from 'lodash/flow';
import { useIntl } from 'react-intl';
Expand Down Expand Up @@ -33,6 +33,8 @@ import commonMessages from '../../common/messages';
import './DocGenSidebar.scss';
import { DocGenTag, DocGenTemplateTagsResponse, JsonPathsMap } from './types';

const DEFAULT_RETRIES = 10;

type ExternalProps = {
enabled: boolean;
getDocGenTags: () => Promise<DocGenTemplateTagsResponse>;
Expand All @@ -55,13 +57,13 @@ type JsonPathsState = {
const DocGenSidebar = ({ getDocGenTags }: Props) => {
const { formatMessage } = useIntl();

const [hasError, setHasError] = React.useState<boolean>(false);
const [isLoading, setIsLoading] = React.useState<boolean>(false);
const [tags, setTags] = React.useState<TagState>({
const [hasError, setHasError] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [tags, setTags] = useState<TagState>({
text: [],
image: [],
});
const [jsonPaths, setJsonPaths] = React.useState<JsonPathsState>({
const [jsonPaths, setJsonPaths] = useState<JsonPathsState>({
textTree: {},
imageTree: {},
});
Expand All @@ -73,7 +75,7 @@ const DocGenSidebar = ({ getDocGenTags }: Props) => {
}, base);
};

const tagsToJsonPaths = (docGenTags: DocGenTag[]): JsonPathsMap => {
const tagsToJsonPaths = useCallback((docGenTags: DocGenTag[]): JsonPathsMap => {
const jsonPathsMap: JsonPathsMap = {};

docGenTags.forEach(tag => {
Expand All @@ -84,49 +86,58 @@ const DocGenSidebar = ({ getDocGenTags }: Props) => {
});

return jsonPathsMap;
};
}, []);

const loadTags = async () => {
setIsLoading(true);
try {
const response: DocGenTemplateTagsResponse = await getDocGenTags();
if (response && !!response.data) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { data } = response || [];

// anything that is not an image tag for this view is treated as a text tag
const textTags = data?.filter(tag => tag.tag_type !== 'image') || [];
const imageTags = data?.filter(tag => tag.tag_type === 'image') || [];
setTags({
text: textTags,
image: imageTags,
});
setJsonPaths({
textTree: tagsToJsonPaths(textTags),
imageTree: tagsToJsonPaths(imageTags),
});
setHasError(false);
} else {
const loadTags = useCallback(
async (attempts = DEFAULT_RETRIES) => {
if (attempts <= 0) {
setIsLoading(false);
return;
}
setIsLoading(true);
try {
const response: DocGenTemplateTagsResponse = await getDocGenTags();
if (response?.message) {
loadTags.call(this, attempts - 1);
} else if (response?.data) {
const { data } = response;
// anything that is not an image tag for this view is treated as a text tag
const textTags = data?.filter(tag => tag.tag_type !== 'image') || [];
const imageTags = data?.filter(tag => tag.tag_type === 'image') || [];
setTags({
text: textTags,
image: imageTags,
});
setJsonPaths({
textTree: tagsToJsonPaths(textTags),
imageTree: tagsToJsonPaths(imageTags),
});
setHasError(false);
setIsLoading(false);
} else {
setHasError(true);
setIsLoading(false);
}
} catch (error) {
setHasError(true);
setIsLoading(false);
}
} catch (error) {
setHasError(true);
}
setIsLoading(false);
};

React.useEffect(() => {
loadTags();
},
// disabling eslint because the getDocGenTags prop is changing very frequently
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
[tagsToJsonPaths],
);

useEffect(() => {
loadTags(DEFAULT_RETRIES);
}, [loadTags]);

const isEmpty = tags.image.length + tags.text.length === 0;

return (
<SidebarContent sidebarView={SIDEBAR_VIEW_DOCGEN} title={formatMessage(messages.docGenTags)}>
<div className={classNames('bcs-DocGenSidebar', { center: isEmpty || hasError || isLoading })}>
{hasError && <Error onClick={loadTags} />}
{hasError && <Error onClick={() => loadTags(DEFAULT_RETRIES)} />}
{isLoading && (
<LoadingIndicator
aria-label={formatMessage(commonMessages.loading)}
Expand Down
1 change: 1 addition & 0 deletions src/elements/content-sidebar/DocGenSidebar/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type DocGenTag = {

export type DocGenTemplateTagsResponse = {
data?: DocGenTag[];
message?: string;
pagination?: {
previousMarker?: string;
nextMarker?: string;
Expand Down
51 changes: 50 additions & 1 deletion src/elements/content-sidebar/__tests__/DocGenSidebar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,39 @@ const docGenSidebarProps = {
),
};

const processAndResolveMock = jest
.fn()
.mockImplementationOnce(() =>
Promise.resolve({
message: 'Processing tags for this file.',
}),
)
.mockImplementationOnce(() =>
Promise.resolve({
pagination: {},
data: mockData,
}),
);

const noTagsMock = jest.fn().mockReturnValue(Promise.resolve({ data: [] }));
const processingTagsMock = jest.fn().mockReturnValue(
Promise.resolve({
message: 'Processing tags for this file.',
}),
);
const errorTagsMock = jest.fn().mockRejectedValue([]);
const noDataMock = jest.fn().mockReturnValue(Promise.resolve({}));

describe('elements/content-sidebar/DocGenSidebar', () => {
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.useRealTimers();
jest.clearAllMocks();
});

const renderComponent = (props = {}) =>
render(<DocGenSidebar logger={{ onReadyMetric: jest.fn() }} {...docGenSidebarProps} {...props} />);

Expand Down Expand Up @@ -72,11 +100,32 @@ describe('elements/content-sidebar/DocGenSidebar', () => {

expect(await screen.findByRole('status', { name: 'Loading' })).toBeInTheDocument();

jest.advanceTimersByTime(1000);

await waitFor(() => {
expect(screen.queryByRole('status', { name: 'Loading' })).not.toBeInTheDocument();
});
});

test('should re-trigger loadTags if the template is still processing', async () => {
renderComponent({
getDocGenTags: processingTagsMock,
});

await waitFor(() => expect(processingTagsMock).toHaveBeenCalledTimes(10));
});

test('should re-trigger loadTags retrigger and successfully display the tags', async () => {
renderComponent({
getDocGenTags: processAndResolveMock,
});

await waitFor(() => expect(processAndResolveMock).toHaveBeenCalledTimes(2));
const parentTag = await screen.findByText('about');

expect(parentTag).toBeVisible();
});

test('should re-trigger getDocGenTags on click on refresh button', async () => {
renderComponent({
getDocGenTags: errorTagsMock,
Expand All @@ -88,7 +137,7 @@ describe('elements/content-sidebar/DocGenSidebar', () => {
const refreshButton = screen.getByRole('button', { name: 'Process document' });
fireEvent.click(refreshButton);

await waitFor(() => expect(errorTagsMock).toBeCalledTimes(2));
await waitFor(() => expect(errorTagsMock).toHaveBeenCalledTimes(2));
});

test('should handle undefined data', async () => {
Expand Down

0 comments on commit fcf335a

Please sign in to comment.