Skip to content

Commit c6ed639

Browse files
committed
move async stuff to hooks; change deprecated wiki endpoint; adjust tests
1 parent 2ea55de commit c6ed639

File tree

9 files changed

+347
-207
lines changed

9 files changed

+347
-207
lines changed

plugins/confluence-plugin/src/api/Cortex.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

plugins/confluence-plugin/src/api/fetchConfluencePageContent.ts

Lines changed: 0 additions & 35 deletions
This file was deleted.

plugins/confluence-plugin/src/api/fetchConfluencePluginConfig.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

plugins/confluence-plugin/src/components/PageContent.test.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ describe("PageContent", () => {
2424

2525
await waitFor(() => {
2626
expect(
27-
screen.getByText("No Confluence details exist on this entity.")
27+
screen.getByText(
28+
"We could not find any Confluence pages associated with this entity."
29+
)
2830
).toBeInTheDocument();
2931
});
3032
});

plugins/confluence-plugin/src/components/PageContent.tsx

Lines changed: 89 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,92 @@
11
import type React from "react";
2-
import { useState, useEffect, useCallback } from "react";
3-
import { isEmpty, isNil } from "lodash";
4-
import "../baseStyles.css";
2+
import { useState, useEffect, useMemo } from "react";
3+
import { isNil } from "lodash";
54
import { usePluginContext } from "@cortexapps/plugin-core/components";
6-
import { getEntityYaml } from "../api/Cortex";
7-
import { getConfluenceDetailsFromEntity } from "../lib/parseEntity";
85
import { Heading, Box } from "@chakra-ui/react";
6+
97
import Instructions from "./Instructions";
108
import Loading from "./Loading";
119
import Notice from "./Notice";
1210
import PageSelector from "./PageSelector";
13-
import { fetchConfluencePageContent } from "../api/fetchConfluencePageContent";
14-
import { fetchConfluencePluginConfig } from "../api/fetchConfluencePluginConfig";
11+
12+
import {
13+
usePluginConfig,
14+
useCortexEntityDefinition,
15+
useConfluencePageContent,
16+
} from "../hooks";
17+
18+
import "../baseStyles.css";
1519

1620
const PageContent: React.FC = () => {
17-
const [entityPages, setEntityPages] = useState<EntityPageI[]>([]);
18-
const [pageContent, setPageContent] = useState<string | undefined>();
19-
const [pageTitle, setPageTitle] = useState<string | undefined>();
20-
const [entityPage, setEntityPage] = useState<string | number | undefined>();
21-
const [baseConfluenceUrl, setBaseConfluenceUrl] = useState<string>("");
21+
const [entityPage, setEntityPage] = useState<EntityPageI>();
2222
const [errorStr, setErrorStr] = useState<string>("");
2323

2424
const context = usePluginContext();
2525

26-
const fetchPageContent = useCallback(
27-
async (pages: EntityPageI[], pageId: string | number): Promise<void> => {
28-
if (pages.length === 0) return;
29-
setEntityPage(pageId);
30-
setErrorStr("loading-content");
31-
try {
32-
const contentJSON = await fetchConfluencePageContent(
33-
baseConfluenceUrl,
34-
pageId
35-
);
36-
setPageContent(contentJSON.body.view.value);
37-
setPageTitle(contentJSON.title);
38-
setErrorStr("");
39-
} catch (error) {
40-
setErrorStr(error.message);
41-
}
42-
},
43-
[baseConfluenceUrl]
26+
const { isLoading: isPluginConfigLoading, pluginConfig } = usePluginConfig(
27+
"confluence-plugin-config"
4428
);
4529

46-
const fetchMissingPageTitles = useCallback(
47-
async (pages: EntityPageI[]): Promise<EntityPageI[]> => {
48-
if (pages.length === 0) return [];
49-
const updatedPages = await Promise.all(
50-
pages.map(async (page) => {
51-
if (page.title && page.title.length > 0) {
52-
return page;
53-
}
54-
try {
55-
const contentJSON = await fetchConfluencePageContent(
56-
baseConfluenceUrl,
57-
page.id
58-
);
59-
return {
60-
...page,
61-
title:
62-
page.title && page.title.length > 0
63-
? page.title
64-
: contentJSON.title,
65-
};
66-
} catch (error) {
67-
console.error(
68-
`Error fetching page title for page with ID ${page.id}: ${
69-
(error as Error).message
70-
}`
71-
);
72-
return page;
73-
}
74-
})
75-
);
76-
return updatedPages;
77-
},
78-
[baseConfluenceUrl]
30+
const { isLoading: isEntityDefinitionLoading, entityDefinition } =
31+
useCortexEntityDefinition(context.entity?.tag ?? "");
32+
33+
const baseConfluenceUrl = useMemo(
34+
() => pluginConfig?.info?.["x-cortex-definition"]?.["confluence-url"] ?? "",
35+
[pluginConfig]
7936
);
8037

81-
useEffect(() => {
82-
if (!context?.apiBaseUrl) return;
83-
const getConfig = async (): Promise<void> => {
84-
setErrorStr("loading");
85-
try {
86-
const newConfluenceUrl = await fetchConfluencePluginConfig(
87-
context.apiBaseUrl
88-
);
89-
setBaseConfluenceUrl(newConfluenceUrl);
90-
setErrorStr(!newConfluenceUrl ? "instructions" : "");
91-
} catch {
92-
setErrorStr("instructions");
38+
const entityPages = useMemo((): EntityPageI[] => {
39+
if (!entityDefinition) return [];
40+
const entityPages: EntityPageI[] = [];
41+
if (Array.isArray(entityDefinition.info?.["x-cortex-confluence"]?.pages)) {
42+
for (const page of entityDefinition.info["x-cortex-confluence"].pages) {
43+
const id = page.id as string;
44+
const title = page.title as string;
45+
if (id) {
46+
entityPages.push({ id, title });
47+
}
9348
}
94-
};
95-
void getConfig();
96-
}, [context?.apiBaseUrl]);
49+
}
50+
if (entityDefinition.info?.["x-cortex-confluence"]?.pageID) {
51+
entityPages.push({
52+
id: `${entityDefinition.info["x-cortex-confluence"].pageID as string}`,
53+
});
54+
}
55+
return entityPages;
56+
}, [entityDefinition]);
57+
58+
useEffect(() => {
59+
if (entityPages.length > 0 && !entityPage) {
60+
setEntityPage(entityPages[0]);
61+
}
62+
}, [entityPages, entityPage]);
63+
64+
const { isLoading: isContentLoading, contents } =
65+
useConfluencePageContent(entityPages);
66+
67+
const isLoading = useMemo(
68+
() =>
69+
isPluginConfigLoading || isEntityDefinitionLoading || isContentLoading,
70+
[isPluginConfigLoading, isEntityDefinitionLoading, isContentLoading]
71+
);
9772

9873
useEffect(() => {
9974
if (!context.entity?.tag) {
10075
setErrorStr(
101-
"This plugin is intended to be used within the entities. " +
76+
"This plugin is intended to be used within entities. " +
10277
"Go to an entity, then under Plugins, select Confluence to view the Confluence page(s)."
10378
);
10479
}
80+
}, [context.entity?.tag]);
10581

106-
if (!context.apiBaseUrl || !baseConfluenceUrl) {
107-
return;
108-
}
109-
110-
const fetchEntityYamlData = async (): Promise<void> => {
111-
const entityTag = context.entity?.tag;
112-
if (!isNil(entityTag)) {
113-
try {
114-
setErrorStr("loading");
115-
const yaml = await getEntityYaml(context.apiBaseUrl, entityTag);
116-
const fetchedEntityPages = isEmpty(yaml)
117-
? []
118-
: getConfluenceDetailsFromEntity(yaml);
119-
if (fetchedEntityPages.length === 0) {
120-
setErrorStr("No Confluence details exist on this entity.");
121-
return;
122-
}
123-
const pagesWithTitles = await fetchMissingPageTitles(
124-
fetchedEntityPages
125-
);
126-
setEntityPages(pagesWithTitles);
127-
} catch (error) {
128-
setErrorStr(
129-
`Error retrieving Confluence page: ${(error as Error).message}`
130-
);
131-
console.error("Error retrieving Confluence page: ", error);
132-
}
133-
}
134-
};
135-
void fetchEntityYamlData();
136-
}, [
137-
context.apiBaseUrl,
138-
context.entity?.tag,
139-
baseConfluenceUrl,
140-
fetchMissingPageTitles,
141-
]);
142-
143-
useEffect(() => {
144-
const setFirstPageContent = async (): Promise<void> => {
145-
if (entityPages.length === 0) return;
146-
await fetchPageContent(entityPages, entityPages[0].id);
147-
};
148-
void setFirstPageContent();
149-
}, [baseConfluenceUrl, entityPages, fetchPageContent]);
150-
151-
if (errorStr === "loading") return <Loading />;
152-
if (errorStr === "instructions") return <Instructions />;
153-
if (errorStr && errorStr !== "loading-content")
154-
return <Notice>{errorStr}</Notice>;
82+
if (isLoading) return <Loading />;
83+
if (!baseConfluenceUrl) return <Instructions />;
84+
if (errorStr) return <Notice>{errorStr}</Notice>;
15585

15686
if (isNil(entityPage)) {
15787
return (
15888
<Notice>
159-
We could not find any Confluence page associated with this entity.
89+
We could not find any Confluence pages associated with this entity.
16090
</Notice>
16191
);
16292
}
@@ -165,26 +95,42 @@ const PageContent: React.FC = () => {
16595
<Box w="full" minH={600}>
16696
{entityPages.length > 1 && (
16797
<PageSelector
168-
currentPageId={entityPage}
169-
onChangeHandler={fetchPageContent}
98+
currentPageId={entityPage.id}
99+
onChangeHandler={(pageId: string) => {
100+
const newEntityPage = entityPages.find(
101+
(page) => `${page.id as string}` === pageId
102+
);
103+
if (newEntityPage) setEntityPage(newEntityPage);
104+
}}
170105
pages={entityPages}
171-
disabled={errorStr === "loading-content"}
106+
disabled={isContentLoading}
172107
/>
173108
)}
174-
{errorStr === "loading-content" ? (
175-
<Loading />
176-
) : (
177-
<Box w="full">
178-
<Heading
179-
as="h1"
180-
dangerouslySetInnerHTML={{ __html: pageTitle as string }}
181-
/>
109+
<Box w="full">
110+
<Heading
111+
as="h1"
112+
dangerouslySetInnerHTML={{
113+
__html: contents[`${entityPage.id}`]?.title as string,
114+
}}
115+
/>
116+
{contents[`${entityPage.id}`]?.body && (
182117
<Box
183118
w="full"
184-
dangerouslySetInnerHTML={{ __html: pageContent as string }}
119+
dangerouslySetInnerHTML={{
120+
__html: contents[`${entityPage.id}`]?.body as string,
121+
}}
185122
/>
186-
</Box>
187-
)}
123+
)}
124+
{contents[`${entityPage.id}`]?.errors && (
125+
<Notice>
126+
{contents[`${entityPage.id}`]?.errors.map((error: any) => (
127+
<Box display="block" key={error.code}>
128+
{error.title}
129+
</Box>
130+
))}
131+
</Notice>
132+
)}
133+
</Box>
188134
</Box>
189135
);
190136
};

plugins/confluence-plugin/src/components/PageSelector.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ describe("PageSelector Component", () => {
6565

6666
fireEvent.change(screen.getByRole("combobox"), { target: { value: "2" } });
6767
await waitFor(() => {
68-
expect(mockOnChangeHandler).toHaveBeenCalledWith(mockPages, "2");
68+
expect(mockOnChangeHandler).toHaveBeenCalledWith("2");
6969
});
7070
});
7171

plugins/confluence-plugin/src/components/PageSelector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default function PageSelector({
2323
<Select
2424
value={currentPageId}
2525
onChange={(e) => {
26-
void onChangeHandler(pages, e.target.value);
26+
void onChangeHandler(e.target.value);
2727
}}
2828
disabled={disabled}
2929
w={"auto"}

0 commit comments

Comments
 (0)