Skip to content

Commit 45cebc6

Browse files
committed
Add OverviewMarkdown component for API overview markdown content display
1 parent 3c2c369 commit 45cebc6

File tree

3 files changed

+138
-9
lines changed

3 files changed

+138
-9
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/* eslint-disable react/no-children-prop */
2+
/*
3+
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com).
4+
*
5+
* WSO2 LLC. licenses this file to you under the Apache License,
6+
* Version 2.0 (the "License"); you may not use this file except
7+
* in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import React, {
21+
useState, useEffect, useContext, Suspense, lazy,
22+
} from 'react';
23+
import { styled } from '@mui/material/styles';
24+
import PropTypes from 'prop-types';
25+
import { injectIntl } from 'react-intl';
26+
import API from 'AppData/api';
27+
import Settings from 'Settings';
28+
import remarkGfm from 'remark-gfm';
29+
import CircularProgress from '@mui/material/CircularProgress';
30+
import { vscDarkPlus, vs } from 'react-syntax-highlighter/dist/esm/styles/prism';
31+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
32+
import { ApiContext } from '../ApiContext';
33+
34+
const PREFIX = 'OverviewMarkdown';
35+
36+
const classes = {
37+
root: `${PREFIX}-root`,
38+
};
39+
40+
const Root = styled('div')((
41+
{
42+
theme,
43+
},
44+
) => ({
45+
[`& .${classes.root}`]: {
46+
paddingTop: theme.spacing(2),
47+
paddingBottom: theme.spacing(2),
48+
},
49+
}));
50+
51+
const ReactMarkdown = lazy(() => import('react-markdown' /* webpackChunkName: "MDReactMarkdown" */));
52+
53+
function OverviewMarkdown({ apiId }) {
54+
const { api } = useContext(ApiContext);
55+
const [code, setCode] = useState('');
56+
const restAPI = new API();
57+
const { skipHtml, syntaxHighlighterProps = {}, syntaxHighlighterDarkTheme } = Settings.app.markdown;
58+
59+
const loadContentForDoc = () => {
60+
restAPI.getMarkdownContentOfAPI(apiId)
61+
.then((dataDoc) => {
62+
let { text } = dataDoc;
63+
Object.keys(api).forEach((fieldName) => {
64+
// eslint-disable-next-line no-useless-escape
65+
const regex = new RegExp('\_\_\_' + fieldName + '\_\_\_', 'g');
66+
text = text.replace(regex, api[fieldName]);
67+
});
68+
setCode(text);
69+
})
70+
.catch((error) => {
71+
if (process.env.NODE_ENV !== 'production') {
72+
console.log(error);
73+
}
74+
});
75+
};
76+
77+
useEffect(() => {
78+
loadContentForDoc();
79+
}, [apiId]);
80+
81+
return (
82+
<Root>
83+
<div className='markdown-content-wrapper'>
84+
<Suspense fallback={<CircularProgress />}>
85+
<ReactMarkdown
86+
skipHtml={skipHtml}
87+
children={code}
88+
remarkPlugins={[remarkGfm]}
89+
components={{
90+
code({
91+
node, inline, className, children, ...propsInner
92+
}) {
93+
const match = /language-(\w+)/.exec(className || '');
94+
return !inline && match ? (
95+
<SyntaxHighlighter
96+
children={String(children).replace(/\n$/, '')}
97+
style={syntaxHighlighterDarkTheme ? vscDarkPlus : vs}
98+
language={match[1]}
99+
PreTag='div'
100+
{...propsInner}
101+
{...syntaxHighlighterProps}
102+
/>
103+
) : (
104+
<code className={className} {...propsInner}>
105+
{children}
106+
</code>
107+
);
108+
},
109+
}}
110+
/>
111+
</Suspense>
112+
</div>
113+
</Root>
114+
);
115+
}
116+
117+
OverviewMarkdown.propTypes = {
118+
classes: PropTypes.shape({}).isRequired,
119+
apiId: PropTypes.string.isRequired,
120+
};
121+
122+
export default injectIntl((OverviewMarkdown));

portals/devportal/src/main/webapp/source/src/app/components/Apis/Details/Overview.jsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import InlineMessage from 'AppComponents/Shared/InlineMessage';
4949
import Progress from 'AppComponents/Shared/Progress';
5050
import API from 'AppData/api';
5151
import CONSTANTS from 'AppData/Constants';
52-
import View from 'AppComponents/Apis/Details/Documents/View';
52+
import OverviewMarkdown from 'AppComponents/Apis/Details/Documents/OverviewMarkdown';
5353
import SolaceEndpoints from './SolaceEndpoints';
5454
import Environments from './Environments';
5555
import Comments from './Comments/Comments';
@@ -191,7 +191,6 @@ function Overview() {
191191
const [isLoading, setIsLoading] = useState(false);
192192
const [notFound, setNotFound] = useState(false);
193193
const [allDocuments, setAllDocuments] = useState(null);
194-
const [overviewDocOverride, setOverviewDocOverride] = useState(null);
195194
const [swaggerDescription, setSwaggerDescription] = useState(null);
196195
const [allPolicies, setAllPolicies] = useState(null);
197196
const [rating, setRating] = useState({
@@ -293,11 +292,6 @@ function Overview() {
293292
const restApi = new API();
294293
return restApi.getDocumentsByAPIId(api.id)
295294
.then((response) => {
296-
const overviewDoc = response.body.list.filter((item) => item.otherTypeName === '_overview');
297-
if (overviewDoc.length > 0) {
298-
// We can override the UI with this content
299-
setOverviewDocOverride(overviewDoc[0]); // Only one doc we can render
300-
}
301295
setAllDocuments(response.body.list);
302296
})
303297
.catch((error) => {
@@ -430,11 +424,11 @@ function Overview() {
430424
/>
431425
);
432426
}
433-
if (overviewDocOverride) {
427+
if (api.isMarkdownOverview) {
434428
return (
435429
<Root>
436430
<Paper className={classes.paperWithDoc} elevation={0}>
437-
<View doc={overviewDocOverride} apiId={api.id} fullScreen dontShowName />
431+
<OverviewMarkdown apiId={api.id} fullScreen dontShowName />
438432
</Paper>
439433
</Root>
440434
);

portals/devportal/src/main/webapp/source/src/app/data/api.jsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@ export default class API extends Resource {
8484
return promised_getDocContent;
8585
}
8686

87+
/*
88+
* Get the markdown overview content of an API
89+
*/
90+
getMarkdownContentOfAPI(api_id) {
91+
const promiseGetMarkdDownContent = this.client.then((client) => {
92+
const payload = {
93+
apiId: api_id,
94+
};
95+
return client.apis.APIs.getMarkdownContentOfAPI(payload);
96+
});
97+
return promiseGetMarkdDownContent;
98+
}
99+
87100
/**
88101
* Get the Documents of an API
89102
* @param id {String} UUID of the API in which the documents needed

0 commit comments

Comments
 (0)