Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Last-minute pre-release fixes #375

Merged
21 commits merged into from
Apr 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cloudformation/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ Parameters:
Default: 'open'
AllowedValues:
- 'open'
- 'request'
# - 'request'
- 'invite'

Conditions:
Expand Down
4,789 changes: 2,042 additions & 2,747 deletions dev-portal/package-lock.json

Large diffs are not rendered by default.

9 changes: 0 additions & 9 deletions dev-portal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,6 @@
"devDependencies": {
"@testing-library/jest-dom": "^4.0.0",
"@testing-library/react": "^8.0.4",
"@typescript-eslint/eslint-plugin": "^2.21.0",
"@typescript-eslint/parser": "^2.21.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.8.0",
"eslint-plugin-flowtype": "^3.13.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-react-hooks": "^1.7.0",
"node-fetch": "^2.3.0",
"react-scripts": "^3.4.0"
}
Expand Down
4 changes: 2 additions & 2 deletions dev-portal/src/components/ApiSearch.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ export default function ApiSearch (props) {
// TODO: replace this with a customized search eventually. At the very least, the Swagger API
// fields shouldn't be here, and
const dataSet = useMemo(() => !store.apiList ? [] : [
...store.apiList.apiGateway.map(({ id, stage, swagger, usagePlan }) => ({
...store.apiList.apiGateway.map(({ id, apiStage: stage, swagger, usagePlan }) => ({
url: `/apis/${id}/${stage}`,
title: `${swagger.info.title} - ${stage}`,
stage: `${stage}`,
searchable: prepareSearch(`${JSON.stringify(swagger)} ${JSON.stringify(usagePlan)} ${stage}`).join(' ')
})),
...store.apiList.generic.map(({ id, swagger, stage }) => {
...store.apiList.generic.map(({ id, swagger, apiStage: stage }) => {
const api = {
url: `/apis/${id}`,
title: stage ? `${swagger.info.title} - ${stage}` : `${swagger.info.title}`,
Expand Down
36 changes: 19 additions & 17 deletions dev-portal/src/components/ApisMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,26 @@ import MenuLink from 'components/MenuLink'

function getApisWithStages (selectedApiId, selectedStage, activateFirst) {
const apiGatewayApiList = _.get(store, 'apiList.apiGateway', []).map(api => ({
group: api.id,
id: api.stage,
group: api.apiId,
id: api.apiStage,
title: api.swagger.info.title,
route: `/apis/${api.id}/${api.stage}`,
route: `/apis/${api.apiId}/${api.apiStage}`,
active: (
(selectedApiId && api.id === selectedApiId) &&
(!selectedStage || api.stage === selectedStage)
(selectedApiId && api.apiId === selectedApiId) &&
(!selectedStage || api.apiStage === selectedStage)
),
stage: api.stage
stage: api.apiStage
}))
const genericApiList = _.get(store, 'apiList.generic', []).map(api => ({
group: api.apiId || api.id,
id: api.stage || api.id,
id: api.apiStage || api.id,
title: api.swagger.info.title,
route: `/apis/${api.id}`,
active: (
(selectedApiId && (api.id === selectedApiId || api.apiId === selectedApiId)) &&
(!selectedStage || api.stage === selectedStage)
(!selectedStage || api.apiStage === selectedStage)
),
stage: api.stage
stage: api.apiStage
}))

return _.toPairs(_.groupBy(apiGatewayApiList.concat(genericApiList), 'group'))
Expand Down Expand Up @@ -83,15 +83,17 @@ export default observer(function ApisMenu (props) {

<>
{apiGroupList.map(({ apis, title, group, active }) => (
<MenuLink key={group} active={active}>
<MenuLink key={group} active={active} to={apis[0].stage ? null : apis[0].route}>
{title}
<Menu.Menu>
{apis.map(({ route, stage, active, id }) => (
<MenuLink key={id} to={route} active={active} style={{ fontWeight: '400' }}>
{stage}
</MenuLink>
))}
</Menu.Menu>
{apis[0].stage ? (
<Menu.Menu>
{apis.map(({ route, stage, active, id }) => (
<MenuLink key={id} to={route} active={active} style={{ fontWeight: '400' }}>
{stage}
</MenuLink>
))}
</Menu.Menu>
) : null}
</MenuLink>
))}
</>
Expand Down
33 changes: 16 additions & 17 deletions dev-portal/src/components/GetSdk.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { apiGatewayClient } from 'services/api'
import { apiGatewayClientWithCredentials } from 'services/api'
import { store } from 'services/state'

import React from 'react'
Expand Down Expand Up @@ -439,38 +439,36 @@ const exportTypes = [
*
*/

function fetchBlob ({ blobType, endpointName, sdkType, exportType, parameters }) {
function fetchBlob ({ blobType, endpointName, sdkType, exportType, ext, parameters }) {
const apiId = store.api.apiId || store.api.id
const stageName = store.api.stage
const stageName = store.api.apiStage

store.api.downloadingSdkOrApi = true

return apiGatewayClient()
return apiGatewayClientWithCredentials()
.then(apiGatewayClient => apiGatewayClient.get(
`/catalog/${apiId}_${stageName}/${endpointName}`,
{ sdkType },
{},
{
queryParams: { exportType, parameters: JSON.stringify(parameters) }
// leaving this as a comment so we know how to switch to a file in the future
// config: { responseType: "blob" }
queryParams: { exportType, parameters: JSON.stringify(parameters) },
config: { responseType: 'blob' }
}
))
.then(({ data }) => {
downloadFile(data, `${apiId}_${stageName}-${sdkType || exportType}.zip`)
})
.catch(({ data } = {}) => {
addNotification({ header: `An error occurred while attempting to download the ${blobType}.`, content: data.message })
downloadFile(data, `${apiId}_${stageName}-${sdkType || exportType}${ext}`)
})
.catch(({ data }) => data.text().then(text => {
const result = JSON.parse(text)
addNotification({ header: `An error occurred while attempting to download the ${blobType}.`, content: result && result.message })
}))
.finally(() => {
store.api.downloadingSdkOrApi = false
})
}

function downloadFile (dataUri, fileName) {
// leaving this as a comment so we know how to switch to a file in the future
// const reader = new FileReader()
// reader.onloadend = () => {
function downloadFile (blob, fileName) {
const dataUri = URL.createObjectURL(blob)
const downloadLinkElement = document.createElement('a')
downloadLinkElement.setAttribute('href', dataUri)
downloadLinkElement.setAttribute('download', fileName)
Expand All @@ -479,14 +477,14 @@ function downloadFile (dataUri, fileName) {
document.body.appendChild(downloadLinkElement)
downloadLinkElement.click()
document.body.removeChild(downloadLinkElement)
// }
// reader.readAsDataURL(data)
URL.revokeObjectURL(dataUri)
}

function getSdk (sdkType, parameters = {}) {
return fetchBlob({
blobType: 'SDK',
endpointName: 'sdk',
ext: '.zip',
sdkType,
parameters
})
Expand All @@ -509,6 +507,7 @@ function getExport (exportType, parameters = {}) {
return fetchBlob({
blobType: 'API export',
endpointName: 'export',
ext: '.json',
exportType,
parameters
})
Expand Down
54 changes: 33 additions & 21 deletions dev-portal/src/components/SwaggerUiLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import React from 'react'
// semantic-ui
import { Button, Header, Image, Container } from 'semantic-ui-react'

// markdown for external docs description
import Markdown from 'react-markdown/with-html'

// services
import { subscribe, unsubscribe } from 'services/api-catalog'
import { isAuthenticated } from 'services/self'
Expand All @@ -25,9 +28,21 @@ export const SwaggerLayoutPlugin = () => ({ components: { InfoContainer: InfoRep
// Note: this is called not as a component, but as a function within a class component. Do
// *not* make this a component, and do *not* use hooks or anything similar in it.
function InfoReplacement ({ specSelectors }) {
const basePath = specSelectors.basePath()
const host = specSelectors.host()
let endpoint
if (specSelectors.hasHost()) {
endpoint = `https://${specSelectors.host()}${specSelectors.basePath()}`
} else {
const servers = specSelectors.servers()
if (servers && servers.size) endpoint = servers.getIn([0, 'url'])
}

const info = specSelectors.info()
const version = specSelectors.version()
const externalDocs = specSelectors.externalDocs()
const apiTitle = info.get('title')
const apiDescription = info.get('description')
const docsDescription = externalDocs.get('description')
const docsUrl = externalDocs.get('url')

return <Observer>
{() => <Container fluid textAlign='left' className='fixfloat' style={{ padding: '40px 0px' }}>
Expand All @@ -36,30 +51,27 @@ function InfoReplacement ({ specSelectors }) {
<Image size='small' src={store.api.logo} />
</div>
<div>
<Header as='h1'>{store.api.swagger.info.title}</Header>
<div style={{ display: 'flex' }}>
<Header as='h1'>{apiTitle}</Header>
<div style={{ display: 'flex', paddingBottom: '1em' }}>
<div style={{ marginRight: '20px' }}>
{store.api.generic && (
<p style={{ fontWeight: 'bold' }}>Version</p>
)}
<p style={{ fontWeight: 'bold' }}>Endpoint</p>
{store.api.swagger.info.description ? (
<p style={{ fontWeight: 'bold' }}>Description</p>
) : null}
{store.api.apiStage == null ? <p style={{ fontWeight: 'bold' }}>Version</p> : null}
{endpoint ? <p style={{ fontWeight: 'bold' }}>Endpoint</p> : null}
{apiDescription ? <p style={{ fontWeight: 'bold' }}>Description</p> : null}
{/* <p style={{ fontWeight: "bold" }}>Usage Plan</p> */}
</div>
<div>
{store.api.generic && (
<p>{store.api.swagger.info.version}</p>
)}
<p>https://{host}{basePath}</p>
{store.api.swagger.info.description ? (
<p>{store.api.swagger.info.description}</p>
) : null}
{store.api.apiStage == null ? <p>{version}</p> : null}
{endpoint ? <p>{endpoint}</p> : null}
{apiDescription ? <p>{apiDescription}</p> : null}
{/* <p>{store.api.usagePlan.name}</p> */}
</div>
</div>
<p>{externalDocs}</p>
{externalDocs ? (
<div style={{ paddingBottom: '1em' }}>
{docsDescription ? <Markdown source={docsDescription} /> : null}
<a href={docsUrl}>{docsUrl}</a>
</div>
) : null}
<SubscriptionButtons />
{store.api.sdkGeneration && <GetSdkButton />}
</div>
Expand All @@ -72,13 +84,13 @@ const SubscriptionButtons = observer(class SubscriptionButtons extends React.Com
render () {
const { api } = store
return (
(api && isAuthenticated()) ? !api.generic ? (
(api && isAuthenticated()) ? api.apiStage != null ? (
api.subscribed ? (
<Button onClick={() => unsubscribe(api.usagePlan.id)}>Unsubscribe</Button>
) : (
<Button onClick={() => subscribe(api.usagePlan.id)}>Subscribe</Button>
)
) : <Header as='h4' color='grey'>This version of the API is not configured to be subscribable from the portal. Please contact an admin for more details.</Header> : null
) : <Header style={{ marginTop: '0em' }} as='h4' color='grey'>This version of the API is not configured to be subscribable from the portal. Please contact an admin for more details.</Header> : null
)
}
})
Expand Down
6 changes: 3 additions & 3 deletions dev-portal/src/pages/Admin/Admin.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import PageWithSidebar from 'components/PageWithSidebar'
import RegisteredAccounts from 'pages/Admin/Accounts/RegisteredAccounts'
import AdminAccounts from 'pages/Admin/Accounts/AdminAccounts'
import PendingInvites from 'pages/Admin/Accounts/PendingInvites'
import PendingRequests from 'pages/Admin/Accounts/PendingRequests'
// import PendingRequests from 'pages/Admin/Accounts/PendingRequests'

function RedirectToApiManagement() {
function RedirectToApiManagement () {
return <Redirect to='/admin/apis' />
}

Expand All @@ -25,7 +25,7 @@ export class Admin extends Component {
<AdminRoute exact path='/admin/accounts' component={RegisteredAccounts} />
<AdminRoute exact path='/admin/accounts/admins' component={AdminAccounts} />
<AdminRoute exact path='/admin/accounts/invites' component={PendingInvites} />
<AdminRoute exact path='/admin/accounts/requests' component={PendingRequests} />
{/* <AdminRoute exact path='/admin/accounts/requests' component={PendingRequests} /> */}
</>
</PageWithSidebar>
</Router>
Expand Down
Loading