feat: 懒加载接口

pull/103/head
bigfengyu 5 years ago
parent 4394f206ef
commit f7f6d05994

@ -3,6 +3,7 @@ export const addInterface = (itf: any, onResolved: any) => ({
interface: itf, interface: itf,
onResolved, onResolved,
}) })
export const addInterfaceSucceeded = (payload: any) => ({ export const addInterfaceSucceeded = (payload: any) => ({
type: 'INTERFACE_ADD_SUCCEEDED', type: 'INTERFACE_ADD_SUCCEEDED',
payload, payload,
@ -12,6 +13,21 @@ export const addInterfaceFailed = (message: any) => ({
message, message,
}) })
export const fetchInterface = (id: number, onResolved: any) => ({
type: 'INTERFACE_FETCH',
id,
onResolved,
})
export const fetchInterfaceSucceeded = (payload: any) => ({
type: 'INTERFACE_FETCH_SUCCEEDED',
payload,
})
export const fetchInterfaceFailed = (message: any) => ({
type: 'INTERFACE_FETCH_FAILED',
message,
})
export const updateInterface = (itf: any, onResolved: any) => ({ export const updateInterface = (itf: any, onResolved: any) => ({
type: 'INTERFACE_UPDATE', type: 'INTERFACE_UPDATE',
interface: itf, interface: itf,

@ -4,7 +4,7 @@ import InterfaceEditorToolbar from './InterfaceEditorToolbar'
import InterfaceSummary, { import InterfaceSummary, {
BODY_OPTION, BODY_OPTION,
REQUEST_PARAMS_TYPE, REQUEST_PARAMS_TYPE,
rptFromStr2Num rptFromStr2Num,
} from './InterfaceSummary' } from './InterfaceSummary'
import PropertyList from './PropertyList' import PropertyList from './PropertyList'
import MoveInterfaceForm from './MoveInterfaceForm' import MoveInterfaceForm from './MoveInterfaceForm'
@ -13,40 +13,35 @@ import { RootState } from 'actions/types'
import { lockInterface, unlockInterface } from 'actions/interface' import { lockInterface, unlockInterface } from 'actions/interface'
import { updateProperties } from 'actions/property' import { updateProperties } from 'actions/property'
import { updateInterface } from 'actions/interface' import { updateInterface } from 'actions/interface'
import Spin from '../../components/utils/Spin'
export const RequestPropertyList = (props: any) => { export const RequestPropertyList = (props: any) => {
return ( return <PropertyList scope="request" title="请求参数" label="请求" {...props} />
<PropertyList scope="request" title="请求参数" label="请求" {...props} />
)
} }
export const ResponsePropertyList = (props: any) => ( export const ResponsePropertyList = (props: any) => (
<PropertyList scope="response" title="响应内容" label="响应" {...props} /> <PropertyList scope="response" title="响应内容" label="响应" {...props} />
) )
type InterfaceEditorProps = { type InterfaceEditorProps = {
auth: any; auth: any
itf: any; itf: any
properties: any[]; mod: any
mod: any; repository: any
repository: any; lockInterface: typeof lockInterface
lockInterface: typeof lockInterface; unlockInterface: typeof unlockInterface
unlockInterface: typeof unlockInterface; updateInterface: typeof updateInterface
updateInterface: typeof updateInterface; updateProperties: typeof updateProperties
updateProperties: typeof updateProperties;
} }
type InterfaceEditorState = { type InterfaceEditorState = {
summaryState: any; summaryState: any
itf: any; itf: any
properties: any; properties: any
editable: boolean; editable: boolean
moveInterfaceDialogOpen: boolean; moveInterfaceDialogOpen: boolean
} }
// TODO 2.x 参考 MySQL Workbench 的字段编辑器 // TODO 2.x 参考 MySQL Workbench 的字段编辑器
// TODO 2.x 支持复制整个接口到其他模块、其他项目 // TODO 2.x 支持复制整个接口到其他模块、其他项目
class InterfaceEditor extends Component< class InterfaceEditor extends Component<InterfaceEditorProps, InterfaceEditorState> {
InterfaceEditorProps,
InterfaceEditorState
> {
static childContextTypes = { static childContextTypes = {
handleLockInterface: PropTypes.func.isRequired, handleLockInterface: PropTypes.func.isRequired,
handleUnlockInterface: PropTypes.func.isRequired, handleUnlockInterface: PropTypes.func.isRequired,
@ -68,15 +63,19 @@ class InterfaceEditor extends Component<
moveInterfaceDialogOpen: false, moveInterfaceDialogOpen: false,
} }
this.summaryStateChange = this.summaryStateChange.bind(this) this.summaryStateChange = this.summaryStateChange.bind(this)
// { itf: {}, properties: [] }
} }
static mapPropsToState(prevProps: any, prevStates: any = {}) { static mapPropsToState(prevProps: any, prevStates: any = {}) {
const { auth, itf, properties } = prevProps const { auth, itf } = prevProps
const editable = !!(itf.locker && itf.locker.id === auth.id)
return { return {
...prevStates, ...prevStates,
itf, itf,
properties: properties.map((property: any) => ({ ...property })), // 编辑模式下不替换 properties
editable: !!(itf.locker && itf.locker.id === auth.id), properties:
editable && prevStates.properties
? prevStates.properties
: itf.properties?.map((property: any) => ({ ...property })),
editable,
} }
} }
getChildContext() { getChildContext() {
@ -90,7 +89,8 @@ class InterfaceEditor extends Component<
componentWillReceiveProps(nextProps: any) { componentWillReceiveProps(nextProps: any) {
if ( if (
nextProps.itf.id === this.state.itf.id && nextProps.itf.id === this.state.itf.id &&
nextProps.itf.updatedAt === this.state.itf.updatedAt nextProps.itf.updatedAt === this.state.itf.updatedAt &&
this.state.properties !== undefined
) { ) {
return return
} }
@ -128,6 +128,9 @@ class InterfaceEditor extends Component<
stateChangeHandler={this.summaryStateChange} stateChangeHandler={this.summaryStateChange}
handleChangeInterface={this.handleChangeInterface} handleChangeInterface={this.handleChangeInterface}
/> />
{this.state.properties ? (
<>
<RequestPropertyList <RequestPropertyList
properties={this.state.properties} properties={this.state.properties}
auth={auth} auth={auth}
@ -150,6 +153,10 @@ class InterfaceEditor extends Component<
handleChangeProperty={this.handleChangeProperty} handleChangeProperty={this.handleChangeProperty}
handleDeleteMemoryProperty={this.handleDeleteMemoryProperty} handleDeleteMemoryProperty={this.handleDeleteMemoryProperty}
/> />
</>
) : (
<Spin />
)}
{this.state.moveInterfaceDialogOpen && ( {this.state.moveInterfaceDialogOpen && (
<MoveInterfaceForm <MoveInterfaceForm
@ -166,7 +173,7 @@ class InterfaceEditor extends Component<
} }
handleAddMemoryProperty = (property: any, cb: any) => { handleAddMemoryProperty = (property: any, cb: any) => {
this.handleAddMemoryProperties([property], cb) this.handleAddMemoryProperties([property], cb)
}; }
handleAddMemoryProperties = (properties: any, cb: any) => { handleAddMemoryProperties = (properties: any, cb: any) => {
const requestParamsType = this.state.summaryState.requestParamsType const requestParamsType = this.state.summaryState.requestParamsType
const rpt = rptFromStr2Num(requestParamsType) const rpt = rptFromStr2Num(requestParamsType)
@ -186,7 +193,7 @@ class InterfaceEditor extends Component<
cb(properties) cb(properties)
} }
}) })
}; }
handleDeleteMemoryProperty = (property: any, cb: any) => { handleDeleteMemoryProperty = (property: any, cb: any) => {
const properties = [...this.state.properties] const properties = [...this.state.properties]
const index = properties.findIndex(item => item.id === property.id) const index = properties.findIndex(item => item.id === property.id)
@ -209,7 +216,7 @@ class InterfaceEditor extends Component<
} }
}) })
} }
}; }
handleChangeProperty = (property: any) => { handleChangeProperty = (property: any) => {
const properties = [...this.state.properties] const properties = [...this.state.properties]
const index = properties.findIndex(item => item.id === property.id) const index = properties.findIndex(item => item.id === property.id)
@ -217,7 +224,7 @@ class InterfaceEditor extends Component<
properties.splice(index, 1, property) properties.splice(index, 1, property)
this.setState({ properties }) this.setState({ properties })
} }
}; }
handleChangeInterface = (newItf: any) => { handleChangeInterface = (newItf: any) => {
this.setState({ this.setState({
itf: { itf: {
@ -225,7 +232,7 @@ class InterfaceEditor extends Component<
...newItf, ...newItf,
}, },
}) })
}; }
handleSaveInterfaceAndProperties = (e: any) => { handleSaveInterfaceAndProperties = (e: any) => {
e.preventDefault() e.preventDefault()
const { itf } = this.state const { itf } = this.state
@ -241,33 +248,28 @@ class InterfaceEditor extends Component<
}, },
() => { () => {
/** empty */ /** empty */
} },
) )
updateProperties( updateProperties(this.state.itf.id, this.state.properties, this.state.summaryState, () => {
this.state.itf.id,
this.state.properties,
this.state.summaryState,
() => {
this.handleUnlockInterface() this.handleUnlockInterface()
})
} }
)
};
handleMoveInterface = () => { handleMoveInterface = () => {
this.setState({ this.setState({
moveInterfaceDialogOpen: true, moveInterfaceDialogOpen: true,
}) })
}; }
handleMoveInterfaceSubmit = () => { handleMoveInterfaceSubmit = () => {
/** empty */ /** empty */
}; }
handleLockInterface = () => { handleLockInterface = () => {
const { itf, lockInterface } = this.props const { itf, lockInterface } = this.props
lockInterface(itf.id) lockInterface(itf.id)
}; }
handleUnlockInterface = () => { handleUnlockInterface = () => {
const { itf, unlockInterface } = this.props const { itf, unlockInterface } = this.props
unlockInterface(itf.id) unlockInterface(itf.id)
}; }
} }
const mapStateToProps = (state: RootState) => ({ const mapStateToProps = (state: RootState) => ({
@ -281,7 +283,4 @@ const mapDispatchToProps = {
updateProperties, updateProperties,
updateInterface, updateInterface,
} }
export default connect( export default connect(mapStateToProps, mapDispatchToProps)(InterfaceEditor)
mapStateToProps,
mapDispatchToProps
)(InterfaceEditor)

@ -1,105 +0,0 @@
import React, { Component } from 'react'
import { PropTypes, connect, Link } from '../../family'
import { moveInterface } from '../../actions/interface'
const OP_MOVE = 1
const OP_COPY = 2
class MoveInterfaceForm extends Component {
static contextTypes = {
rmodal: PropTypes.instanceOf(Component),
onAddInterface: PropTypes.func.isRequired,
onUpdateInterface: PropTypes.func.isRequired
}
static propTypes = {
title: PropTypes.string.isRequired,
repository: PropTypes.object.isRequired,
itfId: PropTypes.number.isRequired,
moveInterface: PropTypes.func.isRequired
}
constructor (props) {
super(props)
const { repository } = props
let modId = 0
if (repository.modules.length > 0) {
modId = repository.modules[0].id
}
this.state = {
op: OP_MOVE, // 1 move, 2 copy
modId
}
}
render () {
const { rmodal } = this.context
const { repository } = this.props
const { modId, op } = this.state
return (
<section>
<div className='rmodal-header'>
<span className='rmodal-title'>{this.props.title}</span>
</div>
<form className='form-horizontal w600' onSubmit={this.handleSubmit} >
<div className='rmodal-body'>
<div className='form-group row'>
<label className='col-sm-2 control-label'>模块</label>
<div className='col-sm-10'>
<select className='form-control' onChange={e => { this.setState({ modId: +e.target.value }) }}>
{repository.modules.map(x => <option key={x.id} value={x.id} checked={x.id === modId}>{x.name}</option>)}
</select>
</div>
</div>
<div className='form-group row'>
<label className='col-sm-2 control-label'>选项</label>
<div className='col-sm-10'>
<div className='col-sm-10'>
<div className='form-check'>
<input className='form-check-input' type='radio' name='op' id='gridRadios1' value='1' checked={op === OP_MOVE} onChange={() => { this.setState({ op: OP_MOVE }) }} />
<label className='form-check-label' htmlFor='gridRadios1'> 移动 </label>
</div>
<div className='form-check'>
<input className='form-check-input' type='radio' name='op' id='gridRadios2' value='2' checked={op === OP_COPY} onChange={() => { this.setState({ op: OP_COPY }) }} />
<label className='form-check-label' htmlFor='gridRadios2'> 复制 </label>
</div>
</div>
</div>
</div>
<div className='rmodal-footer'>
<div className='form-group row mb0'>
<label className='col-sm-2 control-label' />
<div className='col-sm-10'>
<button type='submit' className='btn btn-success w140 mr20'>提交</button>
<Link to='' onClick={e => { e.preventDefault(); rmodal.close() }} className='mr10'>取消</Link>
</div>
</div>
</div>
</div>
</form>
</section>
)
}
componentDidUpdate () {
this.context.rmodal.reposition()
}
handleSubmit = (e) => {
e.preventDefault()
const params = {
modId: this.state.modId,
op: this.state.op,
itfId: this.props.itfId
}
this.props.moveInterface(params, () => {
let { rmodal } = this.context
if (rmodal) rmodal.resolve()
})
}
}
const mapStateToProps = (state) => ({
})
const mapDispatchToProps = ({
moveInterface
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(MoveInterfaceForm)

@ -155,15 +155,12 @@ class RepositoryEditor extends Component<Props, States> {
const mod: Module = const mod: Module =
repository && repository.modules && repository.modules.length repository && repository.modules && repository.modules.length
? repository.modules.find(item => item.id === +params.mod) || ? repository.modules.find(item => item.id === +params.mod) || repository.modules[0]
repository.modules[0] : ({} as Module)
: {} as Module
const itf: Interface = const itf: Interface =
mod.interfaces && mod.interfaces.length mod.interfaces && mod.interfaces.length
? mod.interfaces.find((item: any) => item.id === +params.itf) || ? mod.interfaces.find((item: any) => item.id === +params.itf) || mod.interfaces[0]
mod.interfaces[0] : ({} as Interface)
: {} as Interface
const properties = itf.properties || []
const ownerlink = repository.organization const ownerlink = repository.organization
? `/organization/repository?organization=${repository.organization.id}` ? `/organization/repository?organization=${repository.organization.id}`
@ -273,7 +270,7 @@ class RepositoryEditor extends Component<Props, States> {
<ModuleList mods={repository.modules} repository={repository} mod={mod} /> <ModuleList mods={repository.modules} repository={repository} mod={mod} />
<div className="InterfaceWrapper"> <div className="InterfaceWrapper">
<InterfaceList itfs={mod.interfaces} repository={repository} mod={mod} itf={itf} /> <InterfaceList itfs={mod.interfaces} repository={repository} mod={mod} itf={itf} />
<InterfaceEditor itf={itf} properties={properties} mod={mod} repository={repository} /> <InterfaceEditor itf={itf} mod={mod} repository={repository} />
</div> </div>
</div> </div>
</article > </article >

@ -23,12 +23,13 @@ class DropdownMenuBase extends Component<any, any> {
static contextTypes = { static contextTypes = {
store: PropTypes.object, store: PropTypes.object,
} }
static filter = (respository: any, seed: any) => { static filter = (respository: any, seed: string) => {
const nextRespository = { ...respository, modules: [] } const nextRespository = { ...respository, modules: [] }
let counter = 0 let counter = 0
seed = seed.toLowerCase()
respository.modules.forEach((mod: any) => { respository.modules.forEach((mod: any) => {
const nextModule = { ...mod, interfaces: [] } const nextModule = { ...mod, interfaces: [] }
let matchModule = nextModule.name.indexOf(seed) !== -1 let matchModule = nextModule.name.toLowerCase().indexOf(seed) !== -1
if (matchModule) { if (matchModule) {
counter++ counter++
nextRespository.modules.push(nextModule) nextRespository.modules.push(nextModule)
@ -36,7 +37,10 @@ class DropdownMenuBase extends Component<any, any> {
mod.interfaces.forEach((itf: any) => { mod.interfaces.forEach((itf: any) => {
const nextInterface = { ...itf, properties: [] } const nextInterface = { ...itf, properties: [] }
let matchInterface = nextInterface.name.indexOf(seed) !== -1 || nextInterface.url.indexOf(seed) !== -1 || nextInterface.method === seed const matchInterface =
nextInterface.name.toLowerCase().indexOf(seed) !== -1 ||
nextInterface.url.toLowerCase().indexOf(seed) !== -1 ||
nextInterface.method === seed
if (matchInterface) { if (matchInterface) {
counter++ counter++
if (!matchModule) { if (!matchModule) {
@ -46,22 +50,22 @@ class DropdownMenuBase extends Component<any, any> {
nextModule.interfaces.push(nextInterface) nextModule.interfaces.push(nextInterface)
} }
itf.properties.forEach((property: any) => { // itf.properties.forEach((property: any) => {
const nextProperty = { ...property } // const nextProperty = { ...property }
const matchProperty = nextProperty.name.indexOf(seed) !== -1 // const matchProperty = nextProperty.name.indexOf(seed) !== -1
if (matchProperty) { // if (matchProperty) {
counter++ // counter++
if (!matchModule) { // if (!matchModule) {
matchModule = true // matchModule = true
nextRespository.modules.push(nextModule) // nextRespository.modules.push(nextModule)
} // }
if (!matchInterface) { // if (!matchInterface) {
matchInterface = true // matchInterface = true
nextModule.interfaces.push(nextInterface) // nextModule.interfaces.push(nextInterface)
} // }
nextInterface.properties.push(nextProperty) // nextInterface.properties.push(nextProperty)
} // }
}) // })
}) })
}) })
return { nextRespository, counter } return { nextRespository, counter }
@ -123,16 +127,16 @@ interface IState {
// TODO 2.2 自动隐藏,高阶组件 // TODO 2.2 自动隐藏,高阶组件
class RepositorySearcher extends Component<any, IState> { class RepositorySearcher extends Component<any, IState> {
debouncedInput = AwesomeDebouncePromise((val: string) => this.setState({ result: val }), 300)
constructor(props: any) { constructor(props: any) {
super(props) super(props)
this.state = { seed: '', result: '' } this.state = { seed: '', result: '' }
this.debouncedInput = this.debouncedInput.bind(this)
} }
render() { render() {
const { repository } = this.props const { repository } = this.props
const { seed, result } = this.state const { seed, result } = this.state
const debouncedInput = AwesomeDebouncePromise((val: string) => this.setState({ result: val }), 500)
return ( return (
<div className="RepositorySearcher dropdown"> <div className="RepositorySearcher dropdown">
<input <input
@ -140,12 +144,12 @@ class RepositorySearcher extends Component<any, IState> {
onChange={e => { onChange={e => {
const val = e.target.value const val = e.target.value
this.setState({ seed: val }) this.setState({ seed: val })
debouncedInput(val) this.debouncedInput(val)
}} }}
className="dropdown-input form-control" className="dropdown-input form-control"
placeholder="工作区搜索" placeholder="工作区搜索"
/> />
{this.state.result && <DropdownMenu repository={repository} seed={result} onSelect={this.clearSeed} />} {result && <DropdownMenu repository={repository} seed={result} onSelect={this.clearSeed} />}
</div> </div>
) )
} }

@ -2,16 +2,11 @@ import { takeLatest } from 'redux-saga/effects'
import start from './start' import start from './start'
import handleLocation from './handleLocation' import handleLocation from './handleLocation'
import { createBrowserHistory as createHistory, History } from 'history' import { createBrowserHistory as createHistory, History } from 'history'
import { import { createStore, applyMiddleware, combineReducers, compose, Store } from 'redux'
createStore,
applyMiddleware,
combineReducers,
compose,
Store
} from 'redux'
import { import {
routerMiddleware as createRouterMiddleware, routerMiddleware as createRouterMiddleware,
connectRouter connectRouter,
LOCATION_CHANGE,
} from 'connected-react-router' } from 'connected-react-router'
import loggerMiddleware from './loggerMiddleware' import loggerMiddleware from './loggerMiddleware'
import createSagaMiddleware from 'redux-saga' import createSagaMiddleware from 'redux-saga'
@ -22,12 +17,11 @@ const _reducers: any = {} // { id/key: reducer }
const _prefilters: any[] = [] const _prefilters: any[] = []
const _sagas: any = {} // { pattern: [sagas] } const _sagas: any = {} // { pattern: [sagas] }
const _listeners: any = {} // { pathname: [listeners] } const _listeners: any = {} // { pathname: [listeners] }
// let _routes: any
const Family: { const Family: {
store?: Store; store?: Store
history?: History; history?: History
[k: string]: any; [k: string]: any
} = { } = {
store: undefined, store: undefined,
history: undefined, history: undefined,
@ -93,13 +87,6 @@ const Family: {
} }
return this return this
}, },
// setRoutes(routes: any) {
// if (!routes) {
// return this
// }
// _routes = routes
// return this
// },
start(container: any) { start(container: any) {
_relatives.forEach(({ reducers = {}, sagas = {}, listeners = {} }: any) => { _relatives.forEach(({ reducers = {}, sagas = {}, listeners = {} }: any) => {
this.addReducers(reducers) this.addReducers(reducers)
@ -126,22 +113,17 @@ const Family: {
: [routerMiddleware, sagaMiddleware] : [routerMiddleware, sagaMiddleware]
const store = createStore<any, any, any, any>( const store = createStore<any, any, any, any>(
combineReducers({ ..._reducers, router: connectRouter(history) }), combineReducers({ ..._reducers, router: connectRouter(history) }),
composeEnhancers(applyMiddleware(...middlewares)) composeEnhancers(applyMiddleware(...middlewares)),
) )
// 初始化当前页所需的数据 // 初始化当前页所需的数据
// @ts-ignore // @ts-ignore
history.location.params = URI(history.location.search || '').search(true) history.location.params = URI(history.location.search || '').search(true)
history.listen((location, action: any) =>
handleLocation({ store, listeners: _listeners, location, action })
)
Family.store = store Family.store = store
Family.history = history Family.history = history
/** init store end */ /** init store end */
function* rootSaga() { function* rootSaga() {
try { try {
for (const prefilter of _prefilters) { for (const prefilter of _prefilters) {
yield* prefilter({ store }) yield* prefilter({ store })
@ -153,11 +135,11 @@ const Family: {
// 在执行 prefilter 之后再开始渲染主UI // 在执行 prefilter 之后再开始渲染主UI
start(container, { store, history }) start(container, { store, history })
// handleLocation({ // 监听 connected-react-router 地质变化的 action 而不是用 hisory.listen 以防冲突
// store, yield takeLatest(LOCATION_CHANGE, (action: any) => {
// listeners: _listeners, handleLocation({ store, listeners: _listeners, location: action.payload.location })
// location: { pathname: '*' }, })
// })
handleLocation({ handleLocation({
store, store,
listeners: _listeners, listeners: _listeners,
@ -169,10 +151,8 @@ const Family: {
yield takeLatest(pattern, saga) yield takeLatest(pattern, saga)
} }
} }
} }
sagaMiddleware.run(rootSaga) sagaMiddleware.run(rootSaga)
}, },
} }

@ -14,7 +14,7 @@ export const PropTypes = _PropTypes
export { render, findDOMNode } from 'react-dom' // ReactDOM export { render, findDOMNode } from 'react-dom' // ReactDOM
export { connect, Provider } from 'react-redux' export { connect, Provider } from 'react-redux'
export { createStore, applyMiddleware, combineReducers, compose } from 'redux' export { createStore, applyMiddleware, combineReducers, compose } from 'redux'
export { BrowserRouter, HashRouter, NavLink, Link, Redirect, Router, Route, Switch } from 'react-router-dom' export { NavLink, Link, Redirect, Router, Route, Switch } from 'react-router-dom'
export { push, replace, go, goBack, goForward } from 'connected-react-router' export { push, replace, go, goBack, goForward } from 'connected-react-router'
export { call, put, take, takeLatest } from 'redux-saga/effects' export { call, put, take, takeLatest } from 'redux-saga/effects'
export { delay } from 'redux-saga/effects' export { delay } from 'redux-saga/effects'

@ -12,6 +12,7 @@ export default {
MODULE_MOVE: ModuleEffects.moveModule, MODULE_MOVE: ModuleEffects.moveModule,
MODULE_DELETE: ModuleEffects.deleteModule, MODULE_DELETE: ModuleEffects.deleteModule,
INTERFACE_FETCH: InterfaceEffects.fetchInterface,
INTERFACE_ADD: InterfaceEffects.addInterface, INTERFACE_ADD: InterfaceEffects.addInterface,
INTERFACE_UPDATE: InterfaceEffects.updateInterface, INTERFACE_UPDATE: InterfaceEffects.updateInterface,
INTERFACE_MOVE: InterfaceEffects.moveInterface, INTERFACE_MOVE: InterfaceEffects.moveInterface,

@ -6,6 +6,7 @@ import * as ModuleAction from '../actions/module'
import * as ModuleEffects from './effects/module' import * as ModuleEffects from './effects/module'
import * as RepositoryAction from '../actions/repository' import * as RepositoryAction from '../actions/repository'
import * as RepositoryEffects from './effects/repository' import * as RepositoryEffects from './effects/repository'
import _ from 'lodash'
export default { export default {
reducers: { reducers: {
repository( repository(
@ -51,7 +52,9 @@ export default {
modules: modules.map((mod: any) => ({ modules: modules.map((mod: any) => ({
...mod, ...mod,
interfaces: mod.interfaces.map((itf: any) => { interfaces: mod.interfaces.map((itf: any) => {
if (itf.id !== itfId) { return itf } if (itf.id !== itfId) {
return itf
}
return { return {
...itf, ...itf,
lockerId: locker.id, lockerId: locker.id,
@ -62,6 +65,28 @@ export default {
})), })),
}, },
} }
case 'INTERFACE_FETCH_SUCCEEDED': {
modules = state.data.modules
const fetchedItf = _.omit(action.payload, ['requestProperties', 'responseProperties'])
return {
...state,
data: {
...state.data,
modules: modules.map((mod: any) => ({
...mod,
interfaces: mod.interfaces.map((itf: any) => {
if (itf.id !== fetchedItf.id) {
return itf
}
return {
...itf,
...fetchedItf,
}
}),
})),
},
}
}
case InterfaceAction.unlockInterfaceSucceeded(undefined).type: case InterfaceAction.unlockInterfaceSucceeded(undefined).type:
modules = state.data.modules modules = state.data.modules
itfId = action.payload.itfId itfId = action.payload.itfId
@ -72,7 +97,9 @@ export default {
modules: modules.map((mod: any) => ({ modules: modules.map((mod: any) => ({
...mod, ...mod,
interfaces: mod.interfaces.map((itf: any) => { interfaces: mod.interfaces.map((itf: any) => {
if (itf.id !== itfId) { return itf } if (itf.id !== itfId) {
return itf
}
return { return {
...itf, ...itf,
lockerId: null, lockerId: null,
@ -94,7 +121,9 @@ export default {
modules: modules.map((mod: any) => ({ modules: modules.map((mod: any) => ({
...mod, ...mod,
interfaces: mod.interfaces.map((itf: any) => { interfaces: mod.interfaces.map((itf: any) => {
if (itf.id !== itfId) { return itf } if (itf.id !== itfId) {
return itf
}
return { return {
...itf, ...itf,
properties, properties,
@ -114,7 +143,9 @@ export default {
modules: modules.map((mod: any) => ({ modules: modules.map((mod: any) => ({
...mod, ...mod,
interfaces: mod.interfaces.map((x: any) => { interfaces: mod.interfaces.map((x: any) => {
if (x.id !== itf.id) { return x } if (x.id !== itf.id) {
return x
}
return { return {
...itf, ...itf,
locker: x.locker, locker: x.locker,
@ -150,7 +181,7 @@ export default {
...mod, ...mod,
interfaces: [...mod.interfaces, itf], interfaces: [...mod.interfaces, itf],
} }
: mod : mod,
), ),
}, },
} }
@ -168,7 +199,7 @@ export default {
name: mod.name, name: mod.name,
description: mod.description, description: mod.description,
} }
: x : x,
), ),
}, },
} }
@ -188,9 +219,11 @@ export default {
mod.id === moduleId mod.id === moduleId
? { ? {
...mod, ...mod,
interfaces: [...mod.interfaces].sort((a: any, b: any) => itfIdsMap[a.id] - itfIdsMap[b.id]), interfaces: [...mod.interfaces].sort(
(a: any, b: any) => itfIdsMap[a.id] - itfIdsMap[b.id],
),
} }
: mod : mod,
), ),
}, },
} }
@ -206,7 +239,9 @@ export default {
...state, ...state,
data: { data: {
...state.data, ...state.data,
modules: [...modules].sort((a: any, b: any) => moduleIdsMap[a.id] - moduleIdsMap[b.id]), modules: [...modules].sort(
(a: any, b: any) => moduleIdsMap[a.id] - moduleIdsMap[b.id],
),
}, },
} }
} }

@ -8,6 +8,22 @@ import * as InterfaceAction from '../../actions/interface'
import EditorService from '../services/Editor' import EditorService from '../services/Editor'
import * as RepositoryAction from '../../actions/repository' import * as RepositoryAction from '../../actions/repository'
export function* fetchInterface(action: any) {
try {
const payload = yield call(EditorService.fetchInterface, action.id)
yield put(InterfaceAction.fetchInterfaceSucceeded(payload))
if (action.onResolved) {
action.onResolved()
}
} catch (e) {
console.error(e.message)
yield put(InterfaceAction.fetchInterfaceFailed(e.message))
if (action.onRejected) {
action.onRejected()
}
}
}
export function* addInterface(action: any) { export function* addInterface(action: any) {
try { try {
const payload = yield call(EditorService.addInterface, action.interface) const payload = yield call(EditorService.addInterface, action.interface)

@ -1,7 +1,9 @@
import { call, put, select } from 'redux-saga/effects' import { call, put, select, take } from 'redux-saga/effects'
import * as RepositoryAction from '../../actions/repository' import * as RepositoryAction from '../../actions/repository'
import * as InterfaceAction from '../../actions/interface'
import RepositoryService from '../services/Repository' import RepositoryService from '../services/Repository'
import { RootState } from 'actions/types' import { RootState } from 'actions/types'
import { getCurrentInterfaceId } from '../../selectors/interface'
import { StoreStateRouterLocationURI } from 'family/index' import { StoreStateRouterLocationURI } from 'family/index'
import { IFetchDefaultValsAction, fetchDefaultValsFailed, IUpdateDefaultValsAction } from '../../actions/repository' import { IFetchDefaultValsAction, fetchDefaultValsFailed, IUpdateDefaultValsAction } from '../../actions/repository'
@ -89,17 +91,31 @@ export function* fetchRepository(action: any) {
const router = yield select((state: RootState) => state.router) const router = yield select((state: RootState) => state.router)
const uri = StoreStateRouterLocationURI(router) const uri = StoreStateRouterLocationURI(router)
const params = uri.search(true) const params = uri.search(true)
const count = yield call(RepositoryService.fetchRepository, action.repository || action.id, params.token) const repository = yield call(
yield put(RepositoryAction.fetchRepositorySucceeded(count)) RepositoryService.fetchRepository,
action.repository || action.id,
params.token,
)
yield put(RepositoryAction.fetchRepositorySucceeded(repository))
} catch (e) { } catch (e) {
yield put(RepositoryAction.fetchRepositoryFailed(e.message)) yield put(RepositoryAction.fetchRepositoryFailed(e.message))
} }
} }
export function* handleRepositoryLocationChange(action: any) { export function* handleRepositoryLocationChange(action: any) {
const repositoryId = yield select((state: RootState) => state.repository && state.repository.data && state.repository.data.id) const repositoryId = yield select(
(state: RootState) => state.repository && state.repository.data && state.repository.data.id,
)
if (Number(action.id) !== repositoryId) { if (Number(action.id) !== repositoryId) {
// 切换仓库
yield put(RepositoryAction.fetchRepository(action)) yield put(RepositoryAction.fetchRepository(action))
yield take('REPOSITORY_FETCH_SUCCEEDED')
const itfId = yield select(getCurrentInterfaceId)
yield put(InterfaceAction.fetchInterface(itfId, () => {}))
} else if (repositoryId) {
// 切换接口
const itfId = yield select(getCurrentInterfaceId)
yield put(InterfaceAction.fetchInterface(itfId, () => {}))
} }
} }

@ -25,10 +25,10 @@ export default {
}, },
fetchRepository(id: any, token?: string) { fetchRepository(id: any, token?: string) {
return fetch( return fetch(
`${serve}/repository/get?id=${id}${ `${serve}/repository/get?id=${id}&excludeProperty=true${
token !== undefined ? `&token=${token}` : '' token !== undefined ? `&token=${token}` : ''
}`, }`,
{ ...CREDENTIALS } { ...CREDENTIALS },
) )
.then(res => res.json()) .then(res => res.json())
.then(json => json.data) .then(json => json.data)

@ -1,9 +1,5 @@
import { import { createSelector } from 'reselect'
createSelector import { getRouter } from './router'
} from 'reselect'
import {
getRouter
} from './router'
import { RootState } from 'actions/types' import { RootState } from 'actions/types'
const interfaceSelector = (state: RootState) => { const interfaceSelector = (state: RootState) => {
@ -21,7 +17,18 @@ const interfaceSelector = (state: RootState) => {
return null return null
} }
export const getCurrentInterface = createSelector( export const getCurrentInterface = createSelector(interfaceSelector, result => result)
interfaceSelector,
result => result export const getCurrentInterfaceId = createSelector(
state => state.repository.data,
getRouter,
(repository: any, router: RootState['router']) => {
const itfId = +((router.location as any).params || (router.location as any).query).itf
if (itfId) {
return itfId
}
const modId = +((router.location as any).params || (router.location as any).query).mod
const mod = modId ? repository?.modules?.find((m: any) => m.id === modId) : repository?.modules[0]
return mod?.interfaces?.[0]?.id
},
) )

@ -113,6 +113,7 @@
"no-unused-expression": false, "no-unused-expression": false,
"jsx-no-lambda": false, "jsx-no-lambda": false,
"no-shadowed-variable": false, "no-shadowed-variable": false,
"react-hooks-nesting": "error" "react-hooks-nesting": "error",
"no-empty": false
} }
} }
Loading…
Cancel
Save