Merge pull request #12244 from influxdata/org-view-overlays

Eradicate OrganizationView and begin eradicating GetOrgResources
pull/12253/head
Deniz Kusefoglu 2019-02-28 14:19:45 -08:00 committed by GitHub
commit 81ccdb3a2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 625 additions and 311 deletions

View File

@ -12,7 +12,7 @@ describe('Buckets', () => {
cy.wrap(body.org).as('org')
cy.wrap(bucket).as('bucket')
cy.fixture('routes').then(({orgs}) => {
cy.visit(`${orgs}/${id}/buckets_tab`)
cy.visit(`${orgs}/${id}/buckets`)
})
})
})

View File

@ -29,28 +29,41 @@ describe('Orgs', () => {
})
it('can delete an org', () => {
cy.createOrg().then(() => {
cy.get('.index-list--row').then(rows => {
const numOrgs = rows.length
cy.contains('Confirm').click({force: true})
cy.get('.index-list--row')
cy.createOrg()
.then(() => {
cy.getByTestID('table-row')
.its('length')
.should('eq', numOrgs - 1)
.should('eq', 2)
cy.getByTestID('table-row')
.last()
.trigger('mouseover')
.within(() => {
cy.getByTestID('delete-button')
.trigger('mouseover')
.click()
cy.getByTestID('confirmation-button').click()
})
})
.then(() => {
cy.getByTestID('table-row')
.its('length')
.should('eq', 1)
})
})
})
it('can update an org name', () => {
cy.createOrg().then(({body}) => {
const newName = 'new 🅱organization'
cy.visit(`${orgRoute}/${body.id}/member_tab`)
cy.visit(`${orgRoute}/${body.id}/members`)
cy.get('.renamable-page-title--title').click()
cy.get('.input-field')
.type(newName)
.type('{enter}')
cy.getByTestID('page-header').within(() => {
cy.getByTestID('input-field')
.type(newName)
.type('{enter}')
})
cy.visit('/organizations')

View File

@ -13,7 +13,7 @@ describe('Scrapers', () => {
cy.wrap(bucket).as('bucket')
cy.fixture('routes').then(({orgs}) => {
cy.visit(`${orgs}/${id}/scrapers_tab`)
cy.visit(`${orgs}/${id}/scrapers`)
})
})
})

View File

@ -6,7 +6,7 @@ describe('Variables', () => {
cy.signin().then(({body}) => {
cy.wrap(body.org).as('org')
cy.visit(`organizations/${body.org.id}/variables_tab`)
cy.visit(`organizations/${body.org.id}/variables`)
})
})

View File

@ -1,8 +1,7 @@
import {Template, SourceLinks, TemplateType, TemplateValueType} from 'src/types'
import {Source} from '@influxdata/influx'
import {Cell, Dashboard, Label} from 'src/types/v2'
import {Cell, Dashboard, Label, Task} from 'src/types/v2'
import {Links} from 'src/types/v2/links'
import {Task} from 'src/types/v2/tasks'
import {OnboardingStepProps} from 'src/onboarding/containers/OnboardingWizard'
import {WithRouterProps} from 'react-router'
import {ConfigurationState} from 'src/types/v2/dataLoaders'

View File

@ -88,6 +88,7 @@ class ConfirmationButton extends Component<Props, State> {
onClick={this.handleButtonClick}
icon={icon}
type={ButtonType.Button}
testID="delete-button"
/>
<div className={this.tooltipClassName}>
<div

View File

@ -23,13 +23,13 @@ exports[`ConfirmationButton interaction shows the tooltip when clicked 1`] = `
shape="none"
size="sm"
status="default"
testID="button"
testID="delete-button"
text="I am a dangerous button!"
type="button"
>
<button
className="button button-sm button-danger active"
data-testid="button"
data-testid="delete-button"
disabled={false}
onClick={[Function]}
tabIndex={0}

View File

@ -94,7 +94,7 @@ export default class ResourceListCard extends PureComponent<Props> {
return (
<div className="resource-list--meta-item">
<Link
to={`/organizations/${owner.id}/members_tab`}
to={`/organizations/${owner.id}/members`}
className="resource-list--owner"
>
{owner.name}

View File

@ -197,7 +197,7 @@ export default class DashboardsIndexTableRow extends PureComponent<Props> {
const ownerOrg = orgs.find(o => o.id === dashboard.orgID)
return (
<Link to={`/organizations/${dashboard.orgID}/members_tab`}>
<Link to={`/organizations/${dashboard.orgID}/members`}>
{ownerOrg.name}
</Link>
)

View File

@ -23,7 +23,6 @@ import TaskPage from 'src/tasks/containers/TaskPage'
import TasksPage from 'src/tasks/containers/TasksPage'
import TaskRunsPage from 'src/tasks/components/TaskRunsPage'
import OrganizationsIndex from 'src/organizations/containers/OrganizationsIndex'
import OrganizationView from 'src/organizations/containers/OrganizationView'
import OrgTaskPage from 'src/organizations/components/OrgTaskPage'
import OrgTaskEditPage from 'src/organizations/components/OrgTaskEditPage'
import OrgBucketIndex from 'src/organizations/containers/OrgBucketsIndex'
@ -39,6 +38,10 @@ import ConfigurationPage from 'src/configuration/components/ConfigurationPage'
import OrgDashboardsIndex from 'src/organizations/containers/OrgDashboardsIndex'
import OrgMembersIndex from 'src/organizations/containers/OrgMembersIndex'
import OrgTelegrafsIndex from 'src/organizations/containers/OrgTelegrafsIndex'
import OrgVariablesIndex from 'src/organizations/containers/OrgVariablesIndex'
import OrgScrapersIndex from 'src/organizations/containers/OrgScrapersIndex'
import OrgTasksIndex from 'src/organizations/containers/OrgTasksIndex'
import OrgTaskExportOverlay from 'src/organizations/components/OrgTaskExportOverlay'
import OnboardingWizardPage from 'src/onboarding/containers/OnboardingWizardPage'
@ -105,31 +108,35 @@ class Root extends PureComponent {
<Route path="organizations">
<IndexRoute component={OrganizationsIndex} />
<Route path=":orgID">
<Route path="tasks/new" component={OrgTaskPage} />
<Route
path="tasks_tab/new"
component={OrgTaskPage}
/>
<Route
path="tasks_tab/:id"
path="tasks/:id"
component={OrgTaskEditPage}
/>
<Route path="buckets" component={OrgBucketIndex} />
<Route
path="buckets_tab"
component={OrgBucketIndex}
/>
<Route
path="dashboards_tab"
path="dashboards"
component={OrgDashboardsIndex}
/>
<Route path="members" component={OrgMembersIndex} />
<Route
path="members_tab"
component={OrgMembersIndex}
/>
<Route
path="telegrafs_tab"
path="telegrafs"
component={OrgTelegrafsIndex}
/>
<Route path=":tab" component={OrganizationView} />
<Route
path="variables"
component={OrgVariablesIndex}
/>
<Route
path="scrapers"
component={OrgScrapersIndex}
/>
<Route path="tasks" component={OrgTasksIndex}>
<Route
path=":id/export"
component={OrgTaskExportOverlay}
/>
</Route>
</Route>
</Route>
<Route path="tasks">

View File

@ -67,7 +67,7 @@ class GettingStarted extends PureComponent<StateProps> {
const firstOrgID = orgs[0].id
return `/organizations/${firstOrgID}/telegrafs_tab`
return `/organizations/${firstOrgID}/telegrafs`
}
}

View File

@ -28,7 +28,7 @@ export default class UserDashboardList extends PureComponent<Props> {
<ul className="link-list">
{orgs.map(({id, name}) => (
<li key={id}>
<Link to={`/organizations/${id}/buckets_tab`}>{name}</Link>
<Link to={`/organizations/${id}/buckets`}>{name}</Link>
</li>
))}
</ul>

View File

@ -34,7 +34,7 @@ class CompletionAdvancedButton extends PureComponent<Props> {
const {router, orgs, onExit} = this.props
const id = _.get(orgs, '0.id', null)
if (id) {
router.push(`/organizations/${id}/buckets_tab`)
router.push(`/organizations/${id}/buckets`)
} else {
onExit()
}

View File

@ -0,0 +1,28 @@
import {Task, Organization} from 'src/types/v2'
import {client} from 'src/utils/api'
export enum ActionTypes {
GetTasks = 'GET_TASKS',
PopulateTasks = 'POPULATE_TASKS',
}
export type Actions = PopulateTasks
export interface PopulateTasks {
type: ActionTypes.PopulateTasks
payload: {tasks: Task[]}
}
export const populateTasks = (tasks: Task[]): PopulateTasks => ({
type: ActionTypes.PopulateTasks,
payload: {tasks},
})
export const getTasks = (org: Organization) => async dispatch => {
const tasks = await client.tasks.getAllByOrg(org.name)
const organization = await client.organizations.get(org.id)
const tasksWithOrg = tasks.map(t => ({...t, organization})) as Task[]
dispatch(populateTasks(tasksWithOrg))
}

View File

@ -20,7 +20,7 @@ import {
// Types
import {Organization} from '@influxdata/influx'
import {createOrg} from 'src/organizations/actions'
import {createOrg} from 'src/organizations/actions/orgs'
interface Props {
link: string

View File

@ -65,7 +65,7 @@ class OrgTaskEditPage extends PureComponent<
const {
params: {id, orgID},
} = this.props
await this.props.selectTaskByID(id, `/organizations/${orgID}/tasks_tab/`)
await this.props.selectTaskByID(id, `/organizations/${orgID}/tasks/`)
const {currentTask} = this.props
@ -134,7 +134,7 @@ class OrgTaskEditPage extends PureComponent<
private handleSave = () => {
const {params} = this.props
this.props.updateScript(`/organizations/${params.orgID}/tasks_tab/`)
this.props.updateScript(`/organizations/${params.orgID}/tasks/`)
}
private handleCancel = () => {

View File

@ -0,0 +1,55 @@
import React, {PureComponent} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
// Components
import ExportOverlay from 'src/shared/components/ExportOverlay'
// APIs
import {client} from 'src/utils/api'
import {Task} from '@influxdata/influx'
interface State {
task: Task
}
interface Props extends WithRouterProps {
params: {id: string; orgID: string}
}
class OrgTaskExportOverlay extends PureComponent<Props, State> {
public state = {task: null}
public async componentDidMount() {
const {
params: {id},
} = this.props
const task = await client.tasks.get(id)
console.log(task)
this.setState({task})
}
public render() {
const {task} = this.state
if (!task) {
return null
}
return (
<ExportOverlay
resourceName="Task"
resource={task}
onDismissOverlay={this.onDismiss}
/>
)
}
private onDismiss = () => {
const {
router,
params: {orgID},
} = this.props
router.push(`/organizations/${orgID}/tasks`)
}
}
export default withRouter(OrgTaskExportOverlay)

View File

@ -130,7 +130,7 @@ class OrgTaskPage extends PureComponent<
this.props.saveNewScript(
newScript,
taskOptions,
`/organizations/${params.orgID}/tasks_tab/`
`/organizations/${params.orgID}/tasks/`
)
}

View File

@ -138,7 +138,7 @@ class OrgTasksPage extends PureComponent<Props, State> {
private handleSelectTask = (task: Task) => {
const {selectTask, orgID} = this.props
selectTask(task, `/organizations/${orgID}/tasks_tab/${task.id}`)
selectTask(task, `/organizations/${orgID}/tasks/${task.id}`)
}
private get filteredTasks() {
@ -183,7 +183,7 @@ class OrgTasksPage extends PureComponent<Props, State> {
private handleCreateTask = () => {
const {router, orgID} = this.props
router.push(`/organizations/${orgID}/tasks_tab/new`)
router.push(`/organizations/${orgID}/tasks/new`)
}
private handleToggleImportOverlay = (): void => {

View File

@ -25,44 +25,44 @@ class OrganizationNavigation extends PureComponent<Props> {
<Tabs.Tab
title={'Members'}
id={'members'}
url={`${route}/members_tab`}
active={'members_tab' === tab}
url={`${route}/members`}
active={'members' === tab}
/>
<Tabs.Tab
title={'Buckets'}
id={'buckets'}
url={`${route}/buckets_tab`}
active={'buckets_tab' === tab}
url={`${route}/buckets`}
active={'buckets' === tab}
/>
<Tabs.Tab
title={'Dashboards'}
id={'dashboards'}
url={`${route}/dashboards_tab`}
active={'dashboards_tab' === tab}
url={`${route}/dashboards`}
active={'dashboards' === tab}
/>
<Tabs.Tab
title={'Tasks'}
id={'tasks'}
url={`${route}/tasks_tab`}
active={'tasks_tab' === tab}
url={`${route}/tasks`}
active={'tasks' === tab}
/>
<Tabs.Tab
title={'Telegraf'}
id={'telegrafs'}
url={`${route}/telegrafs_tab`}
active={'telegrafs_tab' === tab}
url={`${route}/telegrafs`}
active={'telegrafs' === tab}
/>
<Tabs.Tab
title={'Scrapers'}
id={'scrapers'}
url={`${route}/scrapers_tab`}
active={'scrapers_tab' === tab}
url={`${route}/scrapers`}
active={'scrapers' === tab}
/>
<Tabs.Tab
title={'Variables'}
id={'variables'}
url={`${route}/variables_tab`}
active={'variables_tab' === tab}
url={`${route}/variables`}
active={'variables' === tab}
/>
</Tabs.Nav>
)

View File

@ -17,7 +17,7 @@ import {ErrorHandling} from 'src/shared/decorators/errors'
// Types
import {Organization} from 'src/types/v2'
import {deleteOrg} from 'src/organizations/actions'
import {deleteOrg} from 'src/organizations/actions/orgs'
interface Props {
orgs: Organization[]
@ -48,7 +48,7 @@ class OrganizationsPageContents extends Component<Props> {
return orgs.map(o => (
<IndexList.Row key={o.id}>
<IndexList.Cell>
<Link to={`/organizations/${o.id}/members_tab`}>{o.name}</Link>
<Link to={`/organizations/${o.id}/members`}>{o.name}</Link>
</IndexList.Cell>
<IndexList.Cell revealOnHover={true} alignment={Alignment.Right}>
<ConfirmationButton

View File

@ -87,7 +87,7 @@ Object {
>
<button
class="button button-xs button-danger"
data-testid="button"
data-testid="delete-button"
tabindex="0"
title="Delete"
type="button"
@ -230,7 +230,7 @@ Object {
>
<button
class="button button-xs button-danger"
data-testid="button"
data-testid="delete-button"
tabindex="0"
title="Delete"
type="button"
@ -430,7 +430,7 @@ Object {
>
<button
class="button button-xs button-danger"
data-testid="button"
data-testid="delete-button"
tabindex="0"
title="Delete"
type="button"
@ -573,7 +573,7 @@ Object {
>
<button
class="button button-xs button-danger"
data-testid="button"
data-testid="delete-button"
tabindex="0"
title="Delete"
type="button"

View File

@ -2,29 +2,27 @@
import React, {Component} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
import {AppState} from 'src/types/v2'
// Components
import {ErrorHandling} from 'src/shared/decorators/errors'
import OrganizationNavigation from 'src/organizations/components/OrganizationNavigation'
import OrgHeader from 'src/organizations/containers/OrgHeader'
import {Tabs} from 'src/clockface'
import {Page} from 'src/pageLayout'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Bucket, Organization} from '@influxdata/influx'
import {client} from 'src/utils/api'
// Components
import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import TabbedPageSection from 'src/shared/components/tabbed_page/TabbedPageSection'
import Buckets from 'src/organizations/components/Buckets'
import GetOrgResources from 'src/organizations/components/GetOrgResources'
// Actions
import * as NotificationsActions from 'src/types/actions/notifications'
import * as notifyActions from 'src/shared/actions/notifications'
// Types
import {Bucket, Organization} from '@influxdata/influx'
import {client} from 'src/utils/api'
import {AppState} from 'src/types/v2'
const getBuckets = async (org: Organization) => {
return client.buckets.getAllByOrg(org.name)
}
@ -60,11 +58,11 @@ class OrgBucketsIndex extends Component<Props> {
<Page.Contents fullWidth={false} scrollable={true}>
<div className="col-xs-12">
<Tabs>
<OrganizationNavigation tab={'buckets_tab'} orgID={org.id} />
<OrganizationNavigation tab={'buckets'} orgID={org.id} />
<Tabs.TabContents>
<TabbedPageSection
id="org-view-tab--buckets"
url="buckets_tab"
url="buckets"
title="Buckets"
>
<GetOrgResources<Bucket>

View File

@ -1,28 +1,29 @@
// Libraries
import React, {Component} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
import {AppState, Dashboard} from 'src/types/v2'
// Components
import {ErrorHandling} from 'src/shared/decorators/errors'
import OrganizationNavigation from 'src/organizations/components/OrganizationNavigation'
import OrgHeader from 'src/organizations/containers/OrgHeader'
import {Tabs} from 'src/clockface'
import {Page} from 'src/pageLayout'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Organization} from '@influxdata/influx'
import {getDashboards} from 'src/organizations/apis'
// Components
import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import TabbedPageSection from 'src/shared/components/tabbed_page/TabbedPageSection'
import Dashboards from 'src/organizations/components/Dashboards'
import GetOrgResources from 'src/organizations/components/GetOrgResources'
//Actions
import * as NotificationsActions from 'src/types/actions/notifications'
import * as notifyActions from 'src/shared/actions/notifications'
import Dashboards from 'src/organizations/components/Dashboards'
// APIs
import {getDashboards} from 'src/organizations/apis'
// Types
import {Organization} from '@influxdata/influx'
import {AppState, Dashboard} from 'src/types/v2'
interface RouterProps {
params: {
@ -55,11 +56,11 @@ class OrgDashboardsIndex extends Component<Props> {
<Page.Contents fullWidth={false} scrollable={true}>
<div className="col-xs-12">
<Tabs>
<OrganizationNavigation tab={'dashboards_tab'} orgID={org.id} />
<OrganizationNavigation tab={'dashboards'} orgID={org.id} />
<Tabs.TabContents>
<TabbedPageSection
id="org-view-tab--dashboards"
url="dashboards_tab"
url="dashboards"
title="Dashboards"
>
<GetOrgResources<Dashboard>

View File

@ -7,7 +7,7 @@ import RenamablePageTitle from 'src/pageLayout/components/RenamablePageTitle'
import {Organization} from '@influxdata/influx'
import {AppState} from 'src/types/v2'
import {updateOrg} from 'src/organizations/actions'
import {updateOrg} from 'src/organizations/actions/orgs'
interface OwnProps {
orgID: string

View File

@ -1,28 +1,26 @@
import React, {Component} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
import {AppState} from 'src/types/v2'
import {ResourceOwner} from '@influxdata/influx'
// Components
import {ErrorHandling} from 'src/shared/decorators/errors'
import OrganizationNavigation from 'src/organizations/components/OrganizationNavigation'
import OrgHeader from 'src/organizations/containers/OrgHeader'
import {Tabs} from 'src/clockface'
import {Page} from 'src/pageLayout'
import Members from 'src/organizations/components/Members'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Organization} from '@influxdata/influx'
// Components
import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import TabbedPageSection from 'src/shared/components/tabbed_page/TabbedPageSection'
import GetOrgResources from 'src/organizations/components/GetOrgResources'
import Members from 'src/organizations/components/Members'
// APIs
import {client} from 'src/utils/api'
// Types
import {ResourceOwner} from '@influxdata/influx'
import {Organization} from '@influxdata/influx'
import {AppState} from 'src/types/v2'
interface RouterProps {
params: {
orgID: string
@ -59,11 +57,11 @@ class OrgMembersIndex extends Component<Props> {
<Page.Contents fullWidth={false} scrollable={true}>
<div className="col-xs-12">
<Tabs>
<OrganizationNavigation tab={'members_tab'} orgID={org.id} />
<OrganizationNavigation tab={'members'} orgID={org.id} />
<Tabs.TabContents>
<TabbedPageSection
id="org-view-tab--members"
url="members_tab"
url="members"
title="Members"
>
<GetOrgResources<ResourceOwner>

View File

@ -0,0 +1,130 @@
// Libraries
import React, {Component} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
// Components
import {Page} from 'src/pageLayout'
import {Tabs} from 'src/clockface'
import TabbedPageSection from 'src/shared/components/tabbed_page/TabbedPageSection'
import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import OrgHeader from 'src/organizations/containers/OrgHeader'
import OrganizationNavigation from 'src/organizations/components/OrganizationNavigation'
import GetOrgResources from 'src/organizations/components/GetOrgResources'
import Scrapers from 'src/organizations/components/Scrapers'
// APIs
import {client} from 'src/utils/api'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
// Actions
import * as NotificationsActions from 'src/types/actions/notifications'
import * as notifyActions from 'src/shared/actions/notifications'
// Types
import {Organization, ScraperTargetResponse, Bucket} from '@influxdata/influx'
import {AppState} from 'src/types/v2'
const getScrapers = async (): Promise<ScraperTargetResponse[]> => {
return await client.scrapers.getAll()
}
const getBuckets = async (org: Organization): Promise<Bucket[]> => {
return client.buckets.getAllByOrg(org.name)
}
interface RouterProps {
params: {
orgID: string
}
}
interface DispatchProps {
notify: NotificationsActions.PublishNotificationActionCreator
}
interface StateProps {
org: Organization
}
type Props = WithRouterProps & RouterProps & DispatchProps & StateProps
@ErrorHandling
class OrgScrapersIndex extends Component<Props> {
public render() {
const {org, notify} = this.props
return (
<Page titleTag={org.name}>
<OrgHeader orgID={org.id} />
<Page.Contents fullWidth={false} scrollable={true}>
<div className="col-xs-12">
<Tabs>
<OrganizationNavigation tab={'scrapers'} orgID={org.id} />
<Tabs.TabContents>
<TabbedPageSection
id="org-view-tab--scrapers"
url="scrapers"
title="Scrapers"
>
<GetOrgResources<ScraperTargetResponse>
organization={org}
fetcher={getScrapers}
>
{(scrapers, loading, fetch) => {
return (
<SpinnerContainer
loading={loading}
spinnerComponent={<TechnoSpinner />}
>
<GetOrgResources<Bucket>
organization={org}
fetcher={getBuckets}
>
{(buckets, loading) => (
<SpinnerContainer
loading={loading}
spinnerComponent={<TechnoSpinner />}
>
<Scrapers
scrapers={scrapers}
onChange={fetch}
orgName={org.name}
buckets={buckets}
notify={notify}
/>
</SpinnerContainer>
)}
</GetOrgResources>
</SpinnerContainer>
)
}}
</GetOrgResources>
</TabbedPageSection>
</Tabs.TabContents>
</Tabs>
</div>
</Page.Contents>
</Page>
)
}
}
const mstp = (state: AppState, props: Props) => {
const {orgs} = state
const org = orgs.find(o => o.id === props.params.orgID)
return {
org,
}
}
const mdtp: DispatchProps = {
notify: notifyActions.notify,
}
export default connect<StateProps, DispatchProps, {}>(
mstp,
mdtp
)(withRouter<{}>(OrgScrapersIndex))

View File

@ -0,0 +1,136 @@
import React, {Component} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
// Components
import {ErrorHandling} from 'src/shared/decorators/errors'
import OrganizationNavigation from 'src/organizations/components/OrganizationNavigation'
import OrgHeader from 'src/organizations/containers/OrgHeader'
import {Tabs} from 'src/clockface'
import {Page} from 'src/pageLayout'
import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import TabbedPageSection from 'src/shared/components/tabbed_page/TabbedPageSection'
import OrgTasksPage from 'src/organizations/components/OrgTasksPage'
//Actions
import {getTasks as getTasksAction} from 'src/organizations/actions/orgView'
// Types
import {Organization} from '@influxdata/influx'
import {AppState, Task} from 'src/types/v2'
import {RemoteDataState} from 'src/types'
interface RouterProps {
params: {
orgID: string
}
}
interface DispatchProps {
getTasks: typeof getTasksAction
}
interface StateProps {
org: Organization
tasks: Task[]
}
type Props = WithRouterProps & RouterProps & DispatchProps & StateProps
interface State {
loadingState: RemoteDataState
}
@ErrorHandling
class OrgTasksIndex extends Component<Props, State> {
public state = {
loadingState: RemoteDataState.NotStarted,
}
public componentDidMount = async () => {
this.setState({loadingState: RemoteDataState.Loading})
const {getTasks, org} = this.props
await getTasks(org)
this.setState({loadingState: RemoteDataState.Done})
}
public render() {
const {org} = this.props
return (
<>
<Page titleTag={org.name}>
<OrgHeader orgID={org.id} />
<Page.Contents fullWidth={false} scrollable={true}>
<div className="col-xs-12">
<Tabs>
<OrganizationNavigation tab={'tasks'} orgID={org.id} />
<Tabs.TabContents>
<TabbedPageSection
id="org-view-tab--tasks"
url="tasks"
title="Tasks"
>
{this.tasksPage}
</TabbedPageSection>
</Tabs.TabContents>
</Tabs>
</div>
</Page.Contents>
</Page>
{this.props.children}
</>
)
}
private get tasksPage() {
const {org, tasks, router} = this.props
const {loadingState} = this.state
return (
<SpinnerContainer
loading={loadingState}
spinnerComponent={<TechnoSpinner />}
>
<OrgTasksPage
tasks={tasks}
orgName={org.name}
orgID={org.id}
onChange={this.updateTasks}
router={router}
/>
</SpinnerContainer>
)
}
private updateTasks() {
const {getTasks, org} = this.props
getTasks(org)
}
}
const mstp = (state: AppState, props: Props): StateProps => {
const {
orgs,
orgView: {tasks},
} = state
const org = orgs.find(o => o.id === props.params.orgID)
return {
org,
tasks,
}
}
const mdtp: DispatchProps = {
getTasks: getTasksAction,
}
export default connect<StateProps, DispatchProps, {}>(
mstp,
mdtp
)(withRouter<{}>(OrgTasksIndex))

View File

@ -5,26 +5,24 @@ import {connect} from 'react-redux'
import {AppState} from 'src/types/v2'
// Components
import {ErrorHandling} from 'src/shared/decorators/errors'
import OrganizationNavigation from 'src/organizations/components/OrganizationNavigation'
import OrgHeader from 'src/organizations/containers/OrgHeader'
import {Tabs} from 'src/clockface'
import {Page} from 'src/pageLayout'
import Collectors from 'src/organizations/components/Collectors'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Bucket, Organization, Telegraf} from '@influxdata/influx'
import {client} from 'src/utils/api'
// Components
import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import TabbedPageSection from 'src/shared/components/tabbed_page/TabbedPageSection'
import GetOrgResources from 'src/organizations/components/GetOrgResources'
// Actions
import * as NotificationsActions from 'src/types/actions/notifications'
import * as notifyActions from 'src/shared/actions/notifications'
// Types
import {Bucket, Organization, Telegraf} from '@influxdata/influx'
import {client} from 'src/utils/api'
const getBuckets = async (org: Organization) => {
return client.buckets.getAllByOrg(org.name)
}
@ -63,11 +61,11 @@ class OrgTelegrafsIndex extends Component<Props> {
<Page.Contents fullWidth={false} scrollable={true}>
<div className="col-xs-12">
<Tabs>
<OrganizationNavigation tab={'telegrafs_tab'} orgID={org.id} />
<OrganizationNavigation tab={'telegrafs'} orgID={org.id} />
<Tabs.TabContents>
<TabbedPageSection
id="org-view-tab--telegrafs"
url="telegrafs_tab"
url="telegrafs"
title="Telegraf"
>
<GetOrgResources<Telegraf>

View File

@ -0,0 +1,83 @@
// Libraries
import React, {Component} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
// Components
import {ErrorHandling} from 'src/shared/decorators/errors'
import OrganizationNavigation from 'src/organizations/components/OrganizationNavigation'
import OrgHeader from 'src/organizations/containers/OrgHeader'
import {Tabs} from 'src/clockface'
import {Page} from 'src/pageLayout'
import TabbedPageSection from 'src/shared/components/tabbed_page/TabbedPageSection'
import Variables from 'src/organizations/components/Variables'
//Actions
import * as NotificationsActions from 'src/types/actions/notifications'
import * as notifyActions from 'src/shared/actions/notifications'
// Types
import {Organization} from '@influxdata/influx'
import {AppState} from 'src/types/v2'
interface RouterProps {
params: {
orgID: string
}
}
interface DispatchProps {
notify: NotificationsActions.PublishNotificationActionCreator
}
interface StateProps {
org: Organization
}
type Props = WithRouterProps & RouterProps & DispatchProps & StateProps
@ErrorHandling
class OrgVariablesIndex extends Component<Props> {
public render() {
const {org} = this.props
return (
<Page titleTag={org.name}>
<OrgHeader orgID={org.id} />
<Page.Contents fullWidth={false} scrollable={true}>
<div className="col-xs-12">
<Tabs>
<OrganizationNavigation tab={'variables'} orgID={org.id} />
<Tabs.TabContents>
<TabbedPageSection
id="org-view-tab--variables"
url="variables"
title="Variables"
>
<Variables org={org} />
</TabbedPageSection>
</Tabs.TabContents>
</Tabs>
</div>
</Page.Contents>
</Page>
)
}
}
const mstp = (state: AppState, props: Props) => {
const {orgs} = state
const org = orgs.find(o => o.id === props.params.orgID)
return {
org,
}
}
const mdtp: DispatchProps = {
notify: notifyActions.notify,
}
export default connect<StateProps, DispatchProps, {}>(
mstp,
mdtp
)(withRouter<{}>(OrgVariablesIndex))

View File

@ -1,171 +0,0 @@
// Libraries
import React, {PureComponent} from 'react'
import {WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
import _ from 'lodash'
// APIs
import {client} from 'src/utils/api'
// Actions
import {updateOrg} from 'src/organizations/actions'
import * as notifyActions from 'src/shared/actions/notifications'
// Components
import {Page} from 'src/pageLayout'
import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import TabbedPageSection from 'src/shared/components/tabbed_page/TabbedPageSection'
import Variables from 'src/organizations/components/Variables'
import OrgTasksPage from 'src/organizations/components/OrgTasksPage'
import Scrapers from 'src/organizations/components/Scrapers'
import GetOrgResources from 'src/organizations/components/GetOrgResources'
import OrganizationTabs from 'src/organizations/components/OrganizationTabs'
import OrgHeader from 'src/organizations/containers/OrgHeader'
// Types
import {AppState} from 'src/types/v2'
import {Bucket, Organization, ScraperTargetResponse} from '@influxdata/influx'
import * as NotificationsActions from 'src/types/actions/notifications'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
import {Task} from 'src/types/v2'
const getScrapers = async (): Promise<ScraperTargetResponse[]> => {
return await client.scrapers.getAll()
}
const getBuckets = async (org: Organization): Promise<Bucket[]> => {
return client.buckets.getAllByOrg(org.name)
}
const getTasks = async (org: Organization): Promise<Task[]> => {
const tasks = await client.tasks.getAllByOrg(org.name)
const mappedTasks = tasks.map(task => {
return {
...task,
organization: org,
}
})
return mappedTasks as Task[]
}
interface StateProps {
org: Organization
}
interface DispatchProps {
onUpdateOrg: typeof updateOrg
notify: NotificationsActions.PublishNotificationActionCreator
}
type Props = StateProps & WithRouterProps & DispatchProps
@ErrorHandling
class OrganizationView extends PureComponent<Props> {
public render() {
const {org, params, notify, router} = this.props
return (
<Page titleTag={org.name}>
<OrgHeader orgID={org.id} />
<Page.Contents fullWidth={false} scrollable={true}>
<div className="col-xs-12">
<OrganizationTabs
name={org.name}
activeTabUrl={params.tab}
orgID={org.id}
>
<TabbedPageSection
id="org-view-tab--tasks"
url="tasks_tab"
title="Tasks"
>
<GetOrgResources<Task> organization={org} fetcher={getTasks}>
{(tasks, loading, fetch) => (
<SpinnerContainer
loading={loading}
spinnerComponent={<TechnoSpinner />}
>
<OrgTasksPage
tasks={tasks}
orgName={org.name}
orgID={org.id}
onChange={fetch}
router={router}
/>
</SpinnerContainer>
)}
</GetOrgResources>
</TabbedPageSection>
<TabbedPageSection
id="org-view-tab--scrapers"
url="scrapers_tab"
title="Scrapers"
>
<GetOrgResources<ScraperTargetResponse>
organization={org}
fetcher={getScrapers}
>
{(scrapers, loading, fetch) => {
return (
<SpinnerContainer
loading={loading}
spinnerComponent={<TechnoSpinner />}
>
<GetOrgResources<Bucket>
organization={org}
fetcher={getBuckets}
>
{(buckets, loading) => (
<SpinnerContainer
loading={loading}
spinnerComponent={<TechnoSpinner />}
>
<Scrapers
scrapers={scrapers}
onChange={fetch}
orgName={org.name}
buckets={buckets}
notify={notify}
/>
</SpinnerContainer>
)}
</GetOrgResources>
</SpinnerContainer>
)
}}
</GetOrgResources>
</TabbedPageSection>
<TabbedPageSection
id="org-view-tab--variables"
url="variables_tab"
title="Variables"
>
<Variables org={org} />
</TabbedPageSection>
</OrganizationTabs>
</div>
</Page.Contents>
</Page>
)
}
}
const mstp = (state: AppState, props: WithRouterProps) => {
const {orgs} = state
const org = orgs.find(o => o.id === props.params.orgID)
return {
org,
}
}
const mdtp: DispatchProps = {
onUpdateOrg: updateOrg,
notify: notifyActions.notify,
}
export default connect<StateProps, DispatchProps, {}>(
mstp,
mdtp
)(OrganizationView)

View File

@ -13,7 +13,7 @@ import {Button, IconFont, ComponentColor} from '@influxdata/clockface'
import {OverlayTechnology} from 'src/clockface'
// Actions
import {createOrg, deleteOrg} from 'src/organizations/actions'
import {createOrg, deleteOrg} from 'src/organizations/actions/orgs'
// Types
import {Organization, Links} from 'src/types/v2'

View File

@ -0,0 +1,36 @@
import {
Variable,
Telegraf,
ScraperTargetResponse,
Bucket,
} from '@influxdata/influx'
import {Task} from 'src/types/v2'
import {Dashboard} from 'src/types'
import {ActionTypes, Actions} from 'src/organizations/actions/orgView'
export interface OrgViewState {
tasks: Task[]
telegrafs: Telegraf[]
scrapers: ScraperTargetResponse[]
variables: Variable[]
dashboards: Dashboard[]
buckets: Bucket[]
}
const defaultState: OrgViewState = {
tasks: [],
telegrafs: [],
scrapers: [],
variables: [],
dashboards: [],
buckets: [],
}
export default (state = defaultState, action: Actions): OrgViewState => {
switch (action.type) {
case ActionTypes.PopulateTasks:
return {...state, tasks: action.payload.tasks}
default:
return state
}
}

View File

@ -1,5 +1,5 @@
import {Organization} from '@influxdata/influx'
import {ActionTypes, Actions} from 'src/organizations/actions'
import {ActionTypes, Actions} from 'src/organizations/actions/orgs'
const defaultState = []

View File

@ -34,7 +34,7 @@ class PageHeader extends Component<Props> {
}
return (
<div className={this.className}>
<div className={this.className} data-testid="page-header">
<div className="page-header--container">{this.children}</div>
</div>
)

View File

@ -5,6 +5,7 @@ exports[`PageHeader matches snapshot in presentation mode 1`] = `""`;
exports[`PageHeader matches snapshot with minimal props 1`] = `
<div
className="page-header"
data-testid="page-header"
>
<div
className="page-header--container"

View File

@ -19,13 +19,17 @@ import {downloadTextFile} from 'src/shared/utils/download'
import 'src/shared/components/ExportOverlay.scss'
interface Props {
isVisible: boolean
onDismissOverlay: () => void
resource: object
resourceName: string
isVisible?: boolean
}
export default class ImportDashboardOverlay extends PureComponent<Props> {
export default class ExportOverlay extends PureComponent<Props> {
public static defaultProps: Partial<Props> = {
isVisible: true,
}
public render() {
const {isVisible, resourceName, onDismissOverlay, resource} = this.props
const options = {

View File

@ -45,10 +45,7 @@ interface State {
importContent: string
}
export default class ImportDashboardOverlay extends PureComponent<
Props,
State
> {
export default class ImportOverlay extends PureComponent<Props, State> {
public static defaultProps: Partial<Props> = {
successNotification: importSucceeded(),
failureNotification: importFailed(),

View File

@ -9,7 +9,7 @@ import {SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import {RemoteDataState} from 'src/types'
// Actions
import {getOrganizations} from 'src/organizations/actions'
import {getOrganizations} from 'src/organizations/actions/orgs'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'

View File

@ -17,6 +17,7 @@ import dashboardsReducer from 'src/dashboards/reducers/v2/dashboards'
import viewsReducer from 'src/dashboards/reducers/v2/views'
import {timeMachinesReducer} from 'src/timeMachine/reducers'
import orgsReducer from 'src/organizations/reducers/orgs'
import orgViewReducer from 'src/organizations/reducers/orgView'
import onboardingReducer from 'src/onboarding/reducers'
import noteEditorReducer from 'src/dashboards/reducers/v2/notes'
import dataLoadingReducer from 'src/dataLoaders/reducers'
@ -38,6 +39,7 @@ export const rootReducer = combineReducers<ReducerState>({
views: viewsReducer,
tasks: tasksReducer,
orgs: orgsReducer,
orgView: orgViewReducer,
me: meReducer,
onboarding: onboardingReducer,
noteEditor: noteEditorReducer,

View File

@ -15,19 +15,13 @@ import {
ComponentSize,
ComponentColor,
} from '@influxdata/clockface'
import {Task as TaskAPI, Organization} from '@influxdata/influx'
// Utils
import {downloadTextFile} from 'src/shared/utils/download'
import {Task as TaskAPI} from '@influxdata/influx'
import {Task} from 'src/types/v2'
// Constants
import {DEFAULT_TASK_NAME} from 'src/dashboards/constants'
import {IconFont} from 'src/clockface/types/index'
interface Task extends TaskAPI {
organization: Organization
}
interface Props {
task: Task
onActivate: (task: Task) => void
@ -155,8 +149,10 @@ export class TaskRow extends PureComponent<Props & WithRouterProps> {
}
private handleExport = () => {
const {task} = this.props
downloadTextFile(task.flux, `${task.name}.flux`)
const {router, task} = this.props
router.push(
`/organizations/${task.organization.id}/tasks/${task.id}/export`
)
}
private handleClone = () => {

View File

@ -6,7 +6,7 @@ import {shallow} from 'enzyme'
import TasksList from 'src/tasks/components/TasksList'
// Types
import {Task} from 'src/types/v2/tasks'
import {Task} from 'src/types/v2'
// Constants
import {tasks} from 'mocks/dummyData'

View File

@ -1,8 +1,10 @@
import {Action} from 'src/tasks/actions/v2'
import {Task} from 'src/types/v2'
import {TaskOptions, TaskSchedule} from 'src/utils/taskOptionsToFluxScript'
import {Run, LogEvent} from '@influxdata/influx'
//Types
import {Action} from 'src/tasks/actions/v2'
import {RemoteDataState} from '@influxdata/clockface'
import {Task} from 'src/types/v2'
export interface State {
newScript: string

View File

@ -37,6 +37,7 @@ import {OnboardingState} from 'src/onboarding/reducers'
import {ProtosState} from 'src/protos/reducers'
import {VariablesState} from 'src/variables/reducers'
import {Label} from 'src/types/v2/labels'
import {OrgViewState} from 'src/organizations/reducers/orgView'
export interface AppState {
VERSION: string
@ -51,6 +52,7 @@ export interface AppState {
tasks: TaskState
timeRange: TimeRange
orgs: Organization[]
orgView: OrgViewState
me: MeState
onboarding: OnboardingState
noteEditor: NoteEditorState

View File

@ -1,11 +1,9 @@
import {Task as TaskAPI, Organization, User} from '@influxdata/influx'
import {Label} from 'src/types/v2/labels'
import {Task as TaskAPI, Organization, User, Label} from '@influxdata/influx'
export interface Task extends Exclude<TaskAPI, 'labels'> {
labels: Label[]
organization: Organization
owner?: User
offset?: string
}
export const TaskStatus = TaskAPI.StatusEnum