Skip to content

Commit

Permalink
feat(ui): Add option to generate an all access token
Browse files Browse the repository at this point in the history
  • Loading branch information
ischolten committed Apr 23, 2019
1 parent bc17af2 commit 0f01067
Show file tree
Hide file tree
Showing 11 changed files with 390 additions and 37 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
1. [13493](https://github.com/influxdata/influxdb/pull/13493): Add org profile tab with ability to edit organization name
1. [13510](https://github.com/influxdata/influxdb/pull/13510): Add org name to dahboard page title
1. [13520](https://github.com/influxdata/influxdb/pull/13520): Add cautioning to bucket renaming
1. [13560](https://github.com/influxdata/influxdb/pull/13560): Add option to generate all access token in tokens tab

### Bug Fixes

Expand Down
2 changes: 1 addition & 1 deletion ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 20 additions & 10 deletions ui/src/authorizations/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
// Libraries
import {Dispatch} from 'react'

// API
import {client} from 'src/utils/api'
import * as authAPI from 'src/authorizations/apis'

// Types
import {RemoteDataState, AppState} from 'src/types'
import {Authorization} from '@influxdata/influx'
import {Dispatch} from 'redux-thunk'

// Actions
import {notify} from 'src/shared/actions/notifications'

// Constants
import {
authorizationsGetFailed,
authorizationCreateFailed,
authorizationUpdateFailed,
authorizationDeleteFailed,
authorizationCreateSuccess,
} from 'src/shared/copy/v2/notifications'

// Types
import {RemoteDataState, GetState} from 'src/types'
import {Authorization} from '@influxdata/influx'
import {PublishNotificationAction} from 'src/types/actions/notifications'

export type Action =
| SetAuthorizations
| AddAuthorization
Expand Down Expand Up @@ -77,9 +82,13 @@ export const removeAuthorization = (id: string): RemoveAuthorization => ({
payload: {id},
})

type GetAuthorizations = (
dispatch: Dispatch<Action | PublishNotificationAction>,
getState: GetState
) => Promise<void>
export const getAuthorizations = () => async (
dispatch: Dispatch<Action>,
getState: () => AppState
dispatch: Dispatch<Action | PublishNotificationAction>,
getState: GetState
) => {
try {
dispatch(setAuthorizations(RemoteDataState.Loading))
Expand All @@ -98,11 +107,12 @@ export const getAuthorizations = () => async (
}

export const createAuthorization = (auth: Authorization) => async (
dispatch: Dispatch<Action>
dispatch: Dispatch<Action | PublishNotificationAction>
) => {
try {
const createdAuthorization = await authAPI.createAuthorization(auth)
dispatch(addAuthorization(createdAuthorization))
dispatch(notify(authorizationCreateSuccess()))
} catch (e) {
console.error(e)
dispatch(notify(authorizationCreateFailed()))
Expand All @@ -111,7 +121,7 @@ export const createAuthorization = (auth: Authorization) => async (
}

export const updateAuthorization = (authorization: Authorization) => async (
dispatch: Dispatch<Action>
dispatch: Dispatch<Action | PublishNotificationAction | GetAuthorizations>
) => {
try {
await client.authorizations.update(authorization.id, authorization)
Expand All @@ -124,7 +134,7 @@ export const updateAuthorization = (authorization: Authorization) => async (
}

export const deleteAuthorization = (id: string, name: string = '') => async (
dispatch: Dispatch<Action>
dispatch: Dispatch<Action | PublishNotificationAction>
) => {
try {
await client.authorizations.delete(id)
Expand Down
141 changes: 141 additions & 0 deletions ui/src/authorizations/components/AllAccessTokenOverlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React, {PureComponent, ChangeEvent} from 'react'
import {connect} from 'react-redux'

// Components
import {Overlay, Input, Form} from 'src/clockface'
import {
Alert,
IconFont,
ComponentColor,
ComponentSpacer,
AlignItems,
FlexDirection,
ComponentSize,
Button,
ButtonType,
} from '@influxdata/clockface'
import {withRouter, WithRouterProps} from 'react-router'

// Actions
import {createAuthorization} from 'src/authorizations/actions'

// Utils
import {allAccessPermissions} from 'src/authorizations/utils/permissions'

// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Authorization} from '@influxdata/influx'

interface DispatchProps {
onCreateAuthorization: typeof createAuthorization
}

interface State {
description: string
}

type Props = WithRouterProps & DispatchProps

@ErrorHandling
class AllAccessTokenOverlay extends PureComponent<Props, State> {
public state = {description: ''}

render() {
const {description} = this.state

return (
<Overlay visible={true}>
<Overlay.Container>
<Overlay.Heading
title="Generate All Access Token"
onDismiss={this.handleDismiss}
/>
<Overlay.Body>
<Form onSubmit={this.handleSave}>
<ComponentSpacer
alignItems={AlignItems.Center}
direction={FlexDirection.Column}
margin={ComponentSize.Large}
>
<Form.Element label="Description">
<Input
placeholder="Describe this new token"
value={description}
onChange={this.handleInputChange}
/>
</Form.Element>
<Alert
icon={IconFont.AlertTriangle}
color={ComponentColor.Warning}
>
This token will be able to create, update, delete, read, and
write to anything in this organization
</Alert>

<ComponentSpacer
alignItems={AlignItems.Center}
direction={FlexDirection.Row}
margin={ComponentSize.Small}
>
<Button
text="Cancel"
icon={IconFont.Remove}
onClick={this.handleDismiss}
/>

<Button
text="Save"
icon={IconFont.Checkmark}
color={ComponentColor.Success}
type={ButtonType.Submit}
/>
</ComponentSpacer>
</ComponentSpacer>
</Form>
</Overlay.Body>
</Overlay.Container>
</Overlay>
)
}

private handleSave = async () => {
const {
params: {orgID},
onCreateAuthorization,
} = this.props

const token: Authorization = {
orgID,
description: this.state.description,
permissions: allAccessPermissions(orgID),
}

await onCreateAuthorization(token)

this.handleDismiss()
}

private handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
const {value} = e.target

this.setState({description: value})
}

private handleDismiss = () => {
const {
router,
params: {orgID},
} = this.props

router.push(`/orgs/${orgID}/tokens`)
}
}

const mdtp: DispatchProps = {
onCreateAuthorization: createAuthorization,
}

export default connect<{}, DispatchProps, {}>(
null,
mdtp
)(withRouter(AllAccessTokenOverlay))
55 changes: 55 additions & 0 deletions ui/src/authorizations/components/GenerateTokenDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Libraries
import React, {PureComponent} from 'react'
import _ from 'lodash'

// Components
import {Dropdown, DropdownMode} from 'src/clockface'

// Types
import {IconFont, ComponentColor, ComponentSize} from '@influxdata/clockface'

interface OwnProps {
onSelectAllAccess: () => void
}

type Props = OwnProps

export default class GenerateTokenDropdown extends PureComponent<Props> {
public render() {
return (
<Dropdown
mode={DropdownMode.ActionList}
titleText="Generate"
icon={IconFont.Plus}
buttonColor={ComponentColor.Primary}
buttonSize={ComponentSize.Small}
widthPixels={160}
onChange={this.handleSelect}
>
{this.optionItems}
</Dropdown>
)
}

private get optionItems(): JSX.Element[] {
return [
<Dropdown.Item
id={this.allAccessOption}
key={this.allAccessOption}
value={this.allAccessOption}
>
{this.allAccessOption}
</Dropdown.Item>,
]
}

private get allAccessOption(): string {
return 'All Access Token'
}

private handleSelect = (selection: string): void => {
if (selection === this.allAccessOption) {
this.props.onSelectAllAccess()
}
}
}
20 changes: 18 additions & 2 deletions ui/src/authorizations/components/TokensTab.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// Libraries
import React, {PureComponent, ChangeEvent} from 'react'
import {connect} from 'react-redux'
import {withRouter, WithRouterProps} from 'react-router'

// Components
import {Input, Sort} from '@influxdata/clockface'
import TokenList from 'src/authorizations/components/TokenList'
import FilterList from 'src/shared/components/Filter'
import TabbedPageHeader from 'src/shared/components/tabbed_page/TabbedPageHeader'
import GenerateTokenDropdown from 'src/authorizations/components/GenerateTokenDropdown'

// Types
import {Authorization} from '@influxdata/influx'
Expand All @@ -32,7 +34,9 @@ interface StateProps {

type SortKey = keyof Authorization

class TokensTab extends PureComponent<StateProps, State> {
type Props = StateProps & WithRouterProps

class TokensTab extends PureComponent<Props, State> {
constructor(props) {
super(props)
this.state = {
Expand All @@ -57,6 +61,9 @@ class TokensTab extends PureComponent<StateProps, State> {
onChange={this.handleChangeSearchTerm}
widthPixels={256}
/>
<GenerateTokenDropdown
onSelectAllAccess={this.handleGenerateAllAccess}
/>
</TabbedPageHeader>
<FilterList<Authorization>
list={tokens}
Expand Down Expand Up @@ -90,11 +97,20 @@ class TokensTab extends PureComponent<StateProps, State> {
private get searchKeys(): AuthSearchKeys[] {
return [AuthSearchKeys.Status, AuthSearchKeys.Description]
}

private handleGenerateAllAccess = () => {
const {
router,
params: {orgID},
} = this.props

router.push(`/orgs/${orgID}/tokens/generate/all-access`)
}
}

const mstp = ({tokens}: AppState) => ({tokens: tokens.list})

export default connect<StateProps, {}, {}>(
mstp,
null
)(TokensTab)
)(withRouter(TokensTab))
Loading

0 comments on commit 0f01067

Please sign in to comment.