@@ -2,102 +2,81 @@ import type React from "react";
22import { useState , useEffect , useCallback } from "react" ;
33import { isEmpty , isNil } from "lodash" ;
44import "../baseStyles.css" ;
5- import {
6- Box ,
7- Text ,
8- usePluginContext ,
9- } from "@cortexapps/plugin-core/components" ;
5+ import { usePluginContext } from "@cortexapps/plugin-core/components" ;
106import { getEntityYaml } from "../api/Cortex" ;
117import { getConfluenceDetailsFromEntity } from "../lib/parseEntity" ;
12-
8+ import { Heading , Box } from "@chakra-ui/react" ;
139import Instructions from "./Instructions" ;
10+ import Loading from "./Loading" ;
11+ import Notice from "./Notice" ;
12+ import PageSelector from "./PageSelector" ;
13+ import { fetchConfluencePageContent } from "../api/fetchConfluencePageContent" ;
14+ import { fetchConfluencePluginConfig } from "../api/fetchConfluencePluginConfig" ;
1415
1516const PageContent : React . FC = ( ) => {
1617 const [ entityPages , setEntityPages ] = useState < EntityPageI [ ] > ( [ ] ) ;
1718 const [ pageContent , setPageContent ] = useState < string | undefined > ( ) ;
1819 const [ pageTitle , setPageTitle ] = useState < string | undefined > ( ) ;
19- const [ entityPage , setEntityPage ] = useState < any | string > ( ) ;
20+ const [ entityPage , setEntityPage ] = useState < string | number | undefined > ( ) ;
2021 const [ baseConfluenceUrl , setBaseConfluenceUrl ] = useState < string > ( "" ) ;
2122 const [ errorStr , setErrorStr ] = useState < string > ( "" ) ;
2223
2324 const context = usePluginContext ( ) ;
2425
2526 const fetchPageContent = useCallback (
2627 async ( pages : EntityPageI [ ] , pageId : string | number ) : Promise < void > => {
27- if ( pages . length === 0 ) {
28- return ;
29- }
28+ if ( pages . length === 0 ) return ;
3029 setEntityPage ( pageId ) ;
31- const jiraURL = `${ baseConfluenceUrl } /wiki/rest/api/content/${ pageId } ?expand=body.view` ;
32- setErrorStr ( "loading" ) ;
33- const contentResult = await fetch ( jiraURL ) ;
34- if ( ! contentResult . ok ) {
35- let newErrorStr = "" ;
36- // if the contentResult contains valid JSON, we can use it to display an error message
37- try {
38- if (
39- contentResult . headers
40- . get ( "content-type" )
41- ?. includes ( "application/json" )
42- ) {
43- const contentJSON = await contentResult . json ( ) ;
44- const msg : string =
45- contentJSON . message || JSON . stringify ( contentJSON ) ;
46- newErrorStr = `Failed to fetch Confluence page with ID ${ pageId } : ${ msg } ` ;
47- } else {
48- // just get the text if it's not JSON
49- const contentText = await contentResult . text ( ) ;
50- newErrorStr = contentText ;
51- }
52- } catch ( e ) {
53- // if we can't parse the content, just use the status text
54- newErrorStr =
55- contentResult . statusText || "Failed to fetch Confluence page" ;
56- }
57- setErrorStr ( newErrorStr ) ;
58- return ;
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 ) ;
5941 }
60- const contentJSON = await contentResult . json ( ) ;
61- setPageContent ( contentJSON . body . view . value ) ;
62- setPageTitle ( contentJSON . title ) ;
63- setErrorStr ( "" ) ;
6442 } ,
6543 [ baseConfluenceUrl ]
6644 ) ;
6745
6846 useEffect ( ( ) => {
69- if ( ! context ?. apiBaseUrl ) {
70- return ;
71- }
72- const getConfluencePluginConfig = async ( ) : Promise < void > => {
47+ if ( ! context ?. apiBaseUrl ) return ;
48+ const getConfig = async ( ) : Promise < void > => {
7349 setErrorStr ( "loading" ) ;
74- if ( ! context ?. apiBaseUrl ) {
75- return ;
76- }
77- let newConfluenceUrl = "" ;
7850 try {
79- const response = await fetch (
80- ` ${ context ? .apiBaseUrl } /catalog/confluence-plugin-config/openapi`
51+ const newConfluenceUrl = await fetchConfluencePluginConfig (
52+ context . apiBaseUrl
8153 ) ;
82- const data = await response . json ( ) ;
83- newConfluenceUrl = data . info [ "x-cortex-definition" ] [ "confluence-url" ] ;
84- } catch ( e ) { }
85- setBaseConfluenceUrl ( newConfluenceUrl ) ;
86- if ( ! newConfluenceUrl ) {
54+ setBaseConfluenceUrl ( newConfluenceUrl ) ;
55+ setErrorStr ( ! newConfluenceUrl ? "instructions" : "" ) ;
56+ } catch {
8757 setErrorStr ( "instructions" ) ;
8858 }
8959 } ;
90- void getConfluencePluginConfig ( ) ;
60+ void getConfig ( ) ;
9161 } , [ context ?. apiBaseUrl ] ) ;
9262
9363 useEffect ( ( ) => {
94- if ( ! context . apiBaseUrl || ! context . entity ?. tag || ! baseConfluenceUrl ) {
64+ if ( ! context . entity ?. tag ) {
65+ setErrorStr (
66+ "This plugin is intended to be used within the entities. " +
67+ "Go to an entity, then under Plugins, select Confluence to view the Confluence page(s)."
68+ ) ;
69+ }
70+
71+ if ( ! context . apiBaseUrl || ! baseConfluenceUrl ) {
9572 return ;
9673 }
97- const fetchEntityYaml = async ( ) : Promise < void > => {
74+
75+ const fetchEntityYamlData = async ( ) : Promise < void > => {
9876 const entityTag = context . entity ?. tag ;
9977 if ( ! isNil ( entityTag ) ) {
10078 try {
79+ setErrorStr ( "loading" ) ;
10180 const yaml = await getEntityYaml ( context . apiBaseUrl , entityTag ) ;
10281 const fetchedEntityPages = isEmpty ( yaml )
10382 ? [ ]
@@ -107,79 +86,63 @@ const PageContent: React.FC = () => {
10786 return ;
10887 }
10988 setEntityPages ( fetchedEntityPages ) ;
110- } catch ( e ) {
111- // This will still result in a "We could not find any Confluence page" error in the UI, but may as well trap in console as well
112- const msg : string = e . message || e . toString ( ) ;
113- setErrorStr ( `Error retrieving Confluence page: ${ msg } ` ) ;
114- console . error ( "Error retrieving Confluence page: " , e ) ;
89+ } catch ( error ) {
90+ setErrorStr (
91+ `Error retrieving Confluence page: ${ ( error as Error ) . message } `
92+ ) ;
93+ console . error ( "Error retrieving Confluence page: " , error ) ;
11594 }
11695 }
11796 } ;
118- void fetchEntityYaml ( ) ;
97+ void fetchEntityYamlData ( ) ;
11998 } , [ context . apiBaseUrl , context . entity ?. tag , baseConfluenceUrl ] ) ;
12099
121100 useEffect ( ( ) => {
122101 const setFirstPageContent = async ( ) : Promise < void > => {
123- if ( entityPages . length === 0 ) {
124- return ;
125- }
102+ if ( entityPages . length === 0 ) return ;
126103 await fetchPageContent ( entityPages , entityPages [ 0 ] . id ) ;
127104 } ;
128105 void setFirstPageContent ( ) ;
129106 } , [ baseConfluenceUrl , entityPages , fetchPageContent ] ) ;
130107
131- if ( errorStr === "loading" ) {
132- return < div > Loading...</ div > ;
133- } else if ( errorStr === "instructions" ) {
134- return < Instructions /> ;
135- } else if ( errorStr ) {
136- return (
137- < Box backgroundColor = "light" padding = { 3 } borderRadius = { 2 } >
138- < Text > { errorStr } </ Text >
139- </ Box >
140- ) ;
141- }
108+ if ( errorStr === "loading" ) return < Loading /> ;
109+ if ( errorStr === "instructions" ) return < Instructions /> ;
110+ if ( errorStr && errorStr !== "loading-content" )
111+ return < Notice > { errorStr } </ Notice > ;
142112
143113 if ( isNil ( entityPage ) ) {
144114 return (
145- < Box backgroundColor = "light" padding = { 3 } borderRadius = { 2 } >
146- < Text >
147- We could not find any Confluence page associated with this entity.
148- </ Text >
149- </ Box >
115+ < Notice >
116+ We could not find any Confluence page associated with this entity.
117+ </ Notice >
150118 ) ;
151119 }
152120
153121 return (
154- < div >
122+ < Box w = "full" minH = { 600 } >
155123 { entityPages . length > 1 && (
156- < div
157- style = { {
158- marginBottom : "1rem" ,
159- display : "flex" ,
160- justifyContent : "flex-end" ,
161- width : "100%" ,
162- } }
163- >
164- < select
165- value = { entityPage }
166- onChange = { ( e ) => {
167- void fetchPageContent ( entityPages , e . target . value ) ;
168- } }
169- >
170- { entityPages . map ( ( page ) => (
171- < option key = { page . id } value = { page . id } >
172- { page . title && page . title . length > 0
173- ? page . title
174- : `Page ID: ${ page . id } ` }
175- </ option >
176- ) ) }
177- </ select >
178- </ div >
124+ < PageSelector
125+ currentPageId = { entityPage }
126+ onChangeHandler = { fetchPageContent }
127+ pages = { entityPages }
128+ disabled = { errorStr === "loading-content" }
129+ />
130+ ) }
131+ { errorStr === "loading-content" ? (
132+ < Loading />
133+ ) : (
134+ < Box w = "full" >
135+ < Heading
136+ as = "h1"
137+ dangerouslySetInnerHTML = { { __html : pageTitle as string } }
138+ />
139+ < Box
140+ w = "full"
141+ dangerouslySetInnerHTML = { { __html : pageContent as string } }
142+ />
143+ </ Box >
179144 ) }
180- < h1 dangerouslySetInnerHTML = { { __html : pageTitle as string } } > </ h1 >
181- < p dangerouslySetInnerHTML = { { __html : pageContent as string } } > </ p >
182- </ div >
145+ </ Box >
183146 ) ;
184147} ;
185148
0 commit comments