@redocly/theme 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Button/Button.js +2 -2
- package/lib/Catalog/Filter.js +1 -3
- package/lib/Markdown/Admonition.d.ts +2 -1
- package/lib/Markdown/Admonition.js +2 -2
- package/lib/Profile/Profile.js +1 -1
- package/lib/ReferenceDocs/ClearButton.d.ts +8 -0
- package/lib/ReferenceDocs/ClearButton.js +48 -0
- package/lib/ReferenceDocs/DevOnboardingTryItSecurity.d.ts +3 -0
- package/lib/ReferenceDocs/DevOnboardingTryItSecurity.js +158 -0
- package/lib/ReferenceDocs/Dropdown.d.ts +28 -0
- package/lib/ReferenceDocs/Dropdown.js +150 -0
- package/lib/ReferenceDocs/TryItSecurityApps.d.ts +7 -0
- package/lib/ReferenceDocs/TryItSecurityApps.js +15 -0
- package/lib/ReferenceDocs/index.d.ts +1 -0
- package/lib/ReferenceDocs/index.js +18 -0
- package/lib/Sidebar/FooterWrapper.d.ts +3 -0
- package/lib/Sidebar/FooterWrapper.js +15 -0
- package/lib/Sidebar/HeaderWrapper.d.ts +3 -0
- package/lib/Sidebar/HeaderWrapper.js +15 -0
- package/lib/Sidebar/MenuContainer.d.ts +5 -3
- package/lib/Sidebar/MenuContainer.js +3 -2
- package/lib/Sidebar/MenuItemLabel.js +2 -2
- package/lib/Sidebar/Sidebar.d.ts +0 -1
- package/lib/Sidebar/Sidebar.js +1 -6
- package/lib/Sidebar/SidebarLayout.d.ts +4 -2
- package/lib/Sidebar/SidebarLayout.js +7 -28
- package/lib/Sidebar/index.d.ts +2 -0
- package/lib/Sidebar/index.js +2 -0
- package/lib/SourceCode/SourceCode.d.ts +3 -2
- package/lib/SourceCode/SourceCode.js +5 -5
- package/lib/globalStyle.js +8 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/mocks/hooks/index.d.ts +1 -1
- package/lib/mocks/hooks/index.js +3 -1
- package/lib/mocks/useGlobalData.d.ts +1 -0
- package/lib/mocks/useGlobalData.js +8 -0
- package/package.json +1 -1
- package/src/Button/Button.tsx +8 -4
- package/src/Catalog/Filter.tsx +1 -1
- package/src/Markdown/Admonition.tsx +3 -0
- package/src/Profile/Profile.tsx +1 -1
- package/src/ReferenceDocs/ClearButton.tsx +32 -0
- package/src/ReferenceDocs/DevOnboardingTryItSecurity.tsx +161 -0
- package/src/ReferenceDocs/Dropdown.tsx +202 -0
- package/src/ReferenceDocs/TryItSecurityApps.tsx +17 -0
- package/src/ReferenceDocs/index.ts +1 -0
- package/src/Sidebar/FooterWrapper.tsx +9 -0
- package/src/Sidebar/HeaderWrapper.tsx +9 -0
- package/src/Sidebar/MenuContainer.tsx +8 -3
- package/src/Sidebar/MenuItemLabel.tsx +2 -2
- package/src/Sidebar/Sidebar.tsx +1 -7
- package/src/Sidebar/SidebarLayout.tsx +12 -34
- package/src/Sidebar/index.ts +2 -0
- package/src/SourceCode/SourceCode.tsx +6 -0
- package/src/globalStyle.ts +8 -0
- package/src/index.ts +1 -0
- package/src/mocks/hooks/index.ts +2 -0
- package/src/mocks/useGlobalData.tsx +3 -0
|
@@ -7,14 +7,14 @@ exports.SidebarLayout = void 0;
|
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
9
9
|
const Sidebar_1 = require("../Sidebar/Sidebar");
|
|
10
|
+
const FooterWrapper_1 = require("../Sidebar/FooterWrapper");
|
|
11
|
+
const HeaderWrapper_1 = require("../Sidebar/HeaderWrapper");
|
|
10
12
|
const useMobileMenu_1 = require("../hooks/useMobileMenu");
|
|
11
13
|
const MobileSidebarButton_1 = require("../Sidebar/MobileSidebarButton");
|
|
12
14
|
const MenuContainer_1 = require("../Sidebar/MenuContainer");
|
|
13
15
|
const SidebarSearch_1 = require("../Search/SidebarSearch");
|
|
14
16
|
const useThemeConfig_1 = require("../hooks/useThemeConfig");
|
|
15
|
-
|
|
16
|
-
const Link_1 = require("../mocks/Link");
|
|
17
|
-
function SidebarLayout({ versions, menu, backLink, isNavbar, }) {
|
|
17
|
+
function SidebarLayout({ versions, menu, footer, header, growContent, }) {
|
|
18
18
|
const [isOpen, setIsOpen] = (0, useMobileMenu_1.useMobileMenu)();
|
|
19
19
|
const toggleMenu = () => setIsOpen(!isOpen);
|
|
20
20
|
const { search, sidebar } = (0, useThemeConfig_1.useThemeConfig)();
|
|
@@ -24,33 +24,12 @@ function SidebarLayout({ versions, menu, backLink, isNavbar, }) {
|
|
|
24
24
|
return (react_1.default.createElement(Wrapper, { "data-component-name": "Sidebar/SidebarLayout" },
|
|
25
25
|
react_1.default.createElement(MobileSidebarButton_1.MobileSidebarButton, { opened: isOpen, onClick: toggleMenu }),
|
|
26
26
|
!(search === null || search === void 0 ? void 0 : search.hide) && (search === null || search === void 0 ? void 0 : search.placement) === 'sidebar' ? react_1.default.createElement(SidebarSearch_1.SidebarSearch, null) : null,
|
|
27
|
-
react_1.default.createElement(Sidebar_1.Sidebar, { animate: true, opened: isOpen
|
|
28
|
-
|
|
29
|
-
react_1.default.createElement(Link_1.Link, { to: backLink.slug },
|
|
30
|
-
react_1.default.createElement(ArrowBack_1.ArrowBack, null),
|
|
31
|
-
"Back to ",
|
|
32
|
-
backLink.label)))) ||
|
|
33
|
-
null,
|
|
27
|
+
react_1.default.createElement(Sidebar_1.Sidebar, { animate: true, opened: isOpen },
|
|
28
|
+
header ? react_1.default.createElement(HeaderWrapper_1.HeaderWrapper, null, header) : null,
|
|
34
29
|
versions,
|
|
35
|
-
react_1.default.createElement(MenuContainer_1.MenuContainer,
|
|
30
|
+
react_1.default.createElement(MenuContainer_1.MenuContainer, { growContent: growContent }, menu),
|
|
31
|
+
footer ? react_1.default.createElement(FooterWrapper_1.FooterWrapper, null, footer) : null)));
|
|
36
32
|
}
|
|
37
33
|
exports.SidebarLayout = SidebarLayout;
|
|
38
|
-
const BackLinkWrapper = styled_components_1.default.div `
|
|
39
|
-
padding: var(--sidebar-offset-top) var(--sidebar-item-padding-horizontal)
|
|
40
|
-
var(--sidebar-item-padding-horizontal)
|
|
41
|
-
calc(var(--sidebar-offset-left) + var(--sidebar-item-padding-horizontal));
|
|
42
|
-
|
|
43
|
-
a {
|
|
44
|
-
color: var(--sidebar-back-button-text-color);
|
|
45
|
-
font-size: var(--sidebar-back-button-font-size);
|
|
46
|
-
font-family: var(--sidebar-back-button-font-family);
|
|
47
|
-
text-decoration: none;
|
|
48
|
-
&:hover {
|
|
49
|
-
color: var(--sidebar-back-button-hover-text-color);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
border-bottom: 1px solid var(--sidebar-border-color);
|
|
54
|
-
`;
|
|
55
34
|
const Wrapper = styled_components_1.default.div ``;
|
|
56
35
|
//# sourceMappingURL=SidebarLayout.js.map
|
package/lib/Sidebar/index.d.ts
CHANGED
package/lib/Sidebar/index.js
CHANGED
|
@@ -33,4 +33,6 @@ __exportStar(require("../Sidebar/Separator"), exports);
|
|
|
33
33
|
__exportStar(require("../Sidebar/SeparatorItem"), exports);
|
|
34
34
|
__exportStar(require("../Sidebar/Sidebar"), exports);
|
|
35
35
|
__exportStar(require("../Sidebar/SidebarLayout"), exports);
|
|
36
|
+
__exportStar(require("../Sidebar/FooterWrapper"), exports);
|
|
37
|
+
__exportStar(require("../Sidebar/HeaderWrapper"), exports);
|
|
36
38
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
interface CommonCodeProps {
|
|
3
3
|
withLineNumbers?: boolean;
|
|
4
4
|
startLineNumber?: number;
|
|
5
|
+
className?: string;
|
|
5
6
|
}
|
|
6
7
|
export interface SourceCodeProps extends CommonCodeProps {
|
|
7
8
|
lang: string;
|
|
@@ -27,6 +28,6 @@ export interface ExternalSource {
|
|
|
27
28
|
properties?: any;
|
|
28
29
|
operation?: any;
|
|
29
30
|
}
|
|
30
|
-
export declare function Code({ source, lang, dataTestId, withLineNumbers, startLineNumber, }: CodeProps): JSX.Element;
|
|
31
|
-
export declare function SourceCode({ lang, source, externalSource, onCopyClick, withCopyButton, dataTestId, withLineNumbers, startLineNumber, }: SourceCodeProps): JSX.Element;
|
|
31
|
+
export declare function Code({ source, lang, dataTestId, withLineNumbers, startLineNumber, className, }: CodeProps): JSX.Element;
|
|
32
|
+
export declare function SourceCode({ lang, source, externalSource, onCopyClick, withCopyButton, dataTestId, withLineNumbers, startLineNumber, className, }: SourceCodeProps): JSX.Element;
|
|
32
33
|
export {};
|
|
@@ -28,16 +28,16 @@ const react_1 = __importStar(require("react"));
|
|
|
28
28
|
const utils_1 = require("../utils");
|
|
29
29
|
const SamplesPanelControls_1 = require("../SamplesPanelControls");
|
|
30
30
|
const CopyButton_1 = require("../CopyButton");
|
|
31
|
-
function Code({ source, lang, dataTestId, withLineNumbers, startLineNumber, }) {
|
|
31
|
+
function Code({ source, lang, dataTestId, withLineNumbers, startLineNumber, className, }) {
|
|
32
32
|
const highlightedCode = (0, utils_1.highlight)(source, lang);
|
|
33
|
-
return (react_1.default.createElement(SamplesPanelControls_1.PreformattedCodeBlock, { dangerouslySetInnerHTML: {
|
|
33
|
+
return (react_1.default.createElement(SamplesPanelControls_1.PreformattedCodeBlock, { className: className, dangerouslySetInnerHTML: {
|
|
34
34
|
__html: withLineNumbers
|
|
35
35
|
? (0, utils_1.addLineNumbers)(highlightedCode, startLineNumber)
|
|
36
36
|
: highlightedCode,
|
|
37
37
|
}, "data-cy": dataTestId }));
|
|
38
38
|
}
|
|
39
39
|
exports.Code = Code;
|
|
40
|
-
function SourceCode({ lang, source, externalSource, onCopyClick, withCopyButton, dataTestId = 'source-code', withLineNumbers, startLineNumber, }) {
|
|
40
|
+
function SourceCode({ lang, source, externalSource, onCopyClick, withCopyButton, dataTestId = 'source-code', withLineNumbers, startLineNumber, className, }) {
|
|
41
41
|
const [sourceCode, setSourceCode] = (0, react_1.useState)(source !== null && source !== void 0 ? source : '');
|
|
42
42
|
// The same initial value should be returned for ssr and frontend to avoid issues
|
|
43
43
|
// Because we don't have session storage in ssr and can't get the security details there
|
|
@@ -52,9 +52,9 @@ function SourceCode({ lang, source, externalSource, onCopyClick, withCopyButton,
|
|
|
52
52
|
if (withCopyButton) {
|
|
53
53
|
return (react_1.default.createElement(CopyButton_1.CopyButtonWrapper, { data: sourceCode, onCopyClick: onCopyClick, "data-component-name": "SourceCode/SourceCode" }, ({ renderCopyButton }) => (react_1.default.createElement(SamplesPanelControls_1.SampleControlsWrap, null,
|
|
54
54
|
react_1.default.createElement(SamplesPanelControls_1.SampleControls, { "data-cy": "copy-button" }, renderCopyButton()),
|
|
55
|
-
react_1.default.createElement(Code, { lang: lang, source: sourceCode, withLineNumbers: withLineNumbers, startLineNumber: startLineNumber, dataTestId: dataTestId })))));
|
|
55
|
+
react_1.default.createElement(Code, { lang: lang, source: sourceCode, withLineNumbers: withLineNumbers, startLineNumber: startLineNumber, dataTestId: dataTestId, className: className })))));
|
|
56
56
|
}
|
|
57
|
-
return (react_1.default.createElement(Code, { dataTestId: dataTestId, lang: lang, source: sourceCode, withLineNumbers: withLineNumbers, startLineNumber: startLineNumber, "data-component-name": "SourceCode/SourceCode" }));
|
|
57
|
+
return (react_1.default.createElement(Code, { dataTestId: dataTestId, className: className, lang: lang, source: sourceCode, withLineNumbers: withLineNumbers, startLineNumber: startLineNumber, "data-component-name": "SourceCode/SourceCode" }));
|
|
58
58
|
}
|
|
59
59
|
exports.SourceCode = SourceCode;
|
|
60
60
|
//# sourceMappingURL=SourceCode.js.map
|
package/lib/globalStyle.js
CHANGED
|
@@ -1982,10 +1982,18 @@ exports.styles = (0, styled_components_1.css) `
|
|
|
1982
1982
|
${apiLogsTable}
|
|
1983
1983
|
${pages}
|
|
1984
1984
|
${modal}
|
|
1985
|
+
|
|
1986
|
+
--api-onboarding-table-text-color: #4e5356;
|
|
1987
|
+
|
|
1988
|
+
background-color: var(--background-color);
|
|
1989
|
+
color: var(--text-color);
|
|
1990
|
+
font-family: var(--font-family-base);
|
|
1985
1991
|
}
|
|
1986
1992
|
|
|
1987
1993
|
:root.dark {
|
|
1988
1994
|
${darkColors_1.darkMode};
|
|
1995
|
+
|
|
1996
|
+
--api-onboarding-table-text-color: #ffffff;
|
|
1989
1997
|
}
|
|
1990
1998
|
|
|
1991
1999
|
:root.notransition * {
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -39,4 +39,5 @@ __exportStar(require("./types/config"), exports);
|
|
|
39
39
|
__exportStar(require("./config"), exports);
|
|
40
40
|
__exportStar(require("./Pages"), exports);
|
|
41
41
|
__exportStar(require("./Markdown"), exports);
|
|
42
|
+
__exportStar(require("./ReferenceDocs"), exports);
|
|
42
43
|
//# sourceMappingURL=index.js.map
|
|
@@ -13,4 +13,4 @@ export declare function useSidebarSiblingsData(): {
|
|
|
13
13
|
};
|
|
14
14
|
export declare function usePageSharedData<T = unknown>(_id: string): T;
|
|
15
15
|
export declare function useCatalog(_items: ResolvedNavItem[], _config: CatalogConfig): FilteredCatalog;
|
|
16
|
-
export {};
|
|
16
|
+
export { useGlobalData } from '../useGlobalData';
|
package/lib/mocks/hooks/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useCatalog = exports.usePageSharedData = exports.useSidebarSiblingsData = exports.useThemeConfig = void 0;
|
|
3
|
+
exports.useGlobalData = exports.useCatalog = exports.usePageSharedData = exports.useSidebarSiblingsData = exports.useThemeConfig = void 0;
|
|
4
4
|
function useThemeConfig() {
|
|
5
5
|
return {
|
|
6
6
|
search: {
|
|
@@ -69,4 +69,6 @@ function useCatalog(_items, _config) {
|
|
|
69
69
|
throw new Error('Mock not implemented yet.');
|
|
70
70
|
}
|
|
71
71
|
exports.useCatalog = useCatalog;
|
|
72
|
+
var useGlobalData_1 = require("../useGlobalData");
|
|
73
|
+
Object.defineProperty(exports, "useGlobalData", { enumerable: true, get: function () { return useGlobalData_1.useGlobalData; } });
|
|
72
74
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useGlobalData(): Record<string, unknown>;
|
package/package.json
CHANGED
package/src/Button/Button.tsx
CHANGED
|
@@ -67,10 +67,14 @@ export const baseButtonStyles = css`
|
|
|
67
67
|
}
|
|
68
68
|
`;
|
|
69
69
|
|
|
70
|
-
const StyledButton = styled.button.attrs(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
70
|
+
const StyledButton = styled.button.attrs(
|
|
71
|
+
({ color = 'default', extraClass, variant }: ButtonProps) => ({
|
|
72
|
+
className: `button-color-${color}${variant ? ` button-variant-${variant}` : ''}${
|
|
73
|
+
extraClass ? ` ${extraClass}` : ''
|
|
74
|
+
}`,
|
|
75
|
+
'data-component-name': 'Button/Button',
|
|
76
|
+
}),
|
|
77
|
+
)<ButtonProps>`
|
|
74
78
|
text-decoration: none;
|
|
75
79
|
text-align: center;
|
|
76
80
|
|
package/src/Catalog/Filter.tsx
CHANGED
|
@@ -8,7 +8,7 @@ export function Filter({ filter }: { filter: ResolvedFilter }) {
|
|
|
8
8
|
if (!filter.parentUsed) return null;
|
|
9
9
|
return (
|
|
10
10
|
<FilterGroup key={filter.property + filter.title}>
|
|
11
|
-
<FilterTitle>{filter.title}
|
|
11
|
+
<FilterTitle>{filter.title}</FilterTitle>
|
|
12
12
|
{filter.type === 'select' ? (
|
|
13
13
|
<StyledSelect
|
|
14
14
|
onChange={(e) => filter.selectOption(e.target.value)}
|
|
@@ -9,6 +9,7 @@ interface AdmonitionTypeProps {
|
|
|
9
9
|
|
|
10
10
|
export interface AdmonitionProps extends Partial<AdmonitionTypeProps> {
|
|
11
11
|
name?: string;
|
|
12
|
+
className?: string;
|
|
12
13
|
'data-source'?: string;
|
|
13
14
|
'data-hash'?: string;
|
|
14
15
|
}
|
|
@@ -17,12 +18,14 @@ export function Admonition({
|
|
|
17
18
|
type = 'info',
|
|
18
19
|
name,
|
|
19
20
|
children,
|
|
21
|
+
className,
|
|
20
22
|
'data-source': dataSource,
|
|
21
23
|
'data-hash': dataHash,
|
|
22
24
|
}: React.PropsWithChildren<AdmonitionProps>): JSX.Element {
|
|
23
25
|
return (
|
|
24
26
|
<Wrapper
|
|
25
27
|
type={type}
|
|
28
|
+
className={className}
|
|
26
29
|
data-component-name="Markdown/Admonition"
|
|
27
30
|
data-source={dataSource}
|
|
28
31
|
data-hash={dataHash}
|
package/src/Profile/Profile.tsx
CHANGED
|
@@ -10,7 +10,7 @@ export interface ProfileProps {
|
|
|
10
10
|
onClick?: () => void;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
function ProfileComponent({ name, imageUrl, onClick, color }: ProfileProps): JSX.Element {
|
|
13
|
+
function ProfileComponent({ name = 'User', imageUrl, onClick, color }: ProfileProps): JSX.Element {
|
|
14
14
|
if (imageUrl) {
|
|
15
15
|
return (
|
|
16
16
|
<ProfileWrapper onClick={onClick}>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
// FIXME!!!
|
|
5
|
+
|
|
6
|
+
interface ClearButtonProps {
|
|
7
|
+
className?: string;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
handleClear?: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const ClearButtonComponent = ({ className, style, handleClear }: ClearButtonProps): JSX.Element => (
|
|
13
|
+
<button className={className} style={style} onClick={handleClear}>
|
|
14
|
+
✕
|
|
15
|
+
</button>
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export const ClearButton = styled(memo<ClearButtonProps>(ClearButtonComponent))`
|
|
19
|
+
z-index: 1;
|
|
20
|
+
position: absolute;
|
|
21
|
+
right: 24px;
|
|
22
|
+
top: 50%;
|
|
23
|
+
transform: translateY(-50%);
|
|
24
|
+
color: #89949f;
|
|
25
|
+
background: none;
|
|
26
|
+
border: none;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
|
|
29
|
+
&:hover {
|
|
30
|
+
color: #fff;
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Button } from '@theme';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
import type { TryItSecurityAppsProps } from './TryItSecurityApps';
|
|
6
|
+
|
|
7
|
+
import { usePageData } from '@portal/hooks/usePageData';
|
|
8
|
+
|
|
9
|
+
import { Dropdown } from './Dropdown';
|
|
10
|
+
|
|
11
|
+
export function DevOnboardingTryItSecurity(props: TryItSecurityAppsProps) {
|
|
12
|
+
const apiId = (props as any).apiId;
|
|
13
|
+
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
const { userData } = usePageData('userData') || {};
|
|
16
|
+
|
|
17
|
+
// TODO: handle error
|
|
18
|
+
const [_error, setError] = React.useState<string | undefined>();
|
|
19
|
+
const [apps, setApps] = React.useState<{ id: string; title: string }[] | undefined>();
|
|
20
|
+
const [appId, setAppId] = React.useState<string | undefined>('');
|
|
21
|
+
const [loading, setLoading] = React.useState(true);
|
|
22
|
+
const [appLoading, setAppLoading] = React.useState(false);
|
|
23
|
+
|
|
24
|
+
const [selectedAppSecret, setSelectedAppSecret] = React.useState<string | undefined>();
|
|
25
|
+
|
|
26
|
+
const [acceptValueUpdate, setAcceptValueUpdate] = React.useState(true);
|
|
27
|
+
const initialRender = React.useRef(true);
|
|
28
|
+
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
if (!props.value && initialRender.current) return;
|
|
31
|
+
if (acceptValueUpdate) {
|
|
32
|
+
setAcceptValueUpdate(false);
|
|
33
|
+
} else {
|
|
34
|
+
setAppId('');
|
|
35
|
+
}
|
|
36
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
37
|
+
}, [props.value]);
|
|
38
|
+
|
|
39
|
+
React.useEffect(() => {
|
|
40
|
+
initialRender.current = false;
|
|
41
|
+
const prevAppId = sessionStorage.getItem('redocly_onboarding:prevAppId');
|
|
42
|
+
if (prevAppId) {
|
|
43
|
+
setAppId(prevAppId);
|
|
44
|
+
}
|
|
45
|
+
if (userData?.isAuthenticated) {
|
|
46
|
+
fetch(`/api/api-keys/api-products/${apiId}/access?expand=1`).then((res) => {
|
|
47
|
+
return res
|
|
48
|
+
.json()
|
|
49
|
+
.then((data: any) => {
|
|
50
|
+
if (res.ok) {
|
|
51
|
+
setApps(data.apps);
|
|
52
|
+
} else {
|
|
53
|
+
setError(data.message);
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
.catch(() => setError('Something went wrong'))
|
|
57
|
+
.finally(() => setLoading(false));
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}, [apiId, userData?.isAuthenticated]);
|
|
61
|
+
|
|
62
|
+
React.useEffect(() => {
|
|
63
|
+
sessionStorage.setItem('redocly_onboarding:prevAppId', appId || '');
|
|
64
|
+
}, [appId]);
|
|
65
|
+
|
|
66
|
+
if (!apiId) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const loadAppCredentials = (appId: string) => {
|
|
71
|
+
setAppLoading(true);
|
|
72
|
+
fetch(`/api/api-keys/apps/${appId}`).then((res) => {
|
|
73
|
+
return res
|
|
74
|
+
.json()
|
|
75
|
+
.then((data: any) => {
|
|
76
|
+
if (res.ok) {
|
|
77
|
+
const cred = data.credentials.find((cred: any) => cred.status === 'approved');
|
|
78
|
+
setAcceptValueUpdate(true);
|
|
79
|
+
setSelectedAppSecret(cred.clientSecret);
|
|
80
|
+
} else {
|
|
81
|
+
setError(data.message);
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
.catch(() => setError('Something went wrong'))
|
|
85
|
+
.finally(() => setAppLoading(false));
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const placeholder = loading ? 'Loading your apps...' : undefined;
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<>
|
|
93
|
+
<FormLabel htmlFor="server">Select app: </FormLabel>
|
|
94
|
+
<FormControl>
|
|
95
|
+
<TryItDropdown
|
|
96
|
+
placeholder={placeholder}
|
|
97
|
+
value={appId || placeholder}
|
|
98
|
+
options={apps?.map((app) => ({ title: app.title, value: app.id })) || []}
|
|
99
|
+
fullWidth
|
|
100
|
+
onChange={({ value }: { value: string }) => {
|
|
101
|
+
setAppId(value);
|
|
102
|
+
loadAppCredentials(value);
|
|
103
|
+
}}
|
|
104
|
+
/>
|
|
105
|
+
<UseKeyButton
|
|
106
|
+
disabled={!selectedAppSecret || appLoading}
|
|
107
|
+
color="secondary"
|
|
108
|
+
blinking={appLoading}
|
|
109
|
+
onClick={() => selectedAppSecret && props.onChange(selectedAppSecret)}
|
|
110
|
+
>
|
|
111
|
+
Use key
|
|
112
|
+
</UseKeyButton>
|
|
113
|
+
</FormControl>
|
|
114
|
+
</>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const TryItDropdown = styled(Dropdown)`
|
|
119
|
+
.dropdown-select,
|
|
120
|
+
label {
|
|
121
|
+
background-color: var(--panel-try-it-dropdown-background-color);
|
|
122
|
+
border: var(--panel-try-it-dropdown-border);
|
|
123
|
+
color: var(--panel-try-it-dropdown-color);
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
const FormControl = styled.div`
|
|
128
|
+
width: 100%;
|
|
129
|
+
display: flex;
|
|
130
|
+
flex-direction: column;
|
|
131
|
+
margin-bottom: 10px;
|
|
132
|
+
|
|
133
|
+
&:last-child {
|
|
134
|
+
margin-bottom: 0;
|
|
135
|
+
}
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
const FormLabel = styled.label<{ required?: boolean }>`
|
|
139
|
+
padding-bottom: 6px;
|
|
140
|
+
display: block;
|
|
141
|
+
white-space: nowrap;
|
|
142
|
+
line-height: 1em;
|
|
143
|
+
|
|
144
|
+
${({ required }) =>
|
|
145
|
+
required &&
|
|
146
|
+
`
|
|
147
|
+
&:after {
|
|
148
|
+
display: inline-block;
|
|
149
|
+
content: '*';
|
|
150
|
+
margin-left: 4px;
|
|
151
|
+
color: var(--color-error-500);
|
|
152
|
+
}
|
|
153
|
+
`}
|
|
154
|
+
`;
|
|
155
|
+
|
|
156
|
+
const UseKeyButton = styled(Button)`
|
|
157
|
+
width: 100px;
|
|
158
|
+
align-self: flex-end;
|
|
159
|
+
margin-top: 16px;
|
|
160
|
+
margin-right: 0;
|
|
161
|
+
`;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import React, { memo, useMemo } from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
export interface DropdownOption {
|
|
5
|
+
idx?: number;
|
|
6
|
+
value: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
serverUrl?: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface DropdownProps {
|
|
13
|
+
options: DropdownOption[];
|
|
14
|
+
onChange: (option: DropdownOption) => void;
|
|
15
|
+
handleClear?: () => void;
|
|
16
|
+
clearable?: boolean;
|
|
17
|
+
ariaLabel?: string;
|
|
18
|
+
className?: string;
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
dense?: boolean;
|
|
22
|
+
fullWidth?: boolean;
|
|
23
|
+
variant?: 'dark' | 'light';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ArrowIconProps {
|
|
27
|
+
className?: string;
|
|
28
|
+
variant?: 'light' | 'dark';
|
|
29
|
+
style?: React.CSSProperties;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
import { ClearButton } from './ClearButton';
|
|
33
|
+
|
|
34
|
+
const ArrowSvg = ({ className, style }: ArrowIconProps): JSX.Element => (
|
|
35
|
+
<svg
|
|
36
|
+
className={className}
|
|
37
|
+
style={style}
|
|
38
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
39
|
+
width="16"
|
|
40
|
+
height="16"
|
|
41
|
+
viewBox="0 0 24 24"
|
|
42
|
+
fill="none"
|
|
43
|
+
stroke="currentColor"
|
|
44
|
+
strokeWidth="2"
|
|
45
|
+
strokeLinecap="round"
|
|
46
|
+
strokeLinejoin="round"
|
|
47
|
+
>
|
|
48
|
+
<polyline points="6 9 12 15 18 9" />
|
|
49
|
+
</svg>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const ArrowIcon = styled(ArrowSvg)`
|
|
53
|
+
position: absolute;
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
z-index: 1;
|
|
56
|
+
top: 50%;
|
|
57
|
+
-webkit-transform: translateY(-50%);
|
|
58
|
+
-ms-transform: translateY(-50%);
|
|
59
|
+
transform: translateY(-50%);
|
|
60
|
+
right: 8px;
|
|
61
|
+
margin: auto;
|
|
62
|
+
text-align: center;
|
|
63
|
+
polyline {
|
|
64
|
+
color: ${(props) => props.variant === 'dark' && 'white'};
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const DropdownComponent = ({
|
|
69
|
+
options,
|
|
70
|
+
onChange,
|
|
71
|
+
handleClear,
|
|
72
|
+
clearable,
|
|
73
|
+
placeholder,
|
|
74
|
+
value = '',
|
|
75
|
+
className,
|
|
76
|
+
variant = 'light',
|
|
77
|
+
}: DropdownProps): JSX.Element => {
|
|
78
|
+
const handleOnChange = (event: any) => {
|
|
79
|
+
const { selectedIndex } = event.target;
|
|
80
|
+
const index = placeholder || !value ? selectedIndex - 1 : selectedIndex;
|
|
81
|
+
onChange(options[index]);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const renderOptions = useMemo(
|
|
85
|
+
() =>
|
|
86
|
+
options.map(({ idx, value, title }: DropdownOption, index) => {
|
|
87
|
+
const normalizedValue = normalizeText(value);
|
|
88
|
+
return (
|
|
89
|
+
<option
|
|
90
|
+
key={idx || normalizedValue + index}
|
|
91
|
+
value={normalizedValue}
|
|
92
|
+
className="dropdown-option"
|
|
93
|
+
>
|
|
94
|
+
{title || normalizedValue}
|
|
95
|
+
</option>
|
|
96
|
+
);
|
|
97
|
+
}),
|
|
98
|
+
[options],
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const normalizedValue = normalizeText(value);
|
|
102
|
+
const title = options.find((option) => option.value === value)?.title || normalizedValue;
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<div className={className + ' dropdown-wrapper'}>
|
|
106
|
+
<ArrowIcon variant={variant} />
|
|
107
|
+
{clearable && normalizedValue?.length > 0 && <ClearButton handleClear={handleClear} />}
|
|
108
|
+
<select onChange={handleOnChange} value={normalizedValue} className="dropdown-select">
|
|
109
|
+
{placeholder && (
|
|
110
|
+
<option disabled hidden value={placeholder}>
|
|
111
|
+
{placeholder}
|
|
112
|
+
</option>
|
|
113
|
+
)}
|
|
114
|
+
{!normalizedValue && !placeholder && <option disabled />}
|
|
115
|
+
{renderOptions}
|
|
116
|
+
</select>
|
|
117
|
+
<label>{title}</label>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const Dropdown = styled(memo<DropdownProps>(DropdownComponent))`
|
|
123
|
+
|
|
124
|
+
box-sizing: border-box;
|
|
125
|
+
outline: none;
|
|
126
|
+
display: inline-block;
|
|
127
|
+
border-radius: var(--border-radius);
|
|
128
|
+
vertical-align: bottom;
|
|
129
|
+
position: relative;
|
|
130
|
+
width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')};
|
|
131
|
+
cursor: pointer;
|
|
132
|
+
text-transform: none;
|
|
133
|
+
|
|
134
|
+
label {
|
|
135
|
+
box-sizing: border-box;
|
|
136
|
+
min-width: 90px;
|
|
137
|
+
height: 36px;
|
|
138
|
+
outline: none;
|
|
139
|
+
display: inline-block;
|
|
140
|
+
color: var(--dropdown-text-color);
|
|
141
|
+
border-radius: var(--border-radius);
|
|
142
|
+
border: var(--dropdown-border);
|
|
143
|
+
padding: var(--dropdown-padding);
|
|
144
|
+
vertical-align: bottom;
|
|
145
|
+
width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')};
|
|
146
|
+
text-transform: none;
|
|
147
|
+
line-height: inherit;
|
|
148
|
+
font-size: var(--dropdown-font-size);
|
|
149
|
+
font-family: inherit;
|
|
150
|
+
text-overflow: ellipsis;
|
|
151
|
+
overflow: hidden;
|
|
152
|
+
white-space: nowrap;
|
|
153
|
+
|
|
154
|
+
&,
|
|
155
|
+
&:hover,
|
|
156
|
+
&:focus-within {
|
|
157
|
+
border: 1px solid var(--border-color);
|
|
158
|
+
box-shadow: none;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
${({ variant }) => (variant === 'dark' ? darkDropdownStyle : '')};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.dropdown-select {
|
|
165
|
+
position: absolute;
|
|
166
|
+
top: 0;
|
|
167
|
+
left: 0;
|
|
168
|
+
width: 100%;
|
|
169
|
+
height: 100%;
|
|
170
|
+
opacity: 0;
|
|
171
|
+
border: none;
|
|
172
|
+
appearance: none;
|
|
173
|
+
cursor: pointer;
|
|
174
|
+
|
|
175
|
+
color: var(--text-color);
|
|
176
|
+
line-height: inherit;
|
|
177
|
+
font-size: 14px;
|
|
178
|
+
font-family: inherit;
|
|
179
|
+
padding: var(--dropdown-padding);
|
|
180
|
+
${({ variant }) => (variant === 'dark' ? darkDropdownStyle : '')};
|
|
181
|
+
|
|
182
|
+
`;
|
|
183
|
+
|
|
184
|
+
const darkDropdownStyle = `
|
|
185
|
+
background-color: var(--panel-samples-dropdown-background-color);
|
|
186
|
+
border: var(--panel-samples-dropdown-border);
|
|
187
|
+
color: var(--panel-samples-dropdown-color);
|
|
188
|
+
|
|
189
|
+
&,
|
|
190
|
+
&:hover,
|
|
191
|
+
&:focus-within {
|
|
192
|
+
border: none;
|
|
193
|
+
box-shadow: none;
|
|
194
|
+
}
|
|
195
|
+
`;
|
|
196
|
+
|
|
197
|
+
function isString<T>(value: T | string): value is string {
|
|
198
|
+
return typeof value === 'string';
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export const normalizeText = (description?: string | Record<string, any>): string =>
|
|
202
|
+
isString(description) ? description : description?.raw;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useGlobalData } from '@portal/hooks';
|
|
4
|
+
|
|
5
|
+
import { DevOnboardingTryItSecurity } from './DevOnboardingTryItSecurity';
|
|
6
|
+
|
|
7
|
+
export type TryItSecurityAppsProps = {
|
|
8
|
+
apiId?: string;
|
|
9
|
+
value?: string;
|
|
10
|
+
onChange: (newSecretKey: string) => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function TryItSecurityApps(props: TryItSecurityAppsProps) {
|
|
14
|
+
const { hasDeveloperOnboarding } = useGlobalData() || {};
|
|
15
|
+
|
|
16
|
+
return hasDeveloperOnboarding && props.apiId ? <DevOnboardingTryItSecurity {...props} /> : null;
|
|
17
|
+
}
|