Introduce CheckServices component
parent
cd66eae659
commit
3d186b1f93
|
@ -82,11 +82,7 @@ class TimeMachine extends PureComponent<Props> {
|
|||
return [
|
||||
{
|
||||
name: 'Explore',
|
||||
headerButtons: [
|
||||
<div key="analyze" className="btn btn-primary btn-xs">
|
||||
Analyze
|
||||
</div>,
|
||||
],
|
||||
headerButtons: [],
|
||||
menuOptions: [],
|
||||
render: () => <SchemaExplorer />,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import {PureComponent, ReactChildren} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {withRouter, WithRouterProps} from 'react-router'
|
||||
import {Source} from 'src/types'
|
||||
|
||||
import * as actions from 'src/shared/actions/services'
|
||||
|
||||
interface Props {
|
||||
sources: Source[]
|
||||
children: ReactChildren
|
||||
fetchServicesAsync: actions.FetchServicesAsync
|
||||
}
|
||||
|
||||
export class CheckServices extends PureComponent<Props & WithRouterProps> {
|
||||
public async componentDidMount() {
|
||||
const source = this.props.sources.find(
|
||||
s => s.id === this.props.params.sourceID
|
||||
)
|
||||
|
||||
if (!source) {
|
||||
return
|
||||
}
|
||||
|
||||
await this.props.fetchServicesAsync(source)
|
||||
}
|
||||
|
||||
public render() {
|
||||
return this.props.children
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
fetchServicesAsync: actions.fetchServicesAsync,
|
||||
}
|
||||
|
||||
const mstp = ({sources}) => ({sources})
|
||||
|
||||
export default connect(mstp, mdtp)(withRouter(CheckServices))
|
|
@ -3,8 +3,9 @@ import {bindActionCreators} from 'redux'
|
|||
import {connect} from 'react-redux'
|
||||
import _ from 'lodash'
|
||||
|
||||
import TimeMachine from 'src/ifql/components/TimeMachine'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import CheckServices from 'src/ifql/containers/CheckServices'
|
||||
import TimeMachine from 'src/ifql/components/TimeMachine'
|
||||
import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts'
|
||||
import {InputArg, Handlers, DeleteFuncNodeArgs, Func} from 'src/types/ifql'
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
|
@ -16,6 +17,7 @@ import {builder, argTypes} from 'src/ifql/constants'
|
|||
|
||||
import {Notification} from 'src/types'
|
||||
import {Suggestion, FlatBody, Links} from 'src/types/ifql'
|
||||
import {Service} from 'src/types'
|
||||
|
||||
interface Status {
|
||||
type: string
|
||||
|
@ -24,6 +26,7 @@ interface Status {
|
|||
|
||||
interface Props {
|
||||
links: Links
|
||||
services: Service[]
|
||||
notify: (message: Notification) => void
|
||||
}
|
||||
|
||||
|
@ -76,39 +79,41 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
const {suggestions, script, data, body, status} = this.state
|
||||
|
||||
return (
|
||||
<IFQLContext.Provider value={this.handlers}>
|
||||
<KeyboardShortcuts onControlEnter={this.getTimeSeries}>
|
||||
<div className="page hosts-list-page">
|
||||
<div className="page-header full-width">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Time Machine</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<button
|
||||
className="btn btn-sm btn-primary"
|
||||
onClick={this.getTimeSeries}
|
||||
>
|
||||
Get Data!
|
||||
</button>
|
||||
<CheckServices>
|
||||
<IFQLContext.Provider value={this.handlers}>
|
||||
<KeyboardShortcuts onControlEnter={this.getTimeSeries}>
|
||||
<div className="page hosts-list-page">
|
||||
<div className="page-header full-width">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Time Machine</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<button
|
||||
className="btn btn-sm btn-primary"
|
||||
onClick={this.getTimeSeries}
|
||||
>
|
||||
Get Data!
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TimeMachine
|
||||
data={data}
|
||||
body={body}
|
||||
script={script}
|
||||
status={status}
|
||||
suggestions={suggestions}
|
||||
onAnalyze={this.handleAnalyze}
|
||||
onAppendFrom={this.handleAppendFrom}
|
||||
onAppendJoin={this.handleAppendJoin}
|
||||
onChangeScript={this.handleChangeScript}
|
||||
onSubmitScript={this.handleSubmitScript}
|
||||
/>
|
||||
</div>
|
||||
<TimeMachine
|
||||
data={data}
|
||||
body={body}
|
||||
script={script}
|
||||
status={status}
|
||||
suggestions={suggestions}
|
||||
onAnalyze={this.handleAnalyze}
|
||||
onAppendFrom={this.handleAppendFrom}
|
||||
onAppendJoin={this.handleAppendJoin}
|
||||
onChangeScript={this.handleChangeScript}
|
||||
onSubmitScript={this.handleSubmitScript}
|
||||
/>
|
||||
</div>
|
||||
</KeyboardShortcuts>
|
||||
</IFQLContext.Provider>
|
||||
</KeyboardShortcuts>
|
||||
</IFQLContext.Provider>
|
||||
</CheckServices>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -416,8 +421,8 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({links}) => {
|
||||
return {links: links.ifql}
|
||||
const mapStateToProps = ({links, services}) => {
|
||||
return {links: links.ifql, services}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import IFQLPage from 'src/ifql/containers/IFQLPage'
|
||||
import CheckServices from 'src/ifql/containers/CheckServices'
|
||||
|
||||
export {IFQLPage}
|
||||
export {IFQLPage, CheckServices}
|
||||
|
|
|
@ -35,7 +35,7 @@ import {
|
|||
} from 'src/kapacitor'
|
||||
import {AdminChronografPage, AdminInfluxDBPage} from 'src/admin'
|
||||
import {SourcePage, ManageSources} from 'src/sources'
|
||||
import {IFQLPage} from 'src/ifql/index'
|
||||
import {IFQLPage} from 'src/ifql'
|
||||
import NotFound from 'src/shared/components/NotFound'
|
||||
|
||||
import {getLinksAsync} from 'src/shared/actions/links'
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import {Source, Service} from 'src/types'
|
||||
import {getServices as getServicesAJAX} from 'src/shared/apis'
|
||||
import {notify} from './notifications'
|
||||
import {couldNotGetServices} from 'src/shared/copy/notifications'
|
||||
|
||||
export type Action =
|
||||
| ActionLoadServices
|
||||
|
@ -94,3 +97,16 @@ export const setActiveService = (
|
|||
service,
|
||||
},
|
||||
})
|
||||
|
||||
export type FetchServicesAsync = (source: Source) => (dispatch) => Promise<void>
|
||||
|
||||
export const fetchServicesAsync = (source: Source) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const services = await getServicesAJAX(source.links.services)
|
||||
dispatch(loadServices(services))
|
||||
} catch (err) {
|
||||
dispatch(notify(couldNotGetServices))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import AJAX from 'src/utils/ajax'
|
||||
import {AlertTypes} from 'src/kapacitor/constants'
|
||||
import {Kapacitor} from 'src/types'
|
||||
import {Kapacitor, Service} from 'src/types'
|
||||
|
||||
export function getSources() {
|
||||
return AJAX({
|
||||
|
@ -303,3 +303,17 @@ export const getQueryConfigAndStatus = (url, queries, tempVars = []) =>
|
|||
method: 'POST',
|
||||
data: {queries, tempVars},
|
||||
})
|
||||
|
||||
export const getServices = async (url: string): Promise<Service[]> => {
|
||||
try {
|
||||
const {data} = await AJAX({
|
||||
url,
|
||||
method: 'GET',
|
||||
})
|
||||
|
||||
return data
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -614,3 +614,9 @@ export const analyzeSuccess = {
|
|||
...defaultSuccessNotification,
|
||||
message: 'No errors found. Happy Happy Joy Joy!',
|
||||
}
|
||||
|
||||
// Service notifications
|
||||
export const couldNotGetServices = {
|
||||
...defaultErrorNotification,
|
||||
message: 'We could not get services',
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ const servicesReducer = (state = initialState, action: Action): Service[] => {
|
|||
|
||||
return newState
|
||||
}
|
||||
|
||||
case 'SET_ACTIVE_SERVICE': {
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
|
|
|
@ -13,7 +13,6 @@ const InfluxTableHead: SFC<{}> = (): ReactElement<
|
|||
<th className="source-table--connect-col" />
|
||||
<th>InfluxDB Connection</th>
|
||||
<th className="text-right" />
|
||||
<th>Services Connection</th>
|
||||
<th>
|
||||
Kapacitor Connection
|
||||
<QuestionMarkTooltip
|
||||
|
|
|
@ -45,7 +45,6 @@ class InfluxTableRow extends PureComponent<Props> {
|
|||
/>
|
||||
</Authorized>
|
||||
</td>
|
||||
<td>Services Connection</td>
|
||||
<td className="source-table--kapacitor">
|
||||
<KapacitorDropdown
|
||||
source={source}
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
import React, {PureComponent, ReactElement} from 'react'
|
||||
import {Link, withRouter, RouteComponentProps} from 'react-router'
|
||||
|
||||
import Dropdown from 'src/shared/components/Dropdown'
|
||||
import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized'
|
||||
|
||||
import {Source, Service} from 'src/types'
|
||||
import {SetActiveService} from 'src/shared/actions/services'
|
||||
|
||||
interface Props {
|
||||
source: Source
|
||||
services: Service[]
|
||||
setActiveService: SetActiveService
|
||||
deleteService: (service: Service) => void
|
||||
}
|
||||
|
||||
interface ServiceItem {
|
||||
text: string
|
||||
resource: string
|
||||
service: Service
|
||||
}
|
||||
|
||||
class ServiceDropdown extends PureComponent<
|
||||
Props & RouteComponentProps<any, any>
|
||||
> {
|
||||
public render() {
|
||||
const {source, router, setActiveService, deleteService} = this.props
|
||||
|
||||
if (this.isServicesEmpty) {
|
||||
return (
|
||||
<Authorized requiredRole={EDITOR_ROLE}>
|
||||
<Link
|
||||
to={`/sources/${source.id}/services/new`}
|
||||
className="btn btn-xs btn-default"
|
||||
>
|
||||
<span className="icon plus" /> Add Service Connection
|
||||
</Link>
|
||||
</Authorized>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Authorized
|
||||
requiredRole={EDITOR_ROLE}
|
||||
replaceWithIfNotAuthorized={this.UnauthorizedDropdown}
|
||||
>
|
||||
<Dropdown
|
||||
className="dropdown-260"
|
||||
buttonColor="btn-primary"
|
||||
buttonSize="btn-xs"
|
||||
items={this.serviceItems}
|
||||
onChoose={setActiveService}
|
||||
addNew={{
|
||||
url: `/sources/${source.id}/services/new`,
|
||||
text: 'Add Service Connection',
|
||||
}}
|
||||
actions={[
|
||||
{
|
||||
icon: 'pencil',
|
||||
text: 'edit',
|
||||
handler: item => {
|
||||
router.push(`${item.resource}/edit`)
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'trash',
|
||||
text: 'delete',
|
||||
handler: item => {
|
||||
deleteService(item.service)
|
||||
},
|
||||
confirmable: true,
|
||||
},
|
||||
]}
|
||||
selected={this.selected}
|
||||
/>
|
||||
</Authorized>
|
||||
)
|
||||
}
|
||||
|
||||
private get UnauthorizedDropdown(): ReactElement<HTMLDivElement> {
|
||||
return (
|
||||
<div className="source-table--service__view-only">{this.selected}</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get isServicesEmpty(): boolean {
|
||||
const {services} = this.props
|
||||
return !services || services.length === 0
|
||||
}
|
||||
|
||||
private get serviceItems(): ServiceItem[] {
|
||||
const {services, source} = this.props
|
||||
|
||||
return services.map(service => {
|
||||
return {
|
||||
text: service.name,
|
||||
resource: `/sources/${source.id}/services/${service.id}`,
|
||||
service,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private get activeService(): Service {
|
||||
return this.props.services.find(s => s.active)
|
||||
}
|
||||
|
||||
private get selected(): string {
|
||||
let selected = ''
|
||||
if (this.activeService) {
|
||||
selected = this.activeService.name
|
||||
} else {
|
||||
selected = this.serviceItems[0].text
|
||||
}
|
||||
|
||||
return selected
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter<Props>(ServiceDropdown)
|
|
@ -16,6 +16,7 @@ import cellEditorOverlay from 'src/dashboards/reducers/cellEditorOverlay'
|
|||
import overlayTechnology from 'src/shared/reducers/overlayTechnology'
|
||||
import dashTimeV1 from 'src/dashboards/reducers/dashTimeV1'
|
||||
import persistStateEnhancer from './persistStateEnhancer'
|
||||
import servicesReducer from 'src/shared/reducers/services'
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
...statusReducers,
|
||||
|
@ -28,6 +29,7 @@ const rootReducer = combineReducers({
|
|||
overlayTechnology,
|
||||
dashTimeV1,
|
||||
routing: routerReducer,
|
||||
services: servicesReducer,
|
||||
})
|
||||
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
|
||||
|
|
|
@ -32,4 +32,5 @@ export interface SourceLinks {
|
|||
databases: string
|
||||
annotations: string
|
||||
health: string
|
||||
services: string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue