Mirror of https://github.com/roostorg/osprey
github.com/roostorg/osprey
1import * as React from 'react';
2import classNames from 'classnames';
3import hljs from 'highlight.js';
4
5import { getUdfDocs } from '../../actions/DocActions';
6import usePromiseResult from '../../hooks/usePromiseResult';
7import { UdfArgumentSpec, UdfCategory, UdfMethodSpec } from '../../types/DocTypes';
8import Text, { TextSizes } from '../../uikit/Text';
9import { renderFromPromiseResult } from '../../utils/PromiseResultUtils';
10
11import styles from './UdfDocsView.module.css';
12
13/*
14TODO:
15- Set up page for other non-UDF documentation (eg have UDF header, probably change URL to be just `/docs`)
16- Ability to link to individual function's position on page, have hover button on each UDF title that navigates to
17 the UDF's URL
18- TOC at side
19- Render markdown (or at least simple subsets?) in the docs
20 */
21
22interface UdfDocProps {
23 udf: UdfMethodSpec;
24}
25
26const UdfDoc = ({ udf }: UdfDocProps) => {
27 const argumentAsParam = (arg: UdfArgumentSpec): string => {
28 const defaultPart = arg.default != null ? ` = ${arg.default}` : '';
29 return `${arg.name}: ${arg.type}${defaultPart}`;
30 };
31
32 const params = udf.argument_specs.map(argumentAsParam).join(', ');
33 const hasAnyArgDocs = udf.argument_specs.some((spec) => spec.doc != null);
34
35 const mainDoc = udf.doc != null && <Text size={TextSizes.LARGE}>{udf.doc}</Text>;
36 const argDocs = udf.argument_specs.map(
37 (spec) =>
38 spec.doc != null && (
39 <Text size={TextSizes.LARGE} key={spec.name}>
40 <code className={styles.udfParamName}>{spec.name}</code>: {spec.doc}
41 </Text>
42 )
43 );
44 const argDocsTitle = hasAnyArgDocs && <Text size={TextSizes.H5}>Parameters</Text>;
45 const noDocsNotice = udf.doc == null && !hasAnyArgDocs && <Text size={TextSizes.LARGE}>No documentation yet!</Text>;
46
47 // We need to add the `def` prefix and `: ...` suffix to ensure highlight.js recognizes this as a function
48 // declaration, but we don't actually want to display them, so we remove them from the processed HTML.
49 const methodSignature = hljs.highlight('python', `def ${udf.name}(${params}) -> ${udf.return_type}: ...`, true);
50 const methodSignatureRawHtml = methodSignature.value
51 .replace('<span class="hljs-keyword">def</span> ', '')
52 .replace(':</span> ...', '</span>');
53
54 return (
55 <>
56 <Text size={TextSizes.LARGE}>
57 <pre className={styles.methodSignatureDisplayArea}>
58 <code
59 className={classNames(styles.methodSignatureHighlightedWrap, 'python')}
60 dangerouslySetInnerHTML={{ __html: methodSignatureRawHtml }}
61 />
62 </pre>
63 </Text>
64 <div className={styles.udfDetails}>
65 {mainDoc}
66 {argDocsTitle}
67 {argDocs}
68 {noDocsNotice}
69 </div>
70 </>
71 );
72};
73
74const renderUdfCategory = (category: UdfCategory) => {
75 const categoryName = category.name || 'Other';
76 return (
77 <div className={styles.udfCategoryContainer} id={categoryName}>
78 <Text size={TextSizes.H4} className={styles.udfCategoryName} key={`category-${categoryName}`}>
79 {categoryName}
80 </Text>
81 {category.udfs.map((udf: UdfMethodSpec) => (
82 <UdfDoc key={udf.name} udf={udf} />
83 ))}
84 </div>
85 );
86};
87
88const UdfDocsView = () => {
89 const udfDocsResult = usePromiseResult(getUdfDocs);
90
91 return renderFromPromiseResult(udfDocsResult, (udfDocs) => (
92 <div className={styles.viewContainer}>
93 <div className={styles.udfDocsContainer}>{udfDocs.map(renderUdfCategory)}</div>
94 </div>
95 ));
96};
97
98export default UdfDocsView;