parent
447059f5e5
commit
576b956c5f
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 24 KiB |
@ -1,67 +0,0 @@
|
||||
// 登陆
|
||||
export const login = (user, onResolved) => ({ type: 'USER_LOGIN', user, onResolved })
|
||||
export const loginSucceeded = (user) => ({ type: 'USER_LOGIN_SUCCEEDED', user })
|
||||
export const loginFailed = (message) => ({ type: 'USER_LOGIN_FAILED', message })
|
||||
|
||||
// 重置
|
||||
export const reset = (email, password, onResolved) => ({ type: 'USER_RESET', email, password, onResolved })
|
||||
export const resetSucceeded = () => ({ type: 'USER_RESET_SUCCEEDED' })
|
||||
export const resetFailed = (message) => ({ type: 'USER_RESET_FAILED', message })
|
||||
|
||||
// 登出
|
||||
export const logout = () => ({ type: 'USER_LOGOUT' })
|
||||
export const logoutSucceeded = () => ({ type: 'USER_LOGOUT_SUCCEEDED' })
|
||||
export const logoutFailed = () => ({ type: 'USER_LOGOUT_FAILED' })
|
||||
|
||||
// 获取登陆信息
|
||||
export const fetchLoginInfo = () => ({ type: 'USER_FETCH_LOGIN_INFO' })
|
||||
export const fetchLoginInfoSucceeded = (user) => ({ type: 'USER_FETCH_LOGIN_INFO_SUCCEEDED', user })
|
||||
export const fetchLoginInfoFailed = (message) => ({ type: 'USER_FETCH_LOGIN_INFO_FAILED', message })
|
||||
|
||||
// 注册
|
||||
export const addUser = (user, onResolved) => ({ type: 'USER_ADD', user, onResolved })
|
||||
export const addUserSucceeded = (user) => ({ type: 'USER_ADD_SUCCEEDED', user })
|
||||
export const addUserFailed = (message) => ({ type: 'USER_ADD_FAILED', message })
|
||||
|
||||
// 更新
|
||||
export const updateUser = (user, onResolved) => ({ type: 'USER_UPDATE', user, onResolved })
|
||||
export const updateUserSucceeded = (user) => ({ type: 'USER_UPDATE_SUCCEEDED', user })
|
||||
export const updateUserFailed = (message) => ({ type: 'USER_UPDATE_FAILED', message })
|
||||
|
||||
// 删除用户
|
||||
export const deleteUser = (id) => ({ type: 'USER_DELETE', id })
|
||||
export const deleteUserSucceeded = (id) => ({ type: 'USER_DELETE_SUCCEEDED', id })
|
||||
export const deleteUserFailed = (id) => ({ type: 'USER_DELETE_FAILED', id })
|
||||
|
||||
// 获取用户列表
|
||||
export const fetchUserCount = () => ({ type: 'USER_COUNT_FETCH' })
|
||||
export const fetchUserCountSucceeded = (count) => ({ type: 'USER_COUNT_FETCH_SUCCEEDED', count })
|
||||
export const fetchUserCountFailed = (message) => ({ type: 'USER_COUNT_FETCH_FAILED', message })
|
||||
export const fetchUserList = ({ cursor, limit } = {}) => ({ type: 'USER_LIST_FETCH', cursor, limit })
|
||||
export const fetchUserListSucceeded = (users) => ({ type: 'USER_LIST_FETCH_SUCCEEDED', users })
|
||||
export const fetchUserListFailed = (message) => ({ type: 'USER_LIST_FETCH_FAILED', message })
|
||||
|
||||
// 获取用户设置
|
||||
export const fetchSetting = () => ({ type: 'SETTING_FETCH' })
|
||||
export const fetchSettingSucceeded = (setting) => ({ type: 'SETTING_FETCH_SUCCEEDED', setting })
|
||||
export const fetchSettingFailed = (message) => ({ type: 'SETTING_FETCH_FAILED', message })
|
||||
|
||||
// 修改用户设置
|
||||
export const updateSetting = (setting) => ({ type: 'SETTING_UPDATE', setting })
|
||||
export const updateSettingSucceeded = (setting) => ({ type: 'SETTING_UPDATE', setting })
|
||||
export const updateSettingFailed = (message) => ({ type: 'SETTING_UPDATE', message })
|
||||
|
||||
// 获取用户通知
|
||||
export const fetchNotificationList = () => ({ type: 'NOTIFICATION_LIST_FETCH' })
|
||||
export const fetchNotificationListSucceeded = () => ({ type: 'NOTIFICATION_LIST_FETCH_SUCCEEDED' })
|
||||
export const fetchNotificationListFailed = () => ({ type: 'NOTIFICATION_LIST_FETCH_Failed' })
|
||||
|
||||
// 阅读用户通知
|
||||
export const readNotification = (id) => ({ type: 'NOTIFICATION_READ', id })
|
||||
export const readNotificationSucceeded = (id) => ({ type: 'NOTIFICATION_READ_SUCCEEDED', id })
|
||||
export const readNotificationFailed = (message) => ({ type: 'NOTIFICATION_READ_FAILED', message })
|
||||
|
||||
// 获取用户日志
|
||||
export const fetchLogList = ({ cursor, limit } = {}) => ({ type: 'LOG_LIST_FETCH', cursor, limit })
|
||||
export const fetchLogListSucceeded = (logs) => ({ type: 'LOG_LIST_FETCH_SUCCEEDED', logs })
|
||||
export const fetchLogListFailed = (message) => ({ type: 'LOG_LIST_FETCH_FAILED', message })
|
@ -0,0 +1,59 @@
|
||||
// 登陆
|
||||
export const login = (user: any, onResolved: any) => ({ type: 'USER_LOGIN', user, onResolved })
|
||||
export const loginSucceeded = (user: any) => ({ type: 'USER_LOGIN_SUCCEEDED', user })
|
||||
export const loginFailed = (message: any) => ({ type: 'USER_LOGIN_FAILED', message })
|
||||
|
||||
// 登出
|
||||
export const logout = () => ({ type: 'USER_LOGOUT' })
|
||||
export const logoutSucceeded = () => { return ({ type: 'USER_LOGOUT_SUCCEEDED' }) }
|
||||
export const logoutFailed = () => ({ type: 'USER_LOGOUT_FAILED' })
|
||||
|
||||
// 获取登陆信息
|
||||
export const fetchLoginInfo = () => ({ type: 'USER_FETCH_LOGIN_INFO' })
|
||||
export const fetchLoginInfoSucceeded = (user: any) => ({ type: 'USER_FETCH_LOGIN_INFO_SUCCEEDED', user })
|
||||
export const fetchLoginInfoFailed = (message: any) => ({ type: 'USER_FETCH_LOGIN_INFO_FAILED', message })
|
||||
|
||||
// 注册
|
||||
export const addUser = (user: any, onResolved: any) => ({ type: 'USER_ADD', user, onResolved })
|
||||
export const addUserSucceeded = (user: any) => ({ type: 'USER_ADD_SUCCEEDED', user })
|
||||
export const addUserFailed = (message: any) => ({ type: 'USER_ADD_FAILED', message })
|
||||
|
||||
// 删除用户
|
||||
export const deleteUser = (id: any) => ({ type: 'USER_DELETE', id })
|
||||
export const deleteUserSucceeded = (id: any) => ({ type: 'USER_DELETE_SUCCEEDED', id })
|
||||
export const deleteUserFailed = (id: any) => ({ type: 'USER_DELETE_FAILED', id })
|
||||
|
||||
// 获取用户列表
|
||||
export const fetchUserCount = () => ({ type: 'USER_COUNT_FETCH' })
|
||||
export const fetchUserCountSucceeded = (count: any) => ({ type: 'USER_COUNT_FETCH_SUCCEEDED', count })
|
||||
export const fetchUserCountFailed = (message: any) => ({ type: 'USER_COUNT_FETCH_FAILED', message })
|
||||
export const fetchUserList = ({ cursor, limit } = { cursor: '', limit: ''}) => ({ type: 'USER_LIST_FETCH', cursor, limit })
|
||||
export const fetchUserListSucceeded = (users: any) => ({ type: 'USER_LIST_FETCH_SUCCEEDED', users })
|
||||
export const fetchUserListFailed = (message: any) => ({ type: 'USER_LIST_FETCH_FAILED', message })
|
||||
|
||||
// 获取用户设置
|
||||
export const fetchSetting = () => ({ type: 'SETTING_FETCH' })
|
||||
export const fetchSettingSucceeded = (setting: any) => ({ type: 'SETTING_FETCH_SUCCEEDED', setting })
|
||||
export const fetchSettingFailed = (message: any) => ({ type: 'SETTING_FETCH_FAILED', message })
|
||||
|
||||
// 修改用户设置
|
||||
export const updateSetting = (setting: any) => ({ type: 'SETTING_UPDATE', setting })
|
||||
export const updateSettingSucceeded = (setting: any) => ({ type: 'SETTING_UPDATE', setting })
|
||||
export const updateSettingFailed = (message: any) => ({ type: 'SETTING_UPDATE', message })
|
||||
|
||||
// 获取用户通知
|
||||
export const fetchNotificationList = () => ({ type: 'NOTIFICATION_LIST_FETCH' })
|
||||
export const fetchNotificationListSucceeded = () => ({ type: 'NOTIFICATION_LIST_FETCH_SUCCEEDED' })
|
||||
export const fetchNotificationListFailed = () => ({ type: 'NOTIFICATION_LIST_FETCH_Failed' })
|
||||
|
||||
// 阅读用户通知
|
||||
export const readNotification = (id: any) => ({ type: 'NOTIFICATION_READ', id })
|
||||
export const readNotificationSucceeded = (id: any) => ({ type: 'NOTIFICATION_READ_SUCCEEDED', id })
|
||||
export const readNotificationFailed = (message: any) => ({ type: 'NOTIFICATION_READ_FAILED', message })
|
||||
|
||||
// 获取用户日志
|
||||
export const fetchLogList = (
|
||||
{ cursor, limit } = { cursor: '', limit: '' }
|
||||
) => ({ type: 'LOG_LIST_FETCH', cursor, limit })
|
||||
export const fetchLogListSucceeded = (logs: any) => ({ type: 'LOG_LIST_FETCH_SUCCEEDED', logs })
|
||||
export const fetchLogListFailed = (message: any) => ({ type: 'LOG_LIST_FETCH_FAILED', message })
|
@ -1,20 +0,0 @@
|
||||
// 获取平台计数信息
|
||||
export const fetchCounter = () => ({ type: 'ANALYTICS_COUNTER_FETCH' })
|
||||
export const fetchCounterSucceeded = (counter) => ({ type: 'ANALYTICS_COUNTER_FETCH_SUCCEEDED', counter })
|
||||
export const fetchCounterFailed = (message) => ({ type: 'ANALYTICS_COUNTER_FETCH_FAILED', message })
|
||||
|
||||
export const fetchAnalyticsRepositoriesCreated = ({ start, end } = {}) => ({ type: 'ANALYTICS_REPOSITORIES_CREATED', start, end })
|
||||
export const fetchAnalyticsRepositoriesCreatedSucceeded = (analytics) => ({ type: 'ANALYTICS_REPOSITORIES_CREATED_SUCCEEDED', analytics })
|
||||
export const fetchAnalyticsRepositoriesCreatedFailed = (message) => ({ type: 'ANALYTICS_REPOSITORIES_CREATED_FAILED', message })
|
||||
|
||||
export const fetchAnalyticsRepositoriesUpdated = ({ start, end } = {}) => ({ type: 'ANALYTICS_REPOSITORIES_UPDATED', start, end })
|
||||
export const fetchAnalyticsRepositoriesUpdatedSucceeded = (analytics) => ({ type: 'ANALYTICS_REPOSITORIES_UPDATED_SUCCEEDED', analytics })
|
||||
export const fetchAnalyticsRepositoriesUpdatedFailed = (message) => ({ type: 'ANALYTICS_REPOSITORIES_UPDATED_FAILED', message })
|
||||
|
||||
export const fetchAnalyticsUsersActivation = ({ start, end } = {}) => ({ type: 'ANALYTICS_USERS_ACTIVATION', start, end })
|
||||
export const fetchAnalyticsUsersActivationSucceeded = (analytics) => ({ type: 'ANALYTICS_USERS_ACTIVATION_SUCCEEDED', analytics })
|
||||
export const fetchAnalyticsUsersActivationFailed = (message) => ({ type: 'ANALYTICS_USERS_ACTIVATION_FAILED', message })
|
||||
|
||||
export const fetchAnalyticsRepositoriesActivation = ({ start, end } = {}) => ({ type: 'ANALYTICS_REPOSITORIES_ACTIVATION', start, end })
|
||||
export const fetchAnalyticsRepositoriesActivationSucceeded = (analytics) => ({ type: 'ANALYTICS_REPOSITORIES_ACTIVATION_SUCCEEDED', analytics })
|
||||
export const fetchAnalyticsRepositoriesActivationFailed = (message) => ({ type: 'ANALYTICS_REPOSITORIES_ACTIVATION_FAILED', message })
|
@ -0,0 +1,28 @@
|
||||
// 获取平台计数信息
|
||||
export const fetchCounter = () => ({ type: 'ANALYTICS_COUNTER_FETCH' })
|
||||
export const fetchCounterSucceeded = (counter: any) => ({ type: 'ANALYTICS_COUNTER_FETCH_SUCCEEDED', counter })
|
||||
export const fetchCounterFailed = (message: any) => ({ type: 'ANALYTICS_COUNTER_FETCH_FAILED', message })
|
||||
|
||||
export const fetchAnalyticsRepositoriesCreated = (
|
||||
{ start, end } = { start: '', end: '' }
|
||||
) => ({ type: 'ANALYTICS_REPOSITORIES_CREATED', start, end })
|
||||
export const fetchAnalyticsRepositoriesCreatedSucceeded = (analytics: any) => ({ type: 'ANALYTICS_REPOSITORIES_CREATED_SUCCEEDED', analytics })
|
||||
export const fetchAnalyticsRepositoriesCreatedFailed = (message: any) => ({ type: 'ANALYTICS_REPOSITORIES_CREATED_FAILED', message })
|
||||
|
||||
export const fetchAnalyticsRepositoriesUpdated = (
|
||||
{ start, end } = { start: '', end: '' }
|
||||
) => ({ type: 'ANALYTICS_REPOSITORIES_UPDATED', start, end })
|
||||
export const fetchAnalyticsRepositoriesUpdatedSucceeded = (analytics: any) => ({ type: 'ANALYTICS_REPOSITORIES_UPDATED_SUCCEEDED', analytics })
|
||||
export const fetchAnalyticsRepositoriesUpdatedFailed = (message: any) => ({ type: 'ANALYTICS_REPOSITORIES_UPDATED_FAILED', message })
|
||||
|
||||
export const fetchAnalyticsUsersActivation = (
|
||||
{ start, end } = { start: '', end: '' }
|
||||
) => ({ type: 'ANALYTICS_USERS_ACTIVATION', start, end })
|
||||
export const fetchAnalyticsUsersActivationSucceeded = (analytics: any) => ({ type: 'ANALYTICS_USERS_ACTIVATION_SUCCEEDED', analytics })
|
||||
export const fetchAnalyticsUsersActivationFailed = (message: any) => ({ type: 'ANALYTICS_USERS_ACTIVATION_FAILED', message })
|
||||
|
||||
export const fetchAnalyticsRepositoriesActivation = (
|
||||
{ start, end } = { start: '', end: '' }
|
||||
) => ({ type: 'ANALYTICS_REPOSITORIES_ACTIVATION', start, end })
|
||||
export const fetchAnalyticsRepositoriesActivationSucceeded = (analytics: any) => ({ type: 'ANALYTICS_REPOSITORIES_ACTIVATION_SUCCEEDED', analytics })
|
||||
export const fetchAnalyticsRepositoriesActivationFailed = (message: any) => ({ type: 'ANALYTICS_REPOSITORIES_ACTIVATION_FAILED', message })
|
@ -0,0 +1 @@
|
||||
export const refresh = () => ({ type: 'REFRESH' })
|
@ -1,113 +0,0 @@
|
||||
export const addInterface = (itf, onResolved) => ({
|
||||
type: 'INTERFACE_ADD',
|
||||
interface: itf,
|
||||
onResolved
|
||||
})
|
||||
export const addInterfaceSucceeded = (payload) => ({
|
||||
type: 'INTERFACE_ADD_SUCCEEDED',
|
||||
payload
|
||||
})
|
||||
export const addInterfaceFailed = (message) => ({
|
||||
type: 'INTERFACE_ADD_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const updateInterface = (itf, onResolved) => ({
|
||||
type: 'INTERFACE_UPDATE',
|
||||
interface: itf,
|
||||
onResolved
|
||||
})
|
||||
export const updateInterfaceSucceeded = (payload) => ({
|
||||
type: 'INTERFACE_UPDATE_SUCCEEDED',
|
||||
payload
|
||||
})
|
||||
export const updateInterfaceFailed = (message) => ({
|
||||
type: 'INTERFACE_UPDATE_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const moveInterface = (params, onResolved) => ({
|
||||
type: 'INTERFACE_MOVE',
|
||||
params,
|
||||
onResolved
|
||||
})
|
||||
export const moveInterfaceSucceeded = () => ({
|
||||
type: 'INTERFACE_MOVE_SUCCEEDED'
|
||||
})
|
||||
export const moveInterfaceFailed = (message) => ({
|
||||
type: 'INTERFACE_MOVE_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const deleteInterface = (id, onResolved) => ({
|
||||
type: 'INTERFACE_DELETE',
|
||||
id,
|
||||
onResolved
|
||||
})
|
||||
export const deleteInterfaceSucceeded = (payload) => ({
|
||||
type: 'INTERFACE_DELETE_SUCCEEDED',
|
||||
payload
|
||||
})
|
||||
export const deleteInterfaceFailed = (message) => ({
|
||||
type: 'INTERFACE_DELETE_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const fetchInterfaceCount = () => ({
|
||||
type: 'INTERFACE_COUNT_FETCH'
|
||||
})
|
||||
export const fetchInterfaceCountSucceeded = (count) => ({
|
||||
type: 'INTERFACE_COUNT_FETCH_SUCCEEDED',
|
||||
count
|
||||
})
|
||||
export const fetchInterfaceCountFailed = (message) => ({
|
||||
type: 'INTERFACE_COUNT_FETCH_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const lockInterface = (id, onResolved) => ({
|
||||
type: 'INTERFACE_LOCK',
|
||||
id,
|
||||
onResolved
|
||||
})
|
||||
export const lockInterfaceSucceeded = (itfId, locker) => ({
|
||||
type: 'INTERFACE_LOCK_SUCCEEDED',
|
||||
payload: {
|
||||
itfId,
|
||||
locker
|
||||
}
|
||||
})
|
||||
export const lockInterfaceFailed = (message) => ({
|
||||
type: 'INTERFACE_LOCK_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const unlockInterface = (id, onResolved) => ({
|
||||
type: 'INTERFACE_UNLOCK',
|
||||
id,
|
||||
onResolved
|
||||
})
|
||||
export const unlockInterfaceSucceeded = (itfId) => ({
|
||||
type: 'INTERFACE_UNLOCK_SUCCEEDED',
|
||||
payload: {
|
||||
itfId
|
||||
},
|
||||
})
|
||||
export const unlockInterfaceFailed = (message) => ({
|
||||
type: 'INTERFACE_UNLOCK_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const sortInterfaceList = (ids, onResolved) => ({
|
||||
type: 'INTERFACE_LIST_SORT',
|
||||
ids,
|
||||
onResolved
|
||||
})
|
||||
export const sortInterfaceListSucceeded = (count) => ({
|
||||
type: 'INTERFACE_LIST_SORT_SUCCEEDED',
|
||||
count
|
||||
})
|
||||
export const sortInterfaceListFailed = (message) => ({
|
||||
type: 'INTERFACE_LIST_SORT_FAILED',
|
||||
message
|
||||
})
|
@ -0,0 +1,113 @@
|
||||
export const addInterface = (itf: any, onResolved: any) => ({
|
||||
type: 'INTERFACE_ADD',
|
||||
interface: itf,
|
||||
onResolved,
|
||||
})
|
||||
export const addInterfaceSucceeded = (payload: any) => ({
|
||||
type: 'INTERFACE_ADD_SUCCEEDED',
|
||||
payload,
|
||||
})
|
||||
export const addInterfaceFailed = (message: any) => ({
|
||||
type: 'INTERFACE_ADD_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const updateInterface = (itf: any, onResolved: any) => ({
|
||||
type: 'INTERFACE_UPDATE',
|
||||
interface: itf,
|
||||
onResolved,
|
||||
})
|
||||
export const updateInterfaceSucceeded = (payload: any) => ({
|
||||
type: 'INTERFACE_UPDATE_SUCCEEDED',
|
||||
payload,
|
||||
})
|
||||
export const updateInterfaceFailed = (message: any) => ({
|
||||
type: 'INTERFACE_UPDATE_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const moveInterface = (params: any, onResolved: any) => ({
|
||||
type: 'INTERFACE_MOVE',
|
||||
params,
|
||||
onResolved,
|
||||
})
|
||||
export const moveInterfaceSucceeded = () => ({
|
||||
type: 'INTERFACE_MOVE_SUCCEEDED',
|
||||
})
|
||||
export const moveInterfaceFailed = (message: any) => ({
|
||||
type: 'INTERFACE_MOVE_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const deleteInterface = (id: any, onResolved: any) => ({
|
||||
type: 'INTERFACE_DELETE',
|
||||
id,
|
||||
onResolved,
|
||||
})
|
||||
export const deleteInterfaceSucceeded = (payload: any) => ({
|
||||
type: 'INTERFACE_DELETE_SUCCEEDED',
|
||||
payload,
|
||||
})
|
||||
export const deleteInterfaceFailed = (message: any) => ({
|
||||
type: 'INTERFACE_DELETE_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const fetchInterfaceCount = () => ({
|
||||
type: 'INTERFACE_COUNT_FETCH',
|
||||
})
|
||||
export const fetchInterfaceCountSucceeded = (count: any) => ({
|
||||
type: 'INTERFACE_COUNT_FETCH_SUCCEEDED',
|
||||
count,
|
||||
})
|
||||
export const fetchInterfaceCountFailed = (message: any) => ({
|
||||
type: 'INTERFACE_COUNT_FETCH_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const lockInterface = (id: any, onResolved?: any) => ({
|
||||
type: 'INTERFACE_LOCK',
|
||||
id,
|
||||
onResolved,
|
||||
})
|
||||
export const lockInterfaceSucceeded = (itfId: any, locker: any) => ({
|
||||
type: 'INTERFACE_LOCK_SUCCEEDED',
|
||||
payload: {
|
||||
itfId,
|
||||
locker,
|
||||
},
|
||||
})
|
||||
export const lockInterfaceFailed = (message: any) => ({
|
||||
type: 'INTERFACE_LOCK_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const unlockInterface = (id: any, onResolved?: any) => ({
|
||||
type: 'INTERFACE_UNLOCK',
|
||||
id,
|
||||
onResolved,
|
||||
})
|
||||
export const unlockInterfaceSucceeded = (itfId: any) => ({
|
||||
type: 'INTERFACE_UNLOCK_SUCCEEDED',
|
||||
payload: {
|
||||
itfId,
|
||||
},
|
||||
})
|
||||
export const unlockInterfaceFailed = (message: any) => ({
|
||||
type: 'INTERFACE_UNLOCK_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const sortInterfaceList = (ids: any, onResolved: any) => ({
|
||||
type: 'INTERFACE_LIST_SORT',
|
||||
ids,
|
||||
onResolved,
|
||||
})
|
||||
export const sortInterfaceListSucceeded = (count: any) => ({
|
||||
type: 'INTERFACE_LIST_SORT_SUCCEEDED',
|
||||
count,
|
||||
})
|
||||
export const sortInterfaceListFailed = (message: any) => ({
|
||||
type: 'INTERFACE_LIST_SORT_FAILED',
|
||||
message,
|
||||
})
|
@ -1,56 +0,0 @@
|
||||
export const addModule = (module, onResolved) => ({
|
||||
type: 'MODULE_ADD',
|
||||
module,
|
||||
onResolved
|
||||
})
|
||||
export const addModuleSucceeded = (module) => ({
|
||||
type: 'MODULE_ADD_SUCCEEDED',
|
||||
module
|
||||
})
|
||||
export const addModuleFailed = (message) => ({
|
||||
type: 'MODULE_ADD_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const updateModule = (module, onResolved) => ({
|
||||
type: 'MODULE_UPDATE',
|
||||
module,
|
||||
onResolved
|
||||
})
|
||||
export const updateModuleSucceeded = (payload) => ({
|
||||
type: 'MODULE_UPDATE_SUCCEEDED',
|
||||
payload
|
||||
})
|
||||
export const updateModuleFailed = (message) => ({
|
||||
type: 'MODULE_UPDATE_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const deleteModule = (id, onResolved, repoId) => ({
|
||||
type: 'MODULE_DELETE',
|
||||
id,
|
||||
onResolved,
|
||||
repoId
|
||||
})
|
||||
export const deleteModuleSucceeded = (id) => ({
|
||||
type: 'MODULE_DELETE_SUCCEEDED',
|
||||
id
|
||||
})
|
||||
export const deleteModuleFailed = (message) => ({
|
||||
type: 'MODULE_DELETE_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const sortModuleList = (ids, onResolved) => ({
|
||||
type: 'MODULE_LIST_SORT',
|
||||
ids,
|
||||
onResolved
|
||||
})
|
||||
export const sortModuleListSucceeded = (count) => ({
|
||||
type: 'MODULE_LIST_SORT_SUCCEEDED',
|
||||
count
|
||||
})
|
||||
export const sortModuleListFailed = (message) => ({
|
||||
type: 'MODULE_LIST_SORT_FAILED',
|
||||
message
|
||||
})
|
@ -0,0 +1,56 @@
|
||||
export const addModule = (module: any, onResolved: any) => ({
|
||||
type: 'MODULE_ADD',
|
||||
module,
|
||||
onResolved,
|
||||
})
|
||||
export const addModuleSucceeded = (module: any) => ({
|
||||
type: 'MODULE_ADD_SUCCEEDED',
|
||||
module,
|
||||
})
|
||||
export const addModuleFailed = (message: any) => ({
|
||||
type: 'MODULE_ADD_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const updateModule = (module: any, onResolved: any) => ({
|
||||
type: 'MODULE_UPDATE',
|
||||
module,
|
||||
onResolved,
|
||||
})
|
||||
export const updateModuleSucceeded = (payload: any) => ({
|
||||
type: 'MODULE_UPDATE_SUCCEEDED',
|
||||
payload,
|
||||
})
|
||||
export const updateModuleFailed = (message: any) => ({
|
||||
type: 'MODULE_UPDATE_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const deleteModule = (id: any, onResolved: any, repoId: any) => ({
|
||||
type: 'MODULE_DELETE',
|
||||
id,
|
||||
onResolved,
|
||||
repoId,
|
||||
})
|
||||
export const deleteModuleSucceeded = (id: any) => ({
|
||||
type: 'MODULE_DELETE_SUCCEEDED',
|
||||
id,
|
||||
})
|
||||
export const deleteModuleFailed = (message: any) => ({
|
||||
type: 'MODULE_DELETE_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const sortModuleList = (ids: any, onResolved: any) => ({
|
||||
type: 'MODULE_LIST_SORT',
|
||||
ids,
|
||||
onResolved,
|
||||
})
|
||||
export const sortModuleListSucceeded = (count: any) => ({
|
||||
type: 'MODULE_LIST_SORT_SUCCEEDED',
|
||||
count,
|
||||
})
|
||||
export const sortModuleListFailed = (message: any) => ({
|
||||
type: 'MODULE_LIST_SORT_FAILED',
|
||||
message,
|
||||
})
|
@ -1,31 +0,0 @@
|
||||
export const addOrganization = (organization, onResolved) => ({ type: 'ORGANIZATION_ADD', organization, onResolved })
|
||||
export const addOrganizationSucceeded = (organization) => ({ type: 'ORGANIZATION_ADD_SUCCEEDED', organization })
|
||||
export const addOrganizationFailed = (message) => ({ type: 'ORGANIZATION_ADD_FAILED', message })
|
||||
|
||||
export const updateOrganization = (organization, onResolved) => ({ type: 'ORGANIZATION_UPDATE', organization, onResolved })
|
||||
export const updateOrganizationSucceeded = (organization) => ({ type: 'ORGANIZATION_UPDATE_SUCCEEDED', organization })
|
||||
export const updateOrganizationFailed = (message) => ({ type: 'ORGANIZATION_UPDATE_FAILED', message })
|
||||
|
||||
export const deleteOrganization = (id, onResolved) => ({ type: 'ORGANIZATION_DELETE', id, onResolved })
|
||||
export const deleteOrganizationSucceeded = (id) => ({ type: 'ORGANIZATION_DELETE_SUCCEEDED', id })
|
||||
export const deleteOrganizationFailed = (message) => ({ type: 'ORGANIZATION_DELETE_FAILED', message })
|
||||
|
||||
export const fetchOrganization = ({ id, organization } = {}) => ({ type: 'ORGANIZATION_FETCH', id, organization })
|
||||
export const fetchOrganizationSucceeded = (organization) => ({ type: 'ORGANIZATION_FETCH_SUCCEEDED', organization })
|
||||
export const fetchOrganizationFailed = (message) => ({ type: 'ORGANIZATION_FETCH_FAILED', message })
|
||||
|
||||
export const fetchOrganizationCount = () => ({ type: 'ORGANIZATION_COUNT_FETCH' })
|
||||
export const fetchOrganizationCountSucceeded = (count) => ({ type: 'ORGANIZATION_COUNT_FETCH_SUCCEEDED', count })
|
||||
export const fetchOrganizationCountFailed = (message) => ({ type: 'ORGANIZATION_COUNT_FETCH_FAILED', message })
|
||||
|
||||
export const fetchOwnedOrganizationList = ({ name } = {}) => ({ type: 'OWNED_ORGANIZATION_LIST_FETCH', name })
|
||||
export const fetchOwnedOrganizationListSucceeded = (organizations) => ({ type: 'OWNED_ORGANIZATION_LIST_FETCH_SUCCEEDED', organizations })
|
||||
export const fetchOwnedOrganizationListFailed = (message) => ({ type: 'OWNED_ORGANIZATION_LIST_FETCH_FAILED', message })
|
||||
|
||||
export const fetchJoinedOrganizationList = ({ name } = {}) => ({ type: 'JOINED_ORGANIZATION_LIST_FETCH', name })
|
||||
export const fetchJoinedOrganizationListSucceeded = (organizations) => ({ type: 'JOINED_ORGANIZATION_LIST_FETCH_SUCCEEDED', organizations })
|
||||
export const fetchJoinedOrganizationListFailed = (message) => ({ type: 'JOINED_ORGANIZATION_LIST_FETCH_FAILED', message })
|
||||
|
||||
export const fetchOrganizationList = ({ name, cursor, limit } = {}) => ({ type: 'ORGANIZATION_LIST_FETCH', name, cursor, limit })
|
||||
export const fetchOrganizationListSucceeded = (organizations) => ({ type: 'ORGANIZATION_LIST_FETCH_SUCCEEDED', organizations })
|
||||
export const fetchOrganizationListFailed = (message) => ({ type: 'ORGANIZATION_LIST_FETCH_FAILED', message })
|
@ -0,0 +1,33 @@
|
||||
export const addOrganization = (organization: any, onResolved: any) => ({ type: 'ORGANIZATION_ADD', organization, onResolved })
|
||||
export const addOrganizationSucceeded = (organization: any) => ({ type: 'ORGANIZATION_ADD_SUCCEEDED', organization })
|
||||
export const addOrganizationFailed = (message: any) => ({ type: 'ORGANIZATION_ADD_FAILED', message })
|
||||
|
||||
export const updateOrganization = (organization: any, onResolved: any) => ({ type: 'ORGANIZATION_UPDATE', organization, onResolved })
|
||||
export const updateOrganizationSucceeded = (organization: any) => ({ type: 'ORGANIZATION_UPDATE_SUCCEEDED', organization })
|
||||
export const updateOrganizationFailed = (message: any) => ({ type: 'ORGANIZATION_UPDATE_FAILED', message })
|
||||
|
||||
export const deleteOrganization = (id: any, onResolved: any) => ({ type: 'ORGANIZATION_DELETE', id, onResolved })
|
||||
export const deleteOrganizationSucceeded = (id: any) => ({ type: 'ORGANIZATION_DELETE_SUCCEEDED', id })
|
||||
export const deleteOrganizationFailed = (message: any) => ({ type: 'ORGANIZATION_DELETE_FAILED', message })
|
||||
|
||||
export const fetchOrganization = ({ id, organization } = { id: '', organization: ''}) => ({ type: 'ORGANIZATION_FETCH', id, organization })
|
||||
export const fetchOrganizationSucceeded = (organization: any) => ({ type: 'ORGANIZATION_FETCH_SUCCEEDED', organization })
|
||||
export const fetchOrganizationFailed = (message: any) => ({ type: 'ORGANIZATION_FETCH_FAILED', message })
|
||||
|
||||
export const fetchOrganizationCount = () => ({ type: 'ORGANIZATION_COUNT_FETCH' })
|
||||
export const fetchOrganizationCountSucceeded = (count: any) => ({ type: 'ORGANIZATION_COUNT_FETCH_SUCCEEDED', count })
|
||||
export const fetchOrganizationCountFailed = (message: any) => ({ type: 'ORGANIZATION_COUNT_FETCH_FAILED', message })
|
||||
|
||||
export const fetchOwnedOrganizationList = ({ name } = { name: ''}) => ({ type: 'OWNED_ORGANIZATION_LIST_FETCH', name })
|
||||
export const fetchOwnedOrganizationListSucceeded = (organizations: any) => ({ type: 'OWNED_ORGANIZATION_LIST_FETCH_SUCCEEDED', organizations })
|
||||
export const fetchOwnedOrganizationListFailed = (message: any) => ({ type: 'OWNED_ORGANIZATION_LIST_FETCH_FAILED', message })
|
||||
|
||||
export const fetchJoinedOrganizationList = ({ name } = { name: ''}) => ({ type: 'JOINED_ORGANIZATION_LIST_FETCH', name })
|
||||
export const fetchJoinedOrganizationListSucceeded = (organizations: any) => ({ type: 'JOINED_ORGANIZATION_LIST_FETCH_SUCCEEDED', organizations })
|
||||
export const fetchJoinedOrganizationListFailed = (message: any) => ({ type: 'JOINED_ORGANIZATION_LIST_FETCH_FAILED', message })
|
||||
|
||||
export const fetchOrganizationList = (
|
||||
{ name, cursor, limit } = { name: '', cursor: '', limit: '' }
|
||||
) => ({ type: 'ORGANIZATION_LIST_FETCH', name, cursor, limit })
|
||||
export const fetchOrganizationListSucceeded = (organizations: any) => ({ type: 'ORGANIZATION_LIST_FETCH_SUCCEEDED', organizations })
|
||||
export const fetchOrganizationListFailed = (message: any) => ({ type: 'ORGANIZATION_LIST_FETCH_FAILED', message })
|
@ -1,71 +0,0 @@
|
||||
export const addProperty = (property, onResolved) => ({
|
||||
type: 'PROPERTY_ADD',
|
||||
property,
|
||||
onResolved
|
||||
})
|
||||
export const addPropertySucceeded = (property) => ({
|
||||
type: 'PROPERTY_ADD_SUCCEEDED',
|
||||
property
|
||||
})
|
||||
export const addPropertyFailed = (message) => ({
|
||||
type: 'PROPERTY_ADD_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const updateProperty = (property, onResolved) => ({
|
||||
type: 'PROPERTY_UPDATE',
|
||||
property,
|
||||
onResolved
|
||||
})
|
||||
export const updatePropertySucceeded = (property) => ({
|
||||
type: 'PROPERTY_UPDATE_SUCCEEDED',
|
||||
property
|
||||
})
|
||||
export const updatePropertyFailed = (message) => ({
|
||||
type: 'PROPERTY_UPDATE_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const updateProperties = (itf, properties, summary, onResolved) => ({
|
||||
type: 'PROPERTIES_UPDATE',
|
||||
itf,
|
||||
properties,
|
||||
summary,
|
||||
onResolved
|
||||
})
|
||||
export const updatePropertiesSucceeded = (payload) => ({
|
||||
type: 'PROPERTIES_UPDATE_SUCCEEDED',
|
||||
payload
|
||||
})
|
||||
export const updatePropertiesFailed = (message) => ({
|
||||
type: 'PROPERTIES_UPDATE_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const deleteProperty = (id, onResolved) => ({
|
||||
type: 'PROPERTY_DELETE',
|
||||
id,
|
||||
onResolved
|
||||
})
|
||||
export const deletePropertySucceeded = (id) => ({
|
||||
type: 'PROPERTY_DELETE_SUCCEEDED',
|
||||
id
|
||||
})
|
||||
export const deletePropertyFailed = (message) => ({
|
||||
type: 'PROPERTY_DELETE_FAILED',
|
||||
message
|
||||
})
|
||||
|
||||
export const sortPropertyList = (ids, onResolved) => ({
|
||||
type: 'PROPERTY_LIST_SORT',
|
||||
ids,
|
||||
onResolved
|
||||
})
|
||||
export const sortPropertyListSucceeded = (count) => ({
|
||||
type: 'PROPERTY_LIST_SORT_SUCCEEDED',
|
||||
count
|
||||
})
|
||||
export const sortPropertyListFailed = (message) => ({
|
||||
type: 'PROPERTY_LIST_SORT_FAILED',
|
||||
message
|
||||
})
|
@ -0,0 +1,71 @@
|
||||
export const addProperty = (property: any, onResolved: any) => ({
|
||||
type: 'PROPERTY_ADD',
|
||||
property,
|
||||
onResolved,
|
||||
})
|
||||
export const addPropertySucceeded = (property: any) => ({
|
||||
type: 'PROPERTY_ADD_SUCCEEDED',
|
||||
property,
|
||||
})
|
||||
export const addPropertyFailed = (message: any) => ({
|
||||
type: 'PROPERTY_ADD_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const updateProperty = (property: any, onResolved: any) => ({
|
||||
type: 'PROPERTY_UPDATE',
|
||||
property,
|
||||
onResolved,
|
||||
})
|
||||
export const updatePropertySucceeded = (property: any) => ({
|
||||
type: 'PROPERTY_UPDATE_SUCCEEDED',
|
||||
property,
|
||||
})
|
||||
export const updatePropertyFailed = (message: any) => ({
|
||||
type: 'PROPERTY_UPDATE_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const updateProperties = (itf: any, properties: any, summary: any, onResolved: any) => ({
|
||||
type: 'PROPERTIES_UPDATE',
|
||||
itf,
|
||||
properties,
|
||||
summary,
|
||||
onResolved,
|
||||
})
|
||||
export const updatePropertiesSucceeded = (payload: any) => ({
|
||||
type: 'PROPERTIES_UPDATE_SUCCEEDED',
|
||||
payload,
|
||||
})
|
||||
export const updatePropertiesFailed = (message: any) => ({
|
||||
type: 'PROPERTIES_UPDATE_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const deleteProperty = (id: any, onResolved: any) => ({
|
||||
type: 'PROPERTY_DELETE',
|
||||
id,
|
||||
onResolved,
|
||||
})
|
||||
export const deletePropertySucceeded = (id: any) => ({
|
||||
type: 'PROPERTY_DELETE_SUCCEEDED',
|
||||
id,
|
||||
})
|
||||
export const deletePropertyFailed = (message: any) => ({
|
||||
type: 'PROPERTY_DELETE_FAILED',
|
||||
message,
|
||||
})
|
||||
|
||||
export const sortPropertyList = (ids: any, onResolved: any) => ({
|
||||
type: 'PROPERTY_LIST_SORT',
|
||||
ids,
|
||||
onResolved,
|
||||
})
|
||||
export const sortPropertyListSucceeded = (count: any) => ({
|
||||
type: 'PROPERTY_LIST_SORT_SUCCEEDED',
|
||||
count,
|
||||
})
|
||||
export const sortPropertyListFailed = (message: any) => ({
|
||||
type: 'PROPERTY_LIST_SORT_FAILED',
|
||||
message,
|
||||
})
|
@ -1,37 +0,0 @@
|
||||
export const addRepository = (repository, onResolved) => ({ type: 'REPOSITORY_ADD', repository, onResolved })
|
||||
export const addRepositorySucceeded = (repository) => ({ type: 'REPOSITORY_ADD_SUCCEEDED', repository })
|
||||
export const addRepositoryFailed = (message) => ({ type: 'REPOSITORY_ADD_FAILED', message })
|
||||
|
||||
export const importRepository = (data, onResolved) => ({ type: 'REPOSITORY_IMPORT', onResolved, data })
|
||||
export const importRepositorySucceeded = () => ({ type: 'REPOSITORY_IMPORT_SUCCEEDED' })
|
||||
export const importRepositoryFailed = (message) => ({ type: 'REPOSITORY_IMPORT_FAILED', message })
|
||||
|
||||
export const updateRepository = (repository, onResolved) => ({ type: 'REPOSITORY_UPDATE', repository, onResolved })
|
||||
export const updateRepositorySucceeded = (repository) => ({ type: 'REPOSITORY_UPDATE_SUCCEEDED', repository })
|
||||
export const updateRepositoryFailed = (message) => ({ type: 'REPOSITORY_UPDATE_FAILED', message })
|
||||
|
||||
export const deleteRepository = (id) => ({ type: 'REPOSITORY_DELETE', id })
|
||||
export const deleteRepositorySucceeded = (id) => ({ type: 'REPOSITORY_DELETE_SUCCEEDED', id })
|
||||
export const deleteRepositoryFailed = (message) => ({ type: 'REPOSITORY_DELETE_FAILED', message })
|
||||
|
||||
export const fetchRepository = ({ id, repository } = {}) => ({ type: 'REPOSITORY_FETCH', id, repository })
|
||||
export const fetchRepositorySucceeded = (repository) => ({ type: 'REPOSITORY_FETCH_SUCCEEDED', repository })
|
||||
export const fetchRepositoryFailed = (message) => ({ type: 'REPOSITORY_FETCH_FAILED', message })
|
||||
|
||||
export const clearRepository = () => ({ type: 'REPOSITORY_CLEAR' })
|
||||
|
||||
export const fetchRepositoryCount = () => ({ type: 'REPOSITORY_COUNT_FETCH' })
|
||||
export const fetchRepositoryCountSucceeded = (count) => ({ type: 'REPOSITORY_COUNT_FETCH_SUCCEEDED', count })
|
||||
export const fetchRepositoryCountFailed = (message) => ({ type: 'REPOSITORY_COUNT_FETCH_FAILED', message })
|
||||
|
||||
export const fetchRepositoryList = ({ user, organization, name, cursor, limit } = {}) => ({ type: 'REPOSITORY_LIST_FETCH', user, organization, name, cursor, limit })
|
||||
export const fetchRepositoryListSucceeded = (repositories) => ({ type: 'REPOSITORY_LIST_FETCH_SUCCEEDED', repositories })
|
||||
export const fetchRepositoryListFailed = (message) => ({ type: 'REPOSITORY_LIST_FETCH_FAILED', message })
|
||||
|
||||
export const fetchOwnedRepositoryList = ({ user, name } = {}) => ({ type: 'OWNED_REPOSITORY_LIST_FETCH', user, name })
|
||||
export const fetchOwnedRepositoryListSucceeded = (repositories) => ({ type: 'OWNED_REPOSITORY_LIST_FETCH_SUCCEEDED', repositories })
|
||||
export const fetchOwnedRepositoryListFailed = (message) => ({ type: 'OWNED_REPOSITORY_LIST_FETCH_FAILED', message })
|
||||
|
||||
export const fetchJoinedRepositoryList = ({ user, name } = {}) => ({ type: 'JOINED_REPOSITORY_LIST_FETCH', user, name })
|
||||
export const fetchJoinedRepositoryListSucceeded = (repositories) => ({ type: 'JOINED_REPOSITORY_LIST_FETCH_SUCCEEDED', repositories })
|
||||
export const fetchJoinedRepositoryListFailed = (message) => ({ type: 'JOINED_REPOSITORY_LIST_FETCH_FAILED', message })
|
@ -0,0 +1,48 @@
|
||||
export const addRepository = (repository: any, onResolved: any) => ({ type: 'REPOSITORY_ADD', repository, onResolved })
|
||||
export const addRepositorySucceeded = (repository: any) => ({ type: 'REPOSITORY_ADD_SUCCEEDED', repository })
|
||||
export const addRepositoryFailed = (message: any) => ({ type: 'REPOSITORY_ADD_FAILED', message })
|
||||
|
||||
export const importRepository = (data: any, onResolved: any) => ({ type: 'REPOSITORY_IMPORT', onResolved, data })
|
||||
export const importRepositorySucceeded = () => ({ type: 'REPOSITORY_IMPORT_SUCCEEDED' })
|
||||
export const importRepositoryFailed = (message: any) => ({ type: 'REPOSITORY_IMPORT_FAILED', message })
|
||||
|
||||
export const updateRepository = (repository: any, onResolved: any) => ({ type: 'REPOSITORY_UPDATE', repository, onResolved })
|
||||
export const updateRepositorySucceeded = (repository: any) => ({ type: 'REPOSITORY_UPDATE_SUCCEEDED', repository })
|
||||
export const updateRepositoryFailed = (message: any) => ({ type: 'REPOSITORY_UPDATE_FAILED', message })
|
||||
|
||||
export const deleteRepository = (id: any) => ({ type: 'REPOSITORY_DELETE', id })
|
||||
export const deleteRepositorySucceeded = (id: any) => ({ type: 'REPOSITORY_DELETE_SUCCEEDED', id })
|
||||
export const deleteRepositoryFailed = (message: any) => ({ type: 'REPOSITORY_DELETE_FAILED', message })
|
||||
|
||||
export const fetchRepository = ({ id, repository }: any) => ({ type: 'REPOSITORY_FETCH', id, repository })
|
||||
export const fetchRepositorySucceeded = (repository: any) => ({ type: 'REPOSITORY_FETCH_SUCCEEDED', repository })
|
||||
export const fetchRepositoryFailed = (message: any) => ({ type: 'REPOSITORY_FETCH_FAILED', message })
|
||||
|
||||
export const clearRepository = () => ({ type: 'REPOSITORY_CLEAR' })
|
||||
|
||||
export const fetchRepositoryCount = () => ({ type: 'REPOSITORY_COUNT_FETCH' })
|
||||
export const fetchRepositoryCountSucceeded = (count: any) => ({ type: 'REPOSITORY_COUNT_FETCH_SUCCEEDED', count })
|
||||
export const fetchRepositoryCountFailed = (message: any) => ({ type: 'REPOSITORY_COUNT_FETCH_FAILED', message })
|
||||
|
||||
export const fetchRepositoryList = ({ user, organization, name, cursor, limit } = {user: '', organization: '', name: '', cursor: '', limit: ''}) => ({ type: 'REPOSITORY_LIST_FETCH', user, organization, name, cursor, limit })
|
||||
export const fetchRepositoryListSucceeded = (repositories: any) => ({ type: 'REPOSITORY_LIST_FETCH_SUCCEEDED', repositories })
|
||||
export const fetchRepositoryListFailed = (message: any) => ({ type: 'REPOSITORY_LIST_FETCH_FAILED', message })
|
||||
export const fetchOwnedRepositoryList = (
|
||||
{ user, name } = { user: '', name: '' }
|
||||
) => ({ type: 'OWNED_REPOSITORY_LIST_FETCH', user, name })
|
||||
export const fetchOwnedRepositoryListSucceeded = (repositories: any) => ({ type: 'OWNED_REPOSITORY_LIST_FETCH_SUCCEEDED', repositories })
|
||||
export const fetchOwnedRepositoryListFailed = (message: any) => ({ type: 'OWNED_REPOSITORY_LIST_FETCH_FAILED', message })
|
||||
|
||||
export const fetchJoinedRepositoryList = (
|
||||
{ user, name } = { user: '', name: '' }
|
||||
) => ({ type: 'JOINED_REPOSITORY_LIST_FETCH', user, name })
|
||||
export const fetchJoinedRepositoryListSucceeded = (repositories: any) => ({ type: 'JOINED_REPOSITORY_LIST_FETCH_SUCCEEDED', repositories })
|
||||
export const fetchJoinedRepositoryListFailed = (message: any) => ({ type: 'JOINED_REPOSITORY_LIST_FETCH_FAILED', message })
|
||||
|
||||
export const fetchForeignInterfaces = ({ id, itf } = {id: '', itf: ''}) => ({ type: 'FOREIGN_INTERFACE_FETCH', id, itf })
|
||||
export const fetchForeignInterfacesSuccessed = (data: any) => ({ type: 'FOREIGN_INTERFACE_FETCH_SUCCEEDED', data })
|
||||
export const fetchForeignInterfacesFailed = (message: any) => ({ type: 'FOREIGN_INTERFACE_FETCH_FAILED', message })
|
||||
|
||||
export const addForeignRoomCase = ({ id, itf, name } = { id: '', itf: '', name: ''}) => ({ type: 'ADD_FOREIGN_ROOM_CASE', id, itf, name })
|
||||
export const addForeignRoomCaseSuccessed = ({ id, itf } = { id: '', itf: ''}) => ({ type: 'ADD_FOREIGN_ROOM_CASE_SUCCEEDED', id, itf })
|
||||
export const addForeignRoomCaseFailed = ({ id, itf, message }: any) => ({ type: 'ADD_FOREIGN_ROOM_CASE_FAILED', id, itf, message })
|
@ -0,0 +1,66 @@
|
||||
import { RouterState } from 'connected-react-router'
|
||||
|
||||
export interface RootState {
|
||||
auth: any
|
||||
router: RouterState
|
||||
repository: any
|
||||
repositories: any
|
||||
organization: any
|
||||
organizations: any
|
||||
ownedRepositories: any
|
||||
ownedOrganizations: any
|
||||
joinedOrganizations: any
|
||||
joinedRepositories: any
|
||||
users: any
|
||||
|
||||
counter: any
|
||||
logs: any
|
||||
foreign: any
|
||||
loading: boolean
|
||||
}
|
||||
|
||||
export interface Organization {
|
||||
|
||||
id: number
|
||||
|
||||
name: string
|
||||
|
||||
description?: string
|
||||
|
||||
logo?: string
|
||||
|
||||
/** true: 公开, false: 私有 */
|
||||
visibility?: boolean
|
||||
|
||||
creatorId?: number
|
||||
|
||||
ownerId?: number
|
||||
|
||||
memberIds?: number[]
|
||||
|
||||
members?: User[]
|
||||
|
||||
owner?: User
|
||||
|
||||
newOwner?: User
|
||||
|
||||
}
|
||||
|
||||
export interface User {
|
||||
id: number
|
||||
fullname: string
|
||||
email: string
|
||||
}
|
||||
|
||||
export interface INumItem {
|
||||
value: number
|
||||
label: string
|
||||
}
|
||||
|
||||
export interface IConfig {
|
||||
serve: string
|
||||
keys: string[]
|
||||
session: {
|
||||
key: string
|
||||
}
|
||||
}
|
@ -1,22 +1,27 @@
|
||||
@import "../../assets/variables.sass";
|
||||
// 水平居中 + 垂直居中
|
||||
.LoginForm
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 25rem;
|
||||
margin-left: -12.5rem;
|
||||
margin-top: -135px;
|
||||
border: 1px solid #E6E6E6;
|
||||
border-radius: .5rem;
|
||||
.header
|
||||
padding: 1.5rem 3rem;
|
||||
border-bottom: 1px solid $border;
|
||||
.title
|
||||
font-size: 2rem;
|
||||
.body
|
||||
padding: 1.5rem 3rem;
|
||||
.footer
|
||||
padding: 1.5rem 3rem;
|
||||
border-top: 1px solid $border;
|
||||
.wrapper
|
||||
background-size: cover;
|
||||
width: 100%
|
||||
height: 100%
|
||||
min-height: 800px
|
||||
.LoginForm
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 30%;
|
||||
width: 25rem;
|
||||
margin-left: -12.5rem;
|
||||
margin-top: -135px;
|
||||
border: 1px solid #E6E6E6;
|
||||
border-radius: .5rem;
|
||||
.header
|
||||
padding: 1.5rem 3rem;
|
||||
border-bottom: 1px solid $border;
|
||||
.title
|
||||
font-size: 2rem;
|
||||
.body
|
||||
padding: 1.5rem 3rem;
|
||||
.footer
|
||||
padding: 1.5rem 3rem;
|
||||
border-top: 1px solid $border;
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
import React from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
const Nav = ({ route, match, location }) => (
|
||||
<ul className='rap-navigation'>
|
||||
<li><NavLink to='/account/users' activeClassName='selected'>User List</NavLink></li>
|
||||
<li><NavLink to='/account/signin' activeClassName='selected'>Sign In</NavLink></li>
|
||||
<li><NavLink to='/account/signup' activeClassName='selected'>Sign Up</NavLink></li>
|
||||
</ul>
|
||||
)
|
||||
|
||||
const mapStateToProps = (state) => ({})
|
||||
const mapDispatchToProps = ({})
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Nav)
|
@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
const Nav = () => (
|
||||
<ul className="rap-navigation">
|
||||
<li><NavLink to="/account/users" activeClassName="selected">User List</NavLink></li>
|
||||
<li><NavLink to="/account/signin" activeClassName="selected">Sign In</NavLink></li>
|
||||
<li><NavLink to="/account/signup" activeClassName="selected">Sign Up</NavLink></li>
|
||||
</ul>
|
||||
)
|
||||
|
||||
const mapDispatchToProps = ({})
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(Nav)
|
@ -1,9 +1,27 @@
|
||||
.RegisterForm
|
||||
width: 30rem;
|
||||
margin: 0 auto;
|
||||
.header
|
||||
margin-bottom: 3rem;
|
||||
.title
|
||||
font-size: 2rem;
|
||||
.body
|
||||
.footer
|
||||
@import "../../assets/variables.sass";
|
||||
// 水平居中 + 垂直居中
|
||||
.wrapper
|
||||
background-size: cover;
|
||||
width: 100%
|
||||
height: 100%
|
||||
min-height: 800p
|
||||
.RegisterForm
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 30%;
|
||||
width: 25rem;
|
||||
margin-left: -12.5rem;
|
||||
margin-top: -135px;
|
||||
border: 1px solid #E6E6E6;
|
||||
border-radius: .5rem;
|
||||
.header
|
||||
padding: 1.5rem 3rem;
|
||||
border-bottom: 1px solid $border;
|
||||
.title
|
||||
font-size: 2rem;
|
||||
.body
|
||||
padding: 1.5rem 3rem;
|
||||
.footer
|
||||
padding: 1.5rem 3rem;
|
||||
border-top: 1px solid $border;
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
const User = ({ match, id, fullname, email, onDeleteUser }) => (
|
||||
const User = ({ match, id, fullname, email, onDeleteUser }: any) => (
|
||||
<tr>
|
||||
<td>{id}</td>
|
||||
<td>{fullname}</td>
|
||||
<td>{email}</td>
|
||||
<td>
|
||||
<Link to={match.url} onClick={e => onDeleteUser(id)}>X</Link>
|
||||
<Link to={match.url} onClick={() => onDeleteUser(id)}>X</Link>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
@ -1,29 +0,0 @@
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import './Footer.css'
|
||||
|
||||
const Footer = ({ counter = {} }) => (
|
||||
<div className='Footer'>
|
||||
v{counter.version}
|
||||
{/* <span className='ml10 mr10 color-c'>|</span>
|
||||
{counter.users} 人正在使用 RAP
|
||||
<span className='ml10 mr10 color-c'>|</span>
|
||||
今日 Mock 服务被调用 {counter.mock} 次 */}
|
||||
<ul className='friend_links'>
|
||||
<li><a href='http://rap.alibaba-inc.com/' target='_blank' rel='noopener noreferrer'>RAP0.x</a></li>
|
||||
<li><a href='http://mockjs.com/' target='_blank' rel='noopener noreferrer'>Mock.js</a></li>
|
||||
<li><a href='https://thx.github.io/' target='_blank' rel='noopener noreferrer'>THX</a></li>
|
||||
<li><a href='https://fe.alimama.net/thx/30/' target='_blank' rel='noopener noreferrer'>MMFE</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
counter: state.counter
|
||||
})
|
||||
const mapDispatchToProps = ({})
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Footer)
|
@ -0,0 +1,30 @@
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import './Footer.css'
|
||||
import { RootState } from 'actions/types'
|
||||
|
||||
const Footer = ({ counter = {} }: { counter: any }) => (
|
||||
<div className="Footer">
|
||||
{counter && counter.version}
|
||||
{/* <span className='ml10 mr10 color-c'>|</span>
|
||||
{counter.users} 人正在使用 RAP
|
||||
<span className='ml10 mr10 color-c'>|</span>
|
||||
今日 Mock 服务被调用 {counter.mock} 次 */}
|
||||
<ul className="friend_links">
|
||||
<li><a href="http://rap.alibaba-inc.com/" target="_blank" rel="noopener noreferrer">RAP0.x</a></li>
|
||||
<li><a href="http://mockjs.com/" target="_blank" rel="noopener noreferrer">Mock.js</a></li>
|
||||
<li><a href="https://thx.github.io/" target="_blank" rel="noopener noreferrer">THX</a></li>
|
||||
<li><a href="https://fe.alimama.net/thx/30/" target="_blank" rel="noopener noreferrer">MMFE</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
counter: state.counter,
|
||||
})
|
||||
const mapDispatchToProps = ({})
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Footer)
|
@ -0,0 +1,30 @@
|
||||
import grey from '@material-ui/core/colors/grey'
|
||||
import { StyleRules, Theme } from '@material-ui/core/styles'
|
||||
|
||||
const GlobalStyles = (theme: Theme) => ({
|
||||
'@global': {
|
||||
'body': {
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
backgroundColor: grey[200],
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif;',
|
||||
},
|
||||
'.ml1': {
|
||||
marginLeft: theme.spacing(1),
|
||||
},
|
||||
'.mr1': {
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
'ol': {
|
||||
padding: `0 ${theme.spacing(2)}px`,
|
||||
},
|
||||
'ul': {
|
||||
padding: `0 ${theme.spacing(2)}px`,
|
||||
},
|
||||
'li': {
|
||||
padding: `${theme.spacing(1)}px 0`,
|
||||
},
|
||||
},
|
||||
}) as StyleRules
|
||||
|
||||
export default GlobalStyles
|
@ -1,38 +0,0 @@
|
||||
@import "../../assets/variables.sass";
|
||||
|
||||
.Header
|
||||
background-color: $nav-bg;
|
||||
color: white;
|
||||
font-size: 1.4rem;
|
||||
line-height: 4rem;
|
||||
vertical-align: middle;
|
||||
// margin-bottom: 2rem;
|
||||
padding: 0 2rem;
|
||||
ul.nav-links
|
||||
float: left;
|
||||
ul.nav-actions
|
||||
float: right;
|
||||
ul.nav-links,
|
||||
ul.nav-actions
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
> li
|
||||
float: left;
|
||||
padding: 0 1rem;
|
||||
> a
|
||||
color: white;
|
||||
opacity: 0.5;
|
||||
&:hover, &.selected
|
||||
border: none;
|
||||
font-weight: bold;
|
||||
opacity: 1;
|
||||
> a.logo
|
||||
opacity: 1;
|
||||
font-weight: bold;
|
||||
.avatar
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
border-radius: 50%;
|
||||
.name
|
||||
margin-left: .5rem;
|
@ -0,0 +1,39 @@
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
import './nprogress.css'
|
||||
import MainMenu from 'components/layout/MainMenu'
|
||||
const Header = ({ fetching, user = {} }: any) => {
|
||||
if (!user || !user.id) {
|
||||
return null
|
||||
}
|
||||
document.body.style.cursor = fetching ? 'wait' : 'default' // TODO 2.3 应该有更好的方式监听整个 APP 是否有未完成的请求!
|
||||
fetching ? NProgress.start() : NProgress.done()
|
||||
return (
|
||||
<section className="Header">
|
||||
<nav className="clearfix">
|
||||
<MainMenu user={user} />
|
||||
</nav>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => ({
|
||||
fetching: (() => {
|
||||
let fetching = 0
|
||||
for (const key in state) {
|
||||
if (state[key] && state[key].fetching) { fetching += 1 }
|
||||
}
|
||||
return fetching
|
||||
})(), // state.fetching
|
||||
user: state.auth,
|
||||
})
|
||||
|
||||
const mapDispatchToProps = ({
|
||||
})
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Header)
|
@ -0,0 +1,42 @@
|
||||
import React from 'react'
|
||||
import { Button, makeStyles, createStyles, CircularProgress } from '@material-ui/core'
|
||||
import { ButtonProps } from '@material-ui/core/Button'
|
||||
import { green } from '@material-ui/core/colors'
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
root: {
|
||||
position: 'relative',
|
||||
display: 'inline',
|
||||
},
|
||||
buttonProgress: {
|
||||
color: green[500],
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
marginTop: -12,
|
||||
marginLeft: -12,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
interface Props extends ButtonProps {
|
||||
label: string
|
||||
}
|
||||
|
||||
export default function LoadingButton(props: Props) {
|
||||
const { children, label, ...rest } = props
|
||||
const classes = useStyles()
|
||||
const loading = props.disabled
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Button
|
||||
{...rest}
|
||||
>
|
||||
{loading ? '处理中...' : label}
|
||||
{children}
|
||||
</Button>
|
||||
{loading && <CircularProgress size={24} className={classes.buttonProgress} />}
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import createMuiTheme from '@material-ui/core/styles/createMuiTheme'
|
||||
|
||||
export const theme = {
|
||||
palette: {
|
||||
},
|
||||
overrides: {
|
||||
},
|
||||
}
|
||||
|
||||
const MuiTheme = createMuiTheme({
|
||||
overrides: {
|
||||
MuiTableCell: {
|
||||
root: {
|
||||
padding: '0 16px',
|
||||
},
|
||||
},
|
||||
},
|
||||
...theme,
|
||||
})
|
||||
|
||||
export default MuiTheme
|
@ -1,19 +0,0 @@
|
||||
import React from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { GoHome, GoRepo, GoOrganization, GoPulse, GoPlug } from 'react-icons/lib/go'
|
||||
|
||||
export default () => (
|
||||
<ul className='nav-links'>
|
||||
<li><NavLink exact to='/' activeClassName='selected'><GoHome /> 首页</NavLink></li>
|
||||
<li><NavLink to='/repository' activeClassName='selected'><GoRepo /> 仓库</NavLink></li>
|
||||
<li><NavLink to='/organization' activeClassName='selected'><GoOrganization /> 团队</NavLink></li>
|
||||
<li><NavLink to='/api' activeClassName='selected'><GoPlug /> 接口</NavLink></li>
|
||||
<li><NavLink to='/status' activeClassName='selected'><GoPulse /> 状态</NavLink></li>
|
||||
{/* <li><NavLink to='/manage' activeClassName='selected'>管理</NavLink></li> */}
|
||||
{/* <li><NavLink to='/account' activeClassName='selected'>Users</NavLink></li>
|
||||
<li><NavLink to='/organization' activeClassName='selected'>Organization</NavLink></li>
|
||||
<li><NavLink to='/workspace' activeClassName='selected'>Workspace</NavLink></li>
|
||||
<li><NavLink to='/analytics' activeClassName='selected'>Analytics</NavLink></li>
|
||||
<li><NavLink to='/utils' activeClassName='selected'>Utils</NavLink></li> */}
|
||||
</ul>
|
||||
)
|
@ -0,0 +1,13 @@
|
||||
import React from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { GoHome, GoRepo, GoOrganization, GoPulse, GoPlug } from 'react-icons/go'
|
||||
|
||||
export default () => (
|
||||
<ul className="nav-links">
|
||||
<li><NavLink exact={true} to="/" activeClassName="selected"><GoHome /> 首页</NavLink></li>
|
||||
<li><NavLink to="/repository" activeClassName="selected"><GoRepo /> 仓库</NavLink></li>
|
||||
<li><NavLink to="/organization" activeClassName="selected"><GoOrganization /> 团队</NavLink></li>
|
||||
<li><NavLink to="/api" activeClassName="selected"><GoPlug /> 接口</NavLink></li>
|
||||
<li><NavLink to="/status" activeClassName="selected"><GoPulse /> 状态</NavLink></li>
|
||||
</ul>
|
||||
)
|
@ -0,0 +1,275 @@
|
||||
import React, { HTMLAttributes } from 'react'
|
||||
import { Chip, Typography, MenuItem, TextField, NoSsr, Paper } from '@material-ui/core'
|
||||
import { emphasize } from '@material-ui/core/styles/colorManipulator'
|
||||
import CancelIcon from '@material-ui/icons/Cancel'
|
||||
import { createStyles, makeStyles, useTheme, Theme } from '@material-ui/core/styles'
|
||||
import { BaseTextFieldProps } from '@material-ui/core/TextField'
|
||||
import Select from 'react-select'
|
||||
import clsx from 'clsx'
|
||||
import { NoticeProps, MenuProps } from 'react-select/src/components/Menu'
|
||||
import { ControlProps } from 'react-select/src/components/Control'
|
||||
import { PlaceholderProps } from 'react-select/src/components/Placeholder'
|
||||
import { SingleValueProps } from 'react-select/src/components/SingleValue'
|
||||
import { ValueContainerProps } from 'react-select/src/components/containers'
|
||||
import { MultiValueProps } from 'react-select/src/components/MultiValue'
|
||||
import AsyncSelect from 'react-select/async'
|
||||
import { OptionProps } from 'react-select/src/components/Option'
|
||||
import { INumItem, User } from '../../actions/types'
|
||||
|
||||
const debounce = require('debounce-promise')
|
||||
|
||||
interface OptionType {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export type SelectedItem = Pick<User, 'id' | 'fullname'>
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
flexGrow: 1,
|
||||
marginBottom: theme.spacing(1),
|
||||
},
|
||||
input: {
|
||||
display: 'flex',
|
||||
padding: 0,
|
||||
height: 'auto',
|
||||
},
|
||||
valueContainer: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
chip: {
|
||||
margin: theme.spacing(0.5, 0.25),
|
||||
},
|
||||
chipFocused: {
|
||||
backgroundColor: emphasize(
|
||||
theme.palette.type === 'light' ? theme.palette.grey[300] : theme.palette.grey[700],
|
||||
0.08
|
||||
),
|
||||
},
|
||||
noOptionsMessage: {
|
||||
padding: theme.spacing(1, 2),
|
||||
},
|
||||
singleValue: {
|
||||
fontSize: 16,
|
||||
},
|
||||
placeholder: {
|
||||
position: 'absolute',
|
||||
left: 2,
|
||||
bottom: 6,
|
||||
fontSize: 16,
|
||||
},
|
||||
paper: {
|
||||
position: 'absolute',
|
||||
zIndex: 1,
|
||||
marginTop: theme.spacing(1),
|
||||
left: 0,
|
||||
right: 0,
|
||||
},
|
||||
divider: {
|
||||
height: theme.spacing(2),
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
function NoOptionsMessage(props: NoticeProps<OptionType>) {
|
||||
return (
|
||||
<Typography
|
||||
color="textSecondary"
|
||||
className={props.selectProps.classes.noOptionsMessage}
|
||||
{...props.innerProps}
|
||||
>
|
||||
{props.children}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
|
||||
type InputComponentProps = Pick<BaseTextFieldProps, 'inputRef'> & HTMLAttributes<HTMLDivElement>
|
||||
|
||||
function inputComponent({ inputRef, ...props }: InputComponentProps) {
|
||||
return <div ref={inputRef} {...props} />
|
||||
}
|
||||
|
||||
function Control(props: ControlProps<OptionType>) {
|
||||
return (
|
||||
<TextField
|
||||
style={{ minWidth: props.selectProps.minWidth || 350 }}
|
||||
InputProps={{
|
||||
inputComponent,
|
||||
inputProps: {
|
||||
className: props.selectProps.classes.input,
|
||||
inputRef: props.innerRef,
|
||||
children: props.children,
|
||||
...props.innerProps,
|
||||
},
|
||||
}}
|
||||
{...props.selectProps.TextFieldProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function Option(props: OptionProps<OptionType>) {
|
||||
return (
|
||||
<MenuItem
|
||||
ref={props.innerRef}
|
||||
selected={props.isFocused}
|
||||
component="div"
|
||||
style={{
|
||||
fontWeight: props.isSelected ? 500 : 400,
|
||||
}}
|
||||
{...props.innerProps}
|
||||
>
|
||||
{props.children}
|
||||
</MenuItem>
|
||||
)
|
||||
}
|
||||
|
||||
function Placeholder(props: PlaceholderProps<OptionType>) {
|
||||
return (
|
||||
<Typography
|
||||
color="textSecondary"
|
||||
className={props.selectProps.classes.placeholder}
|
||||
{...props.innerProps}
|
||||
>
|
||||
{props.children}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
|
||||
function SingleValue(props: SingleValueProps<OptionType>) {
|
||||
return (
|
||||
<Typography className={props.selectProps.classes.singleValue} {...props.innerProps}>
|
||||
{props.children}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
|
||||
function ValueContainer(props: ValueContainerProps<OptionType>) {
|
||||
return <div className={props.selectProps.classes.valueContainer}>{props.children}</div>
|
||||
}
|
||||
|
||||
function MultiValue(props: MultiValueProps<OptionType>) {
|
||||
return (
|
||||
<Chip
|
||||
tabIndex={-1}
|
||||
label={props.children}
|
||||
className={clsx(props.selectProps.classes.chip, {
|
||||
[props.selectProps.classes.chipFocused]: props.isFocused,
|
||||
})}
|
||||
onDelete={props.removeProps.onClick}
|
||||
deleteIcon={<CancelIcon {...props.removeProps} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function Menu(props: MenuProps<OptionType>) {
|
||||
return (
|
||||
<Paper square={true} className={props.selectProps.classes.paper} {...props.innerProps}>
|
||||
{props.children}
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
|
||||
const components = {
|
||||
Control,
|
||||
Menu,
|
||||
MultiValue,
|
||||
NoOptionsMessage,
|
||||
Option,
|
||||
Placeholder,
|
||||
SingleValue,
|
||||
ValueContainer,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
loadOptions?: (input: string) => Promise<INumItem[]>
|
||||
options?: INumItem[]
|
||||
isMulti?: boolean
|
||||
selected?: INumItem[]
|
||||
value?: INumItem[]
|
||||
minWidth?: number
|
||||
onChange: (selected: SelectedItem[]) => void
|
||||
}
|
||||
|
||||
function UserList(props: Props) {
|
||||
const classes = useStyles()
|
||||
const theme = useTheme()
|
||||
const { loadOptions, isMulti, onChange, options, selected, value, minWidth } = props
|
||||
const selectStyles = {
|
||||
input: (base: any) => ({
|
||||
...base,
|
||||
color: theme.palette.text.primary,
|
||||
'& input': {
|
||||
font: 'inherit',
|
||||
},
|
||||
}),
|
||||
}
|
||||
const commonProps: any = {
|
||||
minWidth,
|
||||
cacheOptions: true,
|
||||
defaultValue: selected || [],
|
||||
isMulti: isMulti || false,
|
||||
noOptionsMessage: ({ inputValue }: { inputValue: string }) => {
|
||||
return inputValue && inputValue.trim()
|
||||
? '搜不到数据'
|
||||
: '请输入检索关键字'
|
||||
},
|
||||
onChange: (vals: INumItem[] | INumItem) => {
|
||||
if (Array.isArray(vals)) {
|
||||
onChange(vals.map(x => ({ id: x.value, fullname: x.label })))
|
||||
} else {
|
||||
onChange([{ id: vals.value, fullname: vals.label }])
|
||||
}
|
||||
},
|
||||
placeholder: `请选择(${isMulti ? '多选' : '单选'})`,
|
||||
}
|
||||
|
||||
if (value) {
|
||||
(commonProps as any).value = value
|
||||
}
|
||||
|
||||
if (loadOptions) {
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<NoSsr>
|
||||
<AsyncSelect
|
||||
classes={classes}
|
||||
loadOptions={debounce(loadOptions, 250)}
|
||||
components={components}
|
||||
{...commonProps}
|
||||
/>
|
||||
</NoSsr>
|
||||
</div>
|
||||
)
|
||||
} else if (options) {
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<NoSsr>
|
||||
<Select
|
||||
classes={classes}
|
||||
styles={selectStyles}
|
||||
TextFieldProps={{
|
||||
InputLabelProps: {
|
||||
shrink: true,
|
||||
},
|
||||
}}
|
||||
options={options as any}
|
||||
components={components}
|
||||
{...commonProps}
|
||||
/>
|
||||
</NoSsr>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
throw new Error(
|
||||
'One of props.options and props.loadOptions is required.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default UserList
|
@ -0,0 +1,232 @@
|
||||
import React, { Component } from 'react'
|
||||
import { PropTypes, connect, _ } from '../../family'
|
||||
import InterfaceEditorToolbar from './InterfaceEditorToolbar'
|
||||
import InterfaceSummary, { BODY_OPTION, REQUEST_PARAMS_TYPE, rptFromStr2Num } from './InterfaceSummary'
|
||||
import PropertyList from './PropertyList'
|
||||
import { RModal } from '../utils'
|
||||
import MoveInterfaceForm from './MoveInterfaceForm'
|
||||
import { fetchRepository } from '../../actions/repository'
|
||||
import { RootState } from 'actions/types'
|
||||
import { lockInterface, unlockInterface } from 'actions/interface'
|
||||
import { updateProperties } from 'actions/property'
|
||||
|
||||
export const RequestPropertyList = (props: any) => {
|
||||
return <PropertyList scope="request" title="请求参数" label="请求" {...props} />
|
||||
}
|
||||
export const ResponsePropertyList = (props: any) => (
|
||||
<PropertyList scope="response" title="响应内容" label="响应" {...props} />
|
||||
)
|
||||
type InterfaceEditorProps = {
|
||||
auth: any
|
||||
itf: any
|
||||
properties: any[]
|
||||
mod: any
|
||||
repository: any
|
||||
lockInterface: typeof lockInterface
|
||||
unlockInterface: typeof unlockInterface
|
||||
updateProperties: typeof updateProperties
|
||||
}
|
||||
|
||||
type InterfaceEditorState = {
|
||||
summaryState: any
|
||||
itf: any
|
||||
properties: any
|
||||
editable: boolean
|
||||
moveInterfaceDialogOpen: boolean,
|
||||
}
|
||||
// TODO 2.x 参考 MySQL Workbench 的字段编辑器
|
||||
// TODO 2.x 支持复制整个接口到其他模块、其他项目
|
||||
class InterfaceEditor extends Component<
|
||||
InterfaceEditorProps,
|
||||
InterfaceEditorState
|
||||
> {
|
||||
static childContextTypes = {
|
||||
handleLockInterface: PropTypes.func.isRequired,
|
||||
handleUnlockInterface: PropTypes.func.isRequired,
|
||||
handleSaveInterface: PropTypes.func.isRequired,
|
||||
handleMoveInterface: PropTypes.func.isRequired,
|
||||
handleAddMemoryProperty: PropTypes.func.isRequired,
|
||||
handleAddMemoryProperties: PropTypes.func.isRequired,
|
||||
handleDeleteMemoryProperty: PropTypes.func.isRequired,
|
||||
handleChangeProperty: PropTypes.func.isRequired,
|
||||
}
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = {
|
||||
...InterfaceEditor.mapPropsToState(props),
|
||||
summaryState: {
|
||||
bodyOption: BODY_OPTION.FORM_DATA,
|
||||
requestParamsType: REQUEST_PARAMS_TYPE.QUERY_PARAMS,
|
||||
},
|
||||
moveInterfaceDialogOpen: false,
|
||||
}
|
||||
this.summaryStateChange = this.summaryStateChange.bind(this)
|
||||
// { itf: {}, properties: [] }
|
||||
}
|
||||
static mapPropsToState(prevProps: any, prevStates: any = {}) {
|
||||
const { auth, itf, properties } = prevProps
|
||||
return {
|
||||
...prevStates,
|
||||
itf,
|
||||
properties: properties.map((property: any) => ({ ...property })),
|
||||
editable: !!(itf.locker && (itf.locker.id === auth.id)),
|
||||
}
|
||||
}
|
||||
getChildContext() {
|
||||
return _.pick(this, Object.keys(InterfaceEditor.childContextTypes))
|
||||
}
|
||||
|
||||
summaryStateChange(summaryState: any) {
|
||||
this.setState({ summaryState })
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: any) {
|
||||
if (
|
||||
nextProps.itf.id === this.state.itf.id &&
|
||||
nextProps.itf.updatedAt === this.state.itf.updatedAt
|
||||
) { return }
|
||||
const prevStates = this.state
|
||||
this.setState(InterfaceEditor.mapPropsToState(nextProps, prevStates))
|
||||
}
|
||||
// Use shouldComponentUpdate() to let React know if a component's output is not affected by the current change in state or props.
|
||||
// TODO 2.2
|
||||
// shouldComponentUpdate (nextProps, nextState) {}
|
||||
|
||||
render() {
|
||||
const { auth, repository, mod, itf } = this.props
|
||||
const { editable } = this.state
|
||||
const { id, locker } = this.state.itf
|
||||
if (!id) { return null }
|
||||
return (
|
||||
<article className="InterfaceEditor">
|
||||
<InterfaceEditorToolbar
|
||||
locker={locker}
|
||||
auth={auth}
|
||||
repository={repository}
|
||||
editable={editable}
|
||||
itfId={itf.id}
|
||||
moveInterface={this.handleMoveInterface}
|
||||
handleLockInterface={this.handleLockInterface}
|
||||
handleMoveInterface={this.handleMoveInterface}
|
||||
handleSaveInterface={this.handleSaveInterface}
|
||||
handleUnlockInterface={this.handleUnlockInterface}
|
||||
/>
|
||||
<InterfaceSummary
|
||||
repository={repository}
|
||||
mod={mod}
|
||||
itf={itf}
|
||||
active={true}
|
||||
editable={editable}
|
||||
stateChangeHandler={this.summaryStateChange}
|
||||
/>
|
||||
<RequestPropertyList
|
||||
properties={this.state.properties}
|
||||
editable={editable}
|
||||
repository={repository}
|
||||
mod={mod}
|
||||
itf={this.state.itf}
|
||||
bodyOption={this.state.summaryState.bodyOption}
|
||||
requestParamsType={this.state.summaryState.requestParamsType}
|
||||
/>
|
||||
<ResponsePropertyList
|
||||
properties={this.state.properties}
|
||||
editable={editable}
|
||||
repository={repository}
|
||||
mod={mod}
|
||||
itf={this.state.itf}
|
||||
/>
|
||||
<RModal
|
||||
when={this.state.moveInterfaceDialogOpen}
|
||||
onClose={() => this.setState({ moveInterfaceDialogOpen: false })}
|
||||
onResolve={this.handleMoveInterfaceSubmit}
|
||||
>
|
||||
<MoveInterfaceForm title="移动接口" repository={repository} itfId={itf.id} />
|
||||
</RModal>
|
||||
</article>
|
||||
)
|
||||
}
|
||||
handleAddMemoryProperty = (property: any, cb: any) => {
|
||||
this.handleAddMemoryProperties([property], cb)
|
||||
}
|
||||
handleAddMemoryProperties = (properties: any, cb: any) => {
|
||||
const requestParamsType = this.state.summaryState.requestParamsType
|
||||
const rpt = rptFromStr2Num(requestParamsType)
|
||||
|
||||
properties.forEach((item: any) => {
|
||||
if (item.memory === undefined) { item.memory = true }
|
||||
if (item.id === undefined) { item.id = _.uniqueId('memory-') }
|
||||
item.pos = rpt
|
||||
})
|
||||
const nextState = { properties: [...this.state.properties, ...properties] }
|
||||
this.setState(nextState, () => {
|
||||
if (cb) { cb(properties) }
|
||||
})
|
||||
}
|
||||
handleDeleteMemoryProperty = (property: any, cb: any) => {
|
||||
const properties = [...this.state.properties]
|
||||
const index = properties.findIndex(item => item.id === property.id)
|
||||
if (index >= 0) {
|
||||
properties.splice(index, 1)
|
||||
|
||||
// 清除后代属性
|
||||
const deletedParentIds = [property.id]
|
||||
for (let index = 0; index < properties.length; index++) {
|
||||
if (deletedParentIds.indexOf(properties[index].parentId) !== -1) {
|
||||
deletedParentIds.push(properties[index].id)
|
||||
properties.splice(index--, 1)
|
||||
index = 0 // 强制从头开始查找,避免漏掉后代属性
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ properties }, () => {
|
||||
if (cb) { cb() }
|
||||
})
|
||||
}
|
||||
}
|
||||
handleChangeProperty = (property: any) => {
|
||||
const properties = [...this.state.properties]
|
||||
const index = properties.findIndex(item => item.id === property.id)
|
||||
if (index >= 0) {
|
||||
properties.splice(index, 1, property)
|
||||
this.setState({ properties })
|
||||
}
|
||||
}
|
||||
handleSaveInterface = (e: any) => {
|
||||
e.preventDefault()
|
||||
const { updateProperties } = this.props
|
||||
updateProperties(this.state.itf.id, this.state.properties, this.state.summaryState, () => {
|
||||
this.handleUnlockInterface()
|
||||
})
|
||||
}
|
||||
handleMoveInterface = () => {
|
||||
this.setState({
|
||||
moveInterfaceDialogOpen: true,
|
||||
})
|
||||
}
|
||||
handleMoveInterfaceSubmit = () => {
|
||||
/** empty */
|
||||
}
|
||||
handleLockInterface = () => {
|
||||
const { itf, lockInterface } = this.props
|
||||
lockInterface(itf.id)
|
||||
}
|
||||
handleUnlockInterface = () => {
|
||||
const { itf, unlockInterface } = this.props
|
||||
unlockInterface(itf.id)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
auth: state.auth,
|
||||
fetchRepository,
|
||||
})
|
||||
|
||||
const mapDispatchToProps = {
|
||||
lockInterface,
|
||||
unlockInterface,
|
||||
updateProperties,
|
||||
}
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(InterfaceEditor)
|
@ -0,0 +1,140 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect, Link, replace, StoreStateRouterLocationURI } from '../../family'
|
||||
import { RModal, RSortable } from '../utils'
|
||||
import InterfaceForm from './InterfaceForm'
|
||||
import { GoPencil, GoTrashcan, GoRocket, GoLock } from 'react-icons/go'
|
||||
import { getCurrentInterface } from '../../selectors/interface'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import './InterfaceList.css'
|
||||
import { RootState } from 'actions/types'
|
||||
type InterfaceProps = any
|
||||
type InterfaceState = any
|
||||
class InterfaceBase extends Component<InterfaceProps, InterfaceState> {
|
||||
static contextTypes = {
|
||||
store: PropTypes.object,
|
||||
onDeleteInterface: PropTypes.func.isRequired,
|
||||
}
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = { update: false }
|
||||
}
|
||||
render() {
|
||||
const { auth, repository, mod, itf, router } = this.props
|
||||
const selectHref = StoreStateRouterLocationURI(router)
|
||||
.setSearch('itf', itf.id)
|
||||
.href()
|
||||
const isOwned = repository.owner.id === auth.id
|
||||
const isJoined = repository.members.find((i: any) => i.id === auth.id)
|
||||
return (
|
||||
<div className="Interface clearfix">
|
||||
<span className="name">
|
||||
{itf.locker ? (
|
||||
<span className="locked mr5">
|
||||
<GoLock />
|
||||
</span>
|
||||
) : null}
|
||||
<Link
|
||||
to={selectHref}
|
||||
onClick={e => {
|
||||
if (
|
||||
this.props.curItf &&
|
||||
this.props.curItf.locker &&
|
||||
!window.confirm('编辑模式下切换接口,会导致编辑中的资料丢失,是否确定切换接口?')
|
||||
) {
|
||||
e.preventDefault()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span>{itf.name}</span>
|
||||
</Link>
|
||||
</span>
|
||||
{isOwned || isJoined ? (
|
||||
<div className="toolbar">
|
||||
{!itf.locker || itf.locker.id === auth.id ? (
|
||||
<span className="fake-link" onClick={() => this.setState({ update: true })}>
|
||||
<GoPencil />
|
||||
</span>
|
||||
) : null}
|
||||
<RModal when={this.state.update} onClose={() => this.setState({ update: false })} onResolve={this.handleUpdate}>
|
||||
<InterfaceForm title="修改接口" repository={repository} mod={mod} itf={itf} />
|
||||
</RModal>
|
||||
{!itf.locker ? (
|
||||
<Link to="" onClick={e => this.handleDelete(e, itf)}>
|
||||
<GoTrashcan />
|
||||
</Link>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
handleDelete = (e: any, itf: any) => {
|
||||
e.preventDefault()
|
||||
const message = `接口被删除后不可恢复!\n确认继续删除『#${itf.id} ${itf.name}』吗?`
|
||||
if (window.confirm(message)) {
|
||||
const { onDeleteInterface } = this.context
|
||||
onDeleteInterface(itf.id, () => {
|
||||
const { store } = this.context
|
||||
const uri = StoreStateRouterLocationURI(store)
|
||||
const deleteHref = this.props.active ? uri.removeSearch('itf').href() : uri.href()
|
||||
store.dispatch(replace(deleteHref))
|
||||
})
|
||||
}
|
||||
};
|
||||
handleUpdate = () => { /** test */ }
|
||||
}
|
||||
|
||||
const Interface = connect((state: any) => ({ router: state.router }))(InterfaceBase)
|
||||
type InterfaceListProps = any
|
||||
type InterfaceListState = any
|
||||
class InterfaceList extends Component<InterfaceListProps, InterfaceListState> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = { create: false }
|
||||
}
|
||||
render() {
|
||||
const { auth, repository, mod, itfs = [], itf, curItf } = this.props
|
||||
if (!mod.id) { return null }
|
||||
const isOwned = repository.owner.id === auth.id
|
||||
const isJoined = repository.members.find((i: any) => i.id === auth.id)
|
||||
return (
|
||||
<article className="InterfaceList">
|
||||
<RSortable onChange={this.handleSort} disabled={!isOwned && !isJoined}>
|
||||
<ul className="body">
|
||||
{itfs.map((item: any) => (
|
||||
<li key={item.id} className={item.id === itf.id ? 'active sortable' : 'sortable'} data-id={item.id}>
|
||||
<Interface repository={repository} mod={mod} itf={item} active={item.id === itf.id} auth={auth} curItf={curItf} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</RSortable>
|
||||
{isOwned || isJoined ? (
|
||||
<div className="footer">
|
||||
<span className="fake-link" onClick={() => this.setState({ create: true })}>
|
||||
<span className="fontsize-14">
|
||||
<GoRocket />
|
||||
</span>{' '}
|
||||
新建接口
|
||||
</span>
|
||||
<RModal when={this.state.create} onClose={() => this.setState({ create: false })} onResolve={this.handleCreate}>
|
||||
<InterfaceForm title="新建接口" repository={repository} mod={mod} />
|
||||
</RModal>
|
||||
</div>
|
||||
) : null}
|
||||
</article>
|
||||
)
|
||||
}
|
||||
handleCreate = () => { /** empty */ }
|
||||
handleSort = (_: any, sortable: any) => {
|
||||
const { onSortInterfaceList } = this.context
|
||||
onSortInterfaceList(sortable.toArray())
|
||||
};
|
||||
}
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
auth: state.auth,
|
||||
curItf: getCurrentInterface(state),
|
||||
router: state.router,
|
||||
})
|
||||
const mapDispatchToProps = {}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(InterfaceList)
|
@ -1,126 +0,0 @@
|
||||
import React, { Component } from 'react'
|
||||
import { PropTypes, connect, Link, replace, URI, StoreStateRouterLocationURI } from '../../family'
|
||||
import { RModal, RSortable } from '../utils'
|
||||
import ModuleForm from './ModuleForm'
|
||||
import { GoPencil, GoTrashcan, GoPackage } from 'react-icons/lib/go'
|
||||
|
||||
class Module extends Component {
|
||||
static propTypes = {
|
||||
auth: PropTypes.object.isRequired,
|
||||
repository: PropTypes.object.isRequired,
|
||||
mod: PropTypes.object.isRequired
|
||||
}
|
||||
static contextTypes = {
|
||||
store: PropTypes.object,
|
||||
onDeleteModule: PropTypes.func
|
||||
}
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = { update: false }
|
||||
}
|
||||
render () {
|
||||
let { store } = this.context
|
||||
let { auth, repository, mod } = this.props
|
||||
let uri = StoreStateRouterLocationURI(store).removeSearch('itf')
|
||||
let selectHref = URI(uri).setSearch('mod', mod.id).href()
|
||||
return (
|
||||
<div className='Module clearfix'>
|
||||
<Link to={selectHref} className='name'>{mod.name}</Link>
|
||||
<div className='toolbar'>
|
||||
{/* 编辑权限:拥有者或者成员 */}
|
||||
{repository.owner.id === auth.id || repository.members.find(itme => itme.id === auth.id)
|
||||
? <span className='fake-link' onClick={e => this.setState({ update: true })}><GoPencil /></span>
|
||||
: null
|
||||
}
|
||||
{repository.owner.id === auth.id || repository.members.find(itme => itme.id === auth.id)
|
||||
? <span className='fake-link' onClick={e => this.handleDelete(e, mod)}><GoTrashcan /></span>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<RModal when={this.state.update} onClose={e => this.setState({ update: false })} onResolve={this.handleUpdate}>
|
||||
<ModuleForm title='修改模块' mod={mod} repository={repository} />
|
||||
</RModal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
handleUpdate = (e) => {
|
||||
let { store } = this.context
|
||||
store.dispatch(replace(StoreStateRouterLocationURI(store).href()))
|
||||
}
|
||||
handleDelete = (e, mod) => {
|
||||
e.preventDefault()
|
||||
let message = `模块被删除后不可恢复,并且会删除相关的接口!\n确认继续删除『#${mod.id} ${mod.name}』吗?`
|
||||
if (window.confirm(message)) {
|
||||
this.context.onDeleteModule(this.props.mod.id, () => {
|
||||
let { store } = this.context
|
||||
let uri = StoreStateRouterLocationURI(store)
|
||||
let deleteHref = this.props.active ? URI(uri).removeSearch('mod').href() : uri.href()
|
||||
store.dispatch(replace(deleteHref))
|
||||
}, this.props.repository.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ModuleList extends Component {
|
||||
static contextTypes = {
|
||||
store: PropTypes.object.isRequired,
|
||||
onSortModuleList: PropTypes.func.isRequired
|
||||
}
|
||||
static propTypes = {
|
||||
auth: PropTypes.object.isRequired,
|
||||
repository: PropTypes.object.isRequired,
|
||||
mods: PropTypes.array,
|
||||
mod: PropTypes.object
|
||||
}
|
||||
static childContextTypes = {}
|
||||
getChildContext () {}
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = { create: false }
|
||||
}
|
||||
render () {
|
||||
let { auth, repository = {}, mods = [], mod = {} } = this.props
|
||||
let isOwned = repository.owner.id === auth.id
|
||||
let isJoined = repository.members.find(itme => itme.id === auth.id)
|
||||
return (
|
||||
<RSortable onChange={this.handleSort} disabled={!isOwned && !isJoined}>
|
||||
<ul className='ModuleList clearfix'>
|
||||
{mods.map((item, index) =>
|
||||
<li key={item.id} className={item.id === mod.id ? 'active sortable' : 'sortable'} data-id={item.id}>
|
||||
<Module key={item.id} mod={item} active={item.id === mod.id} repository={repository} auth={auth} />
|
||||
</li>
|
||||
)}
|
||||
{/* 编辑权限:拥有者或者成员 */}
|
||||
{isOwned || isJoined
|
||||
? <li>
|
||||
<span className='fake-link' onClick={e => this.setState({ create: true })}>
|
||||
<GoPackage className='fontsize-14' /> 新建模块
|
||||
</span>
|
||||
<RModal when={this.state.create} onClose={e => this.setState({ create: false })} onResolve={this.handleCreate}>
|
||||
<ModuleForm title='新建模块' repository={repository} />
|
||||
</RModal>
|
||||
</li>
|
||||
: null
|
||||
}
|
||||
</ul>
|
||||
</RSortable>
|
||||
)
|
||||
}
|
||||
handleCreate = () => {
|
||||
let { store } = this.context
|
||||
store.dispatch(replace(StoreStateRouterLocationURI(store).href()))
|
||||
}
|
||||
handleSort = (e, sortable) => {
|
||||
let { onSortModuleList } = this.context
|
||||
onSortModuleList(sortable.toArray())
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
auth: state.auth
|
||||
})
|
||||
const mapDispatchToProps = ({})
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ModuleList)
|
@ -0,0 +1,112 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect, Link, replace, StoreStateRouterLocationURI } from '../../family'
|
||||
import { RModal, RSortable } from '../utils'
|
||||
import ModuleForm from './ModuleForm'
|
||||
import { GoPencil, GoTrashcan, GoPackage } from 'react-icons/go'
|
||||
import { RootState } from 'actions/types'
|
||||
|
||||
class ModuleBase extends Component<any, any> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = { update: false }
|
||||
}
|
||||
render() {
|
||||
const { auth, repository, mod, router } = this.props
|
||||
const uri = StoreStateRouterLocationURI(router).removeSearch('itf')
|
||||
const selectHref = uri.setSearch('mod', mod.id).href()
|
||||
return (
|
||||
<div className="Module clearfix">
|
||||
<Link to={selectHref} className="name">{mod.name}</Link>
|
||||
<div className="toolbar">
|
||||
{/* 编辑权限:拥有者或者成员 */}
|
||||
{repository.owner.id === auth.id || repository.members.find((item: any) => item.id === auth.id)
|
||||
? <span className="fake-link" onClick={() => this.setState({ update: true })}><GoPencil /></span>
|
||||
: null
|
||||
}
|
||||
{repository.owner.id === auth.id || repository.members.find((item: any) => item.id === auth.id)
|
||||
? <span className="fake-link" onClick={e => this.handleDelete(e, mod)}><GoTrashcan /></span>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<RModal when={this.state.update} onClose={() => this.setState({ update: false })} onResolve={this.handleUpdate}>
|
||||
<ModuleForm title="修改模块" mod={mod} repository={repository} />
|
||||
</RModal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
handleUpdate = () => {
|
||||
this.props.replace(StoreStateRouterLocationURI(this.props.router).href())
|
||||
}
|
||||
handleDelete = (e: any, mod: any) => {
|
||||
const { router } = this.props
|
||||
e.preventDefault()
|
||||
const message = `模块被删除后不可恢复,并且会删除相关的接口!\n确认继续删除『#${mod.id} ${mod.name}』吗?`
|
||||
if (window.confirm(message)) {
|
||||
this.context.onDeleteModule(this.props.mod.id, () => {
|
||||
const { store } = this.context
|
||||
const uri = StoreStateRouterLocationURI(router)
|
||||
const deleteHref = this.props.active ? uri.removeSearch('mod').href() : uri.href()
|
||||
store.dispatch(replace(deleteHref))
|
||||
}, this.props.repository.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Module = connect((state: any) => ({
|
||||
router: state.router,
|
||||
}))(ModuleBase)
|
||||
|
||||
class ModuleList extends Component<any, any> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = { create: false }
|
||||
}
|
||||
render() {
|
||||
const { auth, repository = {}, mods = [], mod = {} } = this.props
|
||||
const isOwned = repository.owner.id === auth.id
|
||||
const isJoined = repository.members.find((item: any) => item.id === auth.id)
|
||||
return (
|
||||
<RSortable onChange={this.handleSort} disabled={!isOwned && !isJoined}>
|
||||
<ul className="ModuleList clearfix">
|
||||
{mods.map((item: any) =>
|
||||
<li key={item.id} className={item.id === mod.id ? 'active sortable' : 'sortable'} data-id={item.id}>
|
||||
<Module key={item.id} mod={item} active={item.id === mod.id} repository={repository} auth={auth} />
|
||||
</li>
|
||||
)}
|
||||
{/* 编辑权限:拥有者或者成员 */}
|
||||
{isOwned || isJoined
|
||||
? <li>
|
||||
<span className="fake-link" onClick={() => this.setState({ create: true })}>
|
||||
<GoPackage className="fontsize-14" /> 新建模块
|
||||
</span>
|
||||
<RModal when={this.state.create} onClose={() => this.setState({ create: false })} onResolve={this.handleCreate}>
|
||||
<ModuleForm title="新建模块" repository={repository} />
|
||||
</RModal>
|
||||
</li>
|
||||
: null
|
||||
}
|
||||
</ul>
|
||||
</RSortable>
|
||||
)
|
||||
}
|
||||
handleCreate = () => {
|
||||
const { router, replace } = this.props
|
||||
replace(StoreStateRouterLocationURI(router).href())
|
||||
}
|
||||
handleSort = (_: any, sortable: any) => {
|
||||
const { onSortModuleList } = this.context
|
||||
onSortModuleList(sortable.toArray())
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
auth: state.auth,
|
||||
router: state.router,
|
||||
})
|
||||
const mapDispatchToProps = ({
|
||||
replace,
|
||||
})
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ModuleList)
|
@ -0,0 +1,311 @@
|
||||
import React, { Component } from 'react'
|
||||
import { PropTypes, Link } from '../../family'
|
||||
import { Tree, SmartTextarea, RModal, RSortable } from '../utils'
|
||||
import PropertyForm from './PropertyForm'
|
||||
import Importer from './Importer'
|
||||
import Previewer from './InterfacePreviewer'
|
||||
import { GoPlus, GoTrashcan, GoQuestion } from 'react-icons/go'
|
||||
import { rptFromStr2Num } from './InterfaceSummary'
|
||||
import './PropertyList.css'
|
||||
import { ButtonGroup, Button } from '@material-ui/core'
|
||||
|
||||
export const RequestPropertyListPreviewer = (props: any) => (
|
||||
<Previewer {...props} />
|
||||
)
|
||||
|
||||
export const ResponsePropertyListPreviewer = (props: any) => (
|
||||
<Previewer {...props} />
|
||||
)
|
||||
|
||||
// DONE 2.2 请求属性有什么用?有必要吗?有,用于订制响应数据。
|
||||
// DONE 2.2 如何过滤模拟 URL 中额外的请求属性?解析 URL 中的参数到请求属性列表吗?可以在响应数据中引用 配置的请求参数 和 URL 中的额外参数。
|
||||
// DONE 2.2 支持对属性排序
|
||||
// DONE 2.2 支持对模块排序
|
||||
// DONE 2.2 支持对接口排序
|
||||
// TODO 2.3 检测重复属性
|
||||
|
||||
class SortableTreeTableHeader extends Component<any, any> {
|
||||
render() {
|
||||
const { editable } = this.props
|
||||
return (
|
||||
<div className="SortableTreeTableHeader">
|
||||
<div className="flex-row">
|
||||
{/* DONE 2.1 每列增加帮助 Tip */}
|
||||
{editable && <div className="th operations" />}
|
||||
<div className="th name">名称</div>
|
||||
<div className="th type">必选</div>
|
||||
<div className="th type">类型</div>
|
||||
{/* TODO 2.3 规则编辑器 */}
|
||||
<div className="th rule">
|
||||
生成规则
|
||||
<a
|
||||
href="https://github.com/nuysoft/Mock/wiki/Syntax-Specification"
|
||||
rel="noopener noreferrer"
|
||||
className="helper"
|
||||
target="_blank"
|
||||
>
|
||||
<GoQuestion />
|
||||
</a>
|
||||
</div>
|
||||
<div className="th value">初始值</div>{/* 对象和数组也允许设置初始值 */}
|
||||
<div className="th desc">简介</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const PropertyLabel = (props: any) => {
|
||||
const { pos } = props
|
||||
if (pos === 1) {
|
||||
return <label className="ml5 badge badge-danger">HEAD</label>
|
||||
} else if (pos === 3) {
|
||||
return <label className="ml5 badge badge-primary">BODY</label>
|
||||
} else {
|
||||
return <label className="ml5 badge badge-secondary">QUERY</label>
|
||||
}
|
||||
}
|
||||
|
||||
class SortableTreeTableRow extends Component<any, any> {
|
||||
render() {
|
||||
const { property, editable } = this.props
|
||||
const { handleClickCreateChildPropertyButton, handleDeleteMemoryProperty, handleChangePropertyField, handleSortProperties } = this.props
|
||||
return (
|
||||
<RSortable group={property.depth} handle=".SortableTreeTableRow" disabled={!editable} onChange={handleSortProperties}>
|
||||
<div className={`RSortableWrapper depth${property.depth}`}>
|
||||
{property.children.sort((a: any, b: any) => a.priority - b.priority).map((item: any) =>
|
||||
<div key={item.id} className="SortableTreeTableRow" data-id={item.id}>
|
||||
<div className="flex-row">
|
||||
{editable &&
|
||||
<div className="td operations nowrap">
|
||||
{(item.type === 'Object' || item.type === 'Array')
|
||||
? <Link
|
||||
to=""
|
||||
onClick={e => { e.preventDefault(); handleClickCreateChildPropertyButton(item) }}
|
||||
>
|
||||
<GoPlus className="fontsize-14 color-6" />
|
||||
</Link>
|
||||
: null}
|
||||
<Link to="" onClick={e => handleDeleteMemoryProperty(e, item)}><GoTrashcan className="fontsize-14 color-6" /></Link>
|
||||
</div>
|
||||
}
|
||||
<div className={`td payload name depth-${item.depth} nowrap`}>
|
||||
{!editable
|
||||
? <span className="nowrap">
|
||||
{item.name}
|
||||
{item.scope === 'request' && item.depth === 0 ? <PropertyLabel pos={item.pos} /> : null}
|
||||
</span>
|
||||
: <input
|
||||
value={item.name}
|
||||
onChange={e => handleChangePropertyField(item.id, 'name', e.target.value)}
|
||||
className="form-control editable"
|
||||
spellCheck={false}
|
||||
placeholder=""
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<div className={`td payload type depth-${item.depth} nowrap`}>
|
||||
{!editable
|
||||
? <span className="nowrap">{item.required ? '✔️' : ''}</span>
|
||||
: <input
|
||||
type="checkbox"
|
||||
checked={!!item.required}
|
||||
onChange={e => handleChangePropertyField(item.id, 'required', e.target.checked)}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="td payload type">
|
||||
{!editable
|
||||
? <span className="nowrap">{item.type}</span>
|
||||
: <select
|
||||
value={item.type}
|
||||
onChange={e => handleChangePropertyField(item.id, 'type', e.target.value)}
|
||||
className="form-control editable"
|
||||
>
|
||||
{['String', 'Number', 'Boolean', 'Object', 'Array', 'Function', 'RegExp'].map(type =>
|
||||
<option key={type} value={type}>{type}</option>
|
||||
)}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
<div className="td payload rule nowrap">
|
||||
{!editable
|
||||
? <span className="nowrap">{item.rule}</span>
|
||||
: <input
|
||||
value={item.rule || ''}
|
||||
onChange={e => handleChangePropertyField(item.id, 'rule', e.target.value)}
|
||||
className="form-control editable"
|
||||
spellCheck={false}
|
||||
placeholder=""
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<div className="td payload value">
|
||||
{!editable
|
||||
? <span>{item.value}</span>
|
||||
: <SmartTextarea
|
||||
value={item.value || ''}
|
||||
onChange={(e: any) => handleChangePropertyField(item.id, 'value', e.target.value)}
|
||||
rows="1"
|
||||
className="form-control editable"
|
||||
spellCheck={false}
|
||||
placeholder=""
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<div className="td payload desc">
|
||||
{!editable
|
||||
? <span>{item.description}</span>
|
||||
: <SmartTextarea
|
||||
value={item.description || ''}
|
||||
onChange={(e: any) => handleChangePropertyField(item.id, 'description', e.target.value)}
|
||||
rows="1"
|
||||
className="form-control editable"
|
||||
spellCheck={false}
|
||||
placeholder=""
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{item.children && item.children.length ? <SortableTreeTableRow {...this.props} property={item} /> : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</RSortable>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class SortableTreeTable extends Component<any, any> {
|
||||
render() {
|
||||
const { root, editable } = this.props
|
||||
return (
|
||||
<div className={`SortableTreeTable ${editable ? 'editable' : ''}`}>
|
||||
<SortableTreeTableHeader {...this.props} />
|
||||
<SortableTreeTableRow {...this.props} property={root} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyList extends Component<any, any> {
|
||||
static propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
scope: PropTypes.string.isRequired,
|
||||
properties: PropTypes.array,
|
||||
repository: PropTypes.object.isRequired,
|
||||
mod: PropTypes.object.isRequired,
|
||||
itf: PropTypes.object.isRequired,
|
||||
editable: PropTypes.bool.isRequired,
|
||||
|
||||
/** optional */
|
||||
bodyOption: PropTypes.string,
|
||||
requestParamsType: PropTypes.string,
|
||||
}
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = {
|
||||
createProperty: false,
|
||||
createChildProperty: false,
|
||||
previewer: props.scope === 'response',
|
||||
importer: false,
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const { title, label, scope, properties = [], repository = {}, mod = {}, itf = {} } = this.props
|
||||
if (!itf.id) { return null }
|
||||
const { editable, requestParamsType } = this.props // itf.locker && (itf.locker.id === auth.id)
|
||||
const pos = rptFromStr2Num(requestParamsType)
|
||||
let scopedProperties = properties.map((property: any) => ({ ...property })).filter((property: any) => property.scope === scope)
|
||||
if (scope === 'request' && editable) {
|
||||
scopedProperties = scopedProperties.filter((s: any) => s.pos === pos)
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="PropertyList">
|
||||
<div className="header clearfix">
|
||||
<span className="title">{title || `${label}属性`}</span>
|
||||
<div className="toolbar">
|
||||
<ButtonGroup size="small" color="primary">
|
||||
{editable && [
|
||||
<Button key={1} onClick={this.handleClickCreatePropertyButton}>新建</Button>,
|
||||
<Button key={2} onClick={this.handleClickImporterButton}>导入</Button>,
|
||||
]}
|
||||
<Button onClick={this.handleClickPreviewerButton}>
|
||||
预览
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
<div className="body">
|
||||
<SortableTreeTable
|
||||
root={Tree.arrayToTree(scopedProperties)}
|
||||
editable={editable}
|
||||
handleClickCreateChildPropertyButton={this.handleClickCreateChildPropertyButton}
|
||||
handleDeleteMemoryProperty={this.handleDeleteMemoryProperty}
|
||||
handleChangePropertyField={this.handleChangePropertyField}
|
||||
handleSortProperties={this.handleSortProperties}
|
||||
/>
|
||||
</div>
|
||||
<div className="footer">
|
||||
{this.state.previewer && <Previewer scope={scope} label={label} properties={properties} itf={itf} />}
|
||||
</div>
|
||||
<RModal
|
||||
when={this.state.createProperty}
|
||||
onClose={() => this.setState({ createProperty: false })}
|
||||
onResolve={this.handleCreatePropertySucceeded}
|
||||
>
|
||||
<PropertyForm title={`新建${label}属性`} scope={scope} repository={repository} mod={mod} itf={itf} />
|
||||
</RModal>
|
||||
<RModal
|
||||
when={!!this.state.createChildProperty}
|
||||
onClose={() => this.setState({ createChildProperty: false })}
|
||||
onResolve={this.handleCreatePropertySucceeded}
|
||||
>
|
||||
<PropertyForm title={`新建${label}属性`} scope={scope} repository={repository} mod={mod} itf={itf} parent={this.state.createChildProperty} />
|
||||
</RModal>
|
||||
<RModal when={this.state.importer} onClose={() => this.setState({ importer: false })} onResolve={this.handleCreatePropertySucceeded}>
|
||||
<Importer title={`导入${label}属性`} repository={repository} mod={mod} itf={itf} scope={scope} />
|
||||
</RModal>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
handleClickCreatePropertyButton = () => {
|
||||
this.setState({ createProperty: true })
|
||||
}
|
||||
handleClickCreateChildPropertyButton = (item: any) => {
|
||||
this.setState({ createChildProperty: item })
|
||||
}
|
||||
handleClickImporterButton = () => {
|
||||
this.setState({ importer: true })
|
||||
}
|
||||
handleClickPreviewerButton = () => {
|
||||
this.setState({ previewer: !this.state.previewer })
|
||||
}
|
||||
handleChangePropertyField = (id: any, key: any, value: any) => {
|
||||
const { handleChangeProperty } = this.context
|
||||
const { properties } = this.props
|
||||
const property = properties.find((property: any) => property.id === id)
|
||||
handleChangeProperty({ ...property, [key]: value })
|
||||
}
|
||||
handleCreatePropertySucceeded = () => {
|
||||
/** empty */
|
||||
}
|
||||
handleDeleteMemoryProperty = (e: any, property: any) => {
|
||||
e.preventDefault()
|
||||
const { handleDeleteMemoryProperty } = this.context
|
||||
handleDeleteMemoryProperty(property)
|
||||
}
|
||||
handleSortProperties = (_: any, sortable: any) => {
|
||||
const { properties } = this.props
|
||||
const ids = sortable.toArray()
|
||||
ids.forEach((id: any, index: any) => {
|
||||
const property = properties.find((item: any) => item.id === id || item.id === +id)
|
||||
property.priority = index + 1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default PropertyList
|
@ -0,0 +1,145 @@
|
||||
import React, { Component } from 'react'
|
||||
import { PropTypes, Link, StoreStateRouterLocationURI, connect } from '../../family'
|
||||
|
||||
class Highlight extends Component<any, any> {
|
||||
static replace = (clip: any, seed: any) => {
|
||||
if (!seed) { return clip }
|
||||
const rseed = new RegExp(seed, 'ig')
|
||||
return ('' + clip).replace(rseed, (matched) =>
|
||||
`<span class='highlight'>${matched}</span>`
|
||||
)
|
||||
}
|
||||
render() {
|
||||
const { clip, seed } = this.props
|
||||
const highlighted = { __html: Highlight.replace(clip, seed) }
|
||||
return (
|
||||
<span {...this.props} dangerouslySetInnerHTML={highlighted} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class DropdownMenuBase extends Component<any, any> {
|
||||
static contextTypes = {
|
||||
store: PropTypes.object,
|
||||
}
|
||||
static filter = (respository: any, seed: any) => {
|
||||
const nextRespository = { ...respository, modules: [] }
|
||||
let counter = 0
|
||||
respository.modules.forEach((mod: any) => {
|
||||
const nextModule = { ...mod, interfaces: [] }
|
||||
let matchModule = nextModule.name.indexOf(seed) !== -1
|
||||
if (matchModule) {
|
||||
counter++
|
||||
nextRespository.modules.push(nextModule)
|
||||
}
|
||||
|
||||
mod.interfaces.forEach((itf: any) => {
|
||||
const nextInterface = { ...itf, properties: [] }
|
||||
let matchInterface = nextInterface.name.indexOf(seed) !== -1 || nextInterface.url.indexOf(seed) !== -1 || nextInterface.method === seed
|
||||
if (matchInterface) {
|
||||
counter++
|
||||
if (!matchModule) {
|
||||
matchModule = true
|
||||
nextRespository.modules.push(nextModule)
|
||||
}
|
||||
nextModule.interfaces.push(nextInterface)
|
||||
}
|
||||
|
||||
itf.properties.forEach((property: any) => {
|
||||
const nextProperty = { ...property }
|
||||
const matchProperty = nextProperty.name.indexOf(seed) !== -1
|
||||
if (matchProperty) {
|
||||
counter++
|
||||
if (!matchModule) {
|
||||
matchModule = true
|
||||
nextRespository.modules.push(nextModule)
|
||||
}
|
||||
if (!matchInterface) {
|
||||
matchInterface = true
|
||||
nextModule.interfaces.push(nextInterface)
|
||||
}
|
||||
nextInterface.properties.push(nextProperty)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
return { nextRespository, counter }
|
||||
}
|
||||
static highlight = (clip: any, seed: any) => {
|
||||
if (!seed) { return clip }
|
||||
const rseed = new RegExp(seed, 'ig')
|
||||
return ('' + clip).replace(rseed, (matched) =>
|
||||
`<span class='highlight'>${matched}</span>`
|
||||
)
|
||||
}
|
||||
render() {
|
||||
const { repository, seed, onSelect, router } = this.props
|
||||
const uri = StoreStateRouterLocationURI(router).removeSearch('mod').removeSearch('itf')
|
||||
const { nextRespository, counter } = DropdownMenu.filter(repository, seed)
|
||||
if (counter === 0) { return null }
|
||||
return (
|
||||
<div className="dropdown-menu">
|
||||
{nextRespository.modules.map((mod: any, index: any, modules: any) =>
|
||||
<div key={`mod-${mod.id}`}>
|
||||
<Link to={uri.setSearch({ mod: mod.id }).href()} onClick={onSelect} className="dropdown-item dropdown-item-module">
|
||||
<span className="label">模块</span>
|
||||
<Highlight className="dropdown-item-clip" clip={mod.name} seed={seed} />
|
||||
</Link>
|
||||
{mod.interfaces.map((itf: any) =>
|
||||
<div key={`itf-${itf.id}`} >
|
||||
<Link
|
||||
to={uri.setSearch({ mod: itf.moduleId }).setSearch({ itf: itf.id }).href()}
|
||||
onClick={onSelect}
|
||||
className="dropdown-item dropdown-item-interface"
|
||||
>
|
||||
<span className="label">接口</span>
|
||||
<Highlight className="dropdown-item-clip" clip={itf.name} seed={seed} />
|
||||
<Highlight className="dropdown-item-clip" clip={itf.method} seed={seed} />
|
||||
<Highlight className="dropdown-item-clip" clip={itf.url} seed={seed} />
|
||||
</Link>
|
||||
{itf.properties.map((property: any) =>
|
||||
<Link key={`property-${property.id}`} to={uri.setSearch({ mod: property.moduleId }).setSearch({ itf: property.interfaceId }).href()} onClick={onSelect} className="dropdown-item dropdown-item-property">
|
||||
<span className="label">属性</span>
|
||||
<Highlight className="dropdown-item-clip" clip={property.name} seed={seed} />
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{index < modules.length - 1 && <div className="dropdown-divider" />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const DropdownMenu = connect((state: any) => ({ router: state.router }))(DropdownMenuBase)
|
||||
|
||||
// TODO 2.2 自动隐藏,高阶组件
|
||||
class RepositorySearcher extends Component<any, any> {
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = { seed: '' }
|
||||
}
|
||||
render() {
|
||||
const { repository } = this.props
|
||||
return (
|
||||
<div className="RepositorySearcher dropdown">
|
||||
<input
|
||||
value={this.state.seed}
|
||||
onChange={e => { this.setState({ seed: e.target.value }) }}
|
||||
className="dropdown-input form-control"
|
||||
placeholder="工作区搜索"
|
||||
/>
|
||||
{this.state.seed && <DropdownMenu repository={repository} seed={this.state.seed} onSelect={this.clearSeed} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
clearSeed = () => {
|
||||
this.setState({ seed: '' })
|
||||
}
|
||||
}
|
||||
|
||||
export default connect((state: any) => ({
|
||||
router: state.router,
|
||||
}))(RepositorySearcher)
|
@ -1,53 +0,0 @@
|
||||
import React from 'react'
|
||||
import { connect, Link } from '../../family'
|
||||
import { Spin } from '../utils'
|
||||
import OwnedRepositoriesCard from './OwnedRepositoriesCard'
|
||||
import JoinedRepositoriesCard from './JoinedRepositoriesCard'
|
||||
import LogsCard from './LogsCard'
|
||||
import './Home.css'
|
||||
import { GoRepo } from 'react-icons/lib/go'
|
||||
|
||||
const Maiden = () => (
|
||||
<div className='Maiden'>
|
||||
<Link to='/repository/joined/create' className=' btn btn-lg btn-success'><GoRepo /> 新建仓库</Link>
|
||||
</div>
|
||||
)
|
||||
|
||||
// 展示组件
|
||||
const Home = ({ auth, owned, joined, logs }) => {
|
||||
if (owned.fetching || joined.fetching || logs.fetching) return <Spin />
|
||||
|
||||
if (!owned.data.length && !joined.data.length) {
|
||||
return (
|
||||
<div className='Home'>
|
||||
<Maiden />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className='Home'>
|
||||
<div className='row'>
|
||||
<div className='col-12 col-sm-8 col-md-8 col-lg-8'>
|
||||
<LogsCard logs={logs} />
|
||||
</div>
|
||||
<div className='col-12 col-sm-4 col-md-4 col-lg-4'>
|
||||
<OwnedRepositoriesCard repositories={owned} />
|
||||
<JoinedRepositoriesCard repositories={joined} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// 容器组件
|
||||
const mapStateToProps = (state) => ({
|
||||
auth: state.auth,
|
||||
owned: state.ownedRepositories,
|
||||
joined: state.joinedRepositories,
|
||||
logs: state.logs
|
||||
})
|
||||
const mapDispatchToProps = ({})
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Home)
|
@ -0,0 +1,56 @@
|
||||
import React from 'react'
|
||||
import { Link } from '../../family'
|
||||
import { connect } from 'react-redux'
|
||||
import { Spin } from '../utils'
|
||||
import OwnedRepositoriesCard from './OwnedRepositoriesCard'
|
||||
import JoinedRepositoriesCard from './JoinedRepositoriesCard'
|
||||
import LogsCard from './LogsCard'
|
||||
import './Home.css'
|
||||
import { GoRepo } from 'react-icons/go'
|
||||
import { RootState } from 'actions/types'
|
||||
|
||||
const Maiden = () => (
|
||||
<div className="Maiden">
|
||||
<Link to="/repository/joined/create" className=" btn btn-lg btn-success"><GoRepo /> 新建仓库</Link>
|
||||
</div>
|
||||
)
|
||||
|
||||
// 展示组件
|
||||
const Home = ({ owned, joined, logs }: any) => {
|
||||
if (owned.fetching || joined.fetching || logs.fetching) { return <Spin /> }
|
||||
|
||||
if (!owned.data.length && !joined.data.length) {
|
||||
return (
|
||||
<div className="Home">
|
||||
<Maiden />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className="Home">
|
||||
<div className="row">
|
||||
<div className="col-12 col-sm-8 col-md-8 col-lg-8">
|
||||
<LogsCard logs={logs} />
|
||||
</div>
|
||||
<div className="col-12 col-sm-4 col-md-4 col-lg-4">
|
||||
<OwnedRepositoriesCard repositories={owned} />
|
||||
<div style={{ marginTop: 8 }}>
|
||||
<JoinedRepositoriesCard repositories={joined} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
auth: state.auth,
|
||||
owned: state.ownedRepositories,
|
||||
joined: state.joinedRepositories,
|
||||
logs: state.logs,
|
||||
})
|
||||
const mapDispatchToProps = ({})
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Home)
|
@ -1,25 +1,26 @@
|
||||
import React from 'react'
|
||||
import { Link } from '../../family'
|
||||
import { Spin } from '../utils'
|
||||
import { Card } from '@material-ui/core'
|
||||
|
||||
const JoinedRepositoriesCard = ({ repositories }) => (
|
||||
<div className='card'>
|
||||
<div className='card-header'>我加入的仓库</div>
|
||||
const JoinedRepositoriesCard = ({ repositories }: any) => (
|
||||
<Card>
|
||||
<div className="card-header">我加入的仓库</div>
|
||||
{repositories.fetching ? <Spin /> : (
|
||||
<div className='card-block'>
|
||||
{repositories.data.slice(0, 10).map(repository =>
|
||||
<div className="card-block">
|
||||
{repositories.data.slice(0, 10).map((repository: any) =>
|
||||
<p key={repository.id}><JoinedRepositoryLink repository={repository} /></p>
|
||||
)}
|
||||
{repositories.data.length === 0 ? <span>-</span> : null}
|
||||
{repositories.data.length > 10
|
||||
? <Link to='/repository/joined'>=> 查看全部 {repositories.data.length} 个仓库</Link>
|
||||
? <Link to="/repository/joined">=> 查看全部 {repositories.data.length} 个仓库</Link>
|
||||
: null
|
||||
}
|
||||
</div>)
|
||||
}
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
const JoinedRepositoryLink = ({ repository }) => (
|
||||
const JoinedRepositoryLink = ({ repository }: any) => (
|
||||
<Link to={`/repository/editor?id=${repository.id}`}>
|
||||
<span>{repository.organization ? repository.organization.name : repository.owner.fullname}</span>
|
||||
<span> / </span>
|
@ -1,25 +1,26 @@
|
||||
import React from 'react'
|
||||
import { Link } from '../../family'
|
||||
import { Spin } from '../utils'
|
||||
import { Card } from '@material-ui/core'
|
||||
|
||||
const OwnedRepositoriesCard = ({ repositories }) => (
|
||||
<div className='card'>
|
||||
<div className='card-header'>我拥有的仓库</div>
|
||||
const OwnedRepositoriesCard = ({ repositories }: any) => (
|
||||
<Card>
|
||||
<div className="card-header">我拥有的仓库</div>
|
||||
{repositories.fetching ? <Spin /> : (
|
||||
<div className='card-block'>
|
||||
{repositories.data.slice(0, 10).map(repository =>
|
||||
<div className="card-block">
|
||||
{repositories.data.slice(0, 10).map((repository: any) =>
|
||||
<p key={repository.id}><OwnedRepositoryLink repository={repository} /></p>
|
||||
)}
|
||||
{repositories.data.length === 0 ? <span>-</span> : null}
|
||||
{repositories.data.length > 10
|
||||
? <Link to='/repository/joined'>=> 查看全部 {repositories.data.length} 个仓库</Link>
|
||||
? <Link to="/repository/joined">=> 查看全部 {repositories.data.length} 个仓库</Link>
|
||||
: null
|
||||
}
|
||||
</div>)
|
||||
}
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
const OwnedRepositoryLink = ({ repository }) => (
|
||||
const OwnedRepositoryLink = ({ repository }: any) => (
|
||||
<Link to={`/repository/editor?id=${repository.id}`}>
|
||||
<span>{repository.organization ? repository.organization.name + ' / ' : ''}</span>
|
||||
<span>{repository.name}</span>
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,72 @@
|
||||
import React from 'react'
|
||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||
import AppBar from '@material-ui/core/AppBar'
|
||||
import Toolbar from '@material-ui/core/Toolbar'
|
||||
import Button from '@material-ui/core/Button'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { User } from 'actions/types'
|
||||
import Logo from './Logo'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { logout } from 'actions/account'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
flexGrow: 1,
|
||||
width: '100%',
|
||||
},
|
||||
menuButton: {
|
||||
marginRight: theme.spacing(2),
|
||||
},
|
||||
title: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
link: {
|
||||
color: '#FFFFFF',
|
||||
'&:hover': {
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
},
|
||||
right: {
|
||||
float: 'right',
|
||||
},
|
||||
toolbar: {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
logo: {
|
||||
marginRight: theme.spacing(2),
|
||||
display: 'inline',
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
interface Props {
|
||||
user: User
|
||||
}
|
||||
|
||||
export default function MainMenu(props: Props) {
|
||||
const { user } = props
|
||||
const classes = useStyles()
|
||||
const dispatch = useDispatch()
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<AppBar position="static">
|
||||
<Toolbar className={classes.toolbar}>
|
||||
<div>
|
||||
<div className={classes.logo}> <Logo /> </div>
|
||||
<Link to="/" className={classes.link}><Button color="inherit"> 首页</Button></Link>
|
||||
<Link to="/repository/joined" className={classes.link}><Button color="inherit"> 仓库 </Button></Link>
|
||||
<Link to="/organization/joined" className={classes.link}><Button color="inherit"> 团队 </Button></Link>
|
||||
<Link to="/api" className={classes.link}><Button color="inherit"> 接口 </Button></Link>
|
||||
<Link to="/status" className={classes.link}><Button color="inherit"> 状态 </Button></Link>
|
||||
</div>
|
||||
<div>
|
||||
{user.id && <Button color="inherit" onClick={() => dispatch(logout())}>注销</Button>}
|
||||
</div>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Popover } from '../utils'
|
||||
import OrganizationForm from './OrganizationForm'
|
||||
import { GoOrganization } from 'react-icons/go'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState, Organization } from '../../actions/types'
|
||||
import { handleDelete, handleExit, handleJoin } from './OrganizationListParts'
|
||||
|
||||
function avatar(user: any) {
|
||||
return `https://work.alibaba-inc.com/photo/${user.empId}.220x220.jpg`
|
||||
}
|
||||
|
||||
interface Props {
|
||||
organization: Organization
|
||||
}
|
||||
|
||||
function OrganizationBlock(props: Props) {
|
||||
const { organization } = props
|
||||
const auth = useSelector((state: RootState) => state.auth)
|
||||
const [update, setUpdate] = useState(false)
|
||||
const owned = organization.owner && organization.owner.id === auth.id
|
||||
const joined = organization.members!.find(user => user.id === auth.id)
|
||||
const selfHelpJoin = false // DONE 2.1 不允许自助加入团队
|
||||
return (
|
||||
<section className="Organization card">
|
||||
<div className="card-block">
|
||||
<div className="header clearfix">
|
||||
<span className="title">
|
||||
<GoOrganization className="mr6 color-9" />
|
||||
<Link to={`/organization/repository?organization=${organization.id}`} >{organization.name}</Link>
|
||||
</span>
|
||||
<span className="toolbar">
|
||||
{owned || joined ? ( // 拥有或已加入
|
||||
<span className="fake-link operation mr5" onClick={() => setUpdate(true)}>编辑</span>
|
||||
) : null}
|
||||
<OrganizationForm organization={organization} open={update} onClose={() => setUpdate(false)} />
|
||||
{owned ? ( // 拥有
|
||||
<Link to="" onClick={e => handleDelete(e, organization)} className="operation mr5">删除</Link>
|
||||
) : null}
|
||||
{!owned && joined ? ( // 不拥有,已加入
|
||||
<Link to="" onClick={e => handleExit(e, organization)} className="operation mr5">退出</Link>
|
||||
) : null}
|
||||
{!owned && !joined && selfHelpJoin ? ( // 不拥有,未加入
|
||||
<Link to="" onClick={e => handleJoin(e, organization)} className="operation mr5">加入</Link>
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
<div className="body">
|
||||
<div className="desc">{organization.description}</div>
|
||||
<div className="members">
|
||||
<Popover content={`${organization.owner!.fullname} ${organization.owner!.id}`}>
|
||||
<img alt={organization.owner!.fullname} src={avatar(organization.owner)} className="avatar owner" />
|
||||
</Popover>
|
||||
{organization.members!.map(user =>
|
||||
<Popover key={user.id} content={`${user.fullname} ${user.id}`}>
|
||||
<img alt={user.fullname} title={user.fullname} src={avatar(user)} className="avatar" />
|
||||
</Popover>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default OrganizationBlock
|
@ -0,0 +1,177 @@
|
||||
import React from 'react'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import RadioList from '../utils/RadioList'
|
||||
import { FORM, YUP_MSG } from '../../family/UIConst'
|
||||
import { Formik, Field, Form } from 'formik'
|
||||
import { TextField } from 'formik-material-ui'
|
||||
import * as Yup from 'yup'
|
||||
import { Button, Theme, Dialog, Slide, DialogContent, DialogTitle } from '@material-ui/core'
|
||||
import { makeStyles } from '@material-ui/styles'
|
||||
import { TransitionProps } from '@material-ui/core/transitions/transition'
|
||||
import { Organization, RootState } from '../../actions/types'
|
||||
import UserList from '../common/UserList'
|
||||
import AccountService from '../../relatives/services/Account'
|
||||
import * as _ from 'lodash'
|
||||
import { updateOrganization, addOrganization } from '../../actions/organization'
|
||||
import { refresh } from '../../actions/common'
|
||||
|
||||
const useStyles = makeStyles(({ spacing }: Theme) => ({
|
||||
root: {
|
||||
},
|
||||
appBar: {
|
||||
position: 'relative',
|
||||
},
|
||||
title: {
|
||||
marginLeft: spacing(2),
|
||||
flex: 1,
|
||||
},
|
||||
preview: {
|
||||
marginTop: spacing(1),
|
||||
},
|
||||
form: {
|
||||
minWidth: 500,
|
||||
minHeight: 300,
|
||||
},
|
||||
formTitle: {
|
||||
color: 'rgba(0, 0, 0, 0.54)',
|
||||
fontSize: 9,
|
||||
},
|
||||
formItem: {
|
||||
marginBottom: spacing(1),
|
||||
},
|
||||
ctl: {
|
||||
marginTop: spacing(3),
|
||||
},
|
||||
}))
|
||||
|
||||
const schema = Yup.object().shape<Partial<Organization>>({
|
||||
name: Yup.string().required(YUP_MSG.REQUIRED).max(20, YUP_MSG.MAX_LENGTH(20)),
|
||||
description: Yup.string().max(1000, YUP_MSG.MAX_LENGTH(1000)),
|
||||
})
|
||||
|
||||
const FORM_STATE_INIT: Organization = {
|
||||
id: 0,
|
||||
name: '',
|
||||
description: '',
|
||||
members: [],
|
||||
visibility: false,
|
||||
}
|
||||
|
||||
const Transition = React.forwardRef<unknown, TransitionProps>((props, ref) => {
|
||||
return <Slide direction="up" ref={ref} {...props} />
|
||||
})
|
||||
|
||||
interface Props {
|
||||
open: boolean
|
||||
onClose: (isOk?: boolean) => void
|
||||
organization?: Organization
|
||||
}
|
||||
|
||||
function OrganizationForm(props: Props) {
|
||||
const { open, onClose, organization } = props
|
||||
const auth = useSelector((state: RootState) => state.auth)
|
||||
const classes = useStyles()
|
||||
const dispatch = useDispatch()
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={() => onClose()}
|
||||
TransitionComponent={Transition}
|
||||
>
|
||||
<DialogTitle>新建团队</DialogTitle>
|
||||
<DialogContent dividers={true}>
|
||||
<div className={classes.form}>
|
||||
<Formik
|
||||
initialValues={{
|
||||
...FORM_STATE_INIT,
|
||||
...(organization || {}),
|
||||
}}
|
||||
validationSchema={schema}
|
||||
onSubmit={(values) => {
|
||||
const addOrUpdateOrganization = values.id ? updateOrganization : addOrganization
|
||||
const organization: Organization = {
|
||||
...values,
|
||||
memberIds: (values.members || []).map(user => user.id),
|
||||
}
|
||||
const { owner, newOwner } = values
|
||||
if (newOwner && newOwner.id !== owner!.id) { organization.ownerId = newOwner.id }
|
||||
dispatch(addOrUpdateOrganization(organization, () => {
|
||||
dispatch(refresh())
|
||||
onClose(true)
|
||||
}))
|
||||
}}
|
||||
render={({ isSubmitting, setFieldValue, values }) => {
|
||||
function loadUserOptions(input: string): Promise<Array<{ label: string, value: number }>> {
|
||||
return new Promise(async (resolve) => {
|
||||
const users = await AccountService.fetchUserList({ name: input })
|
||||
const options = _.differenceWith(users.data, values.members || [], _.isEqual)
|
||||
resolve(options.map(x => ({ label: `${x.fullname} ${x.empId || x.email}`, value: x.id })))
|
||||
})
|
||||
}
|
||||
return (
|
||||
<Form>
|
||||
<div className="rmodal-body">
|
||||
{values.id > 0 &&
|
||||
<div className={classes.formItem}>
|
||||
<div className={classes.formTitle}>项目Owner</div>
|
||||
{values.owner && (values.owner.id === auth.id)
|
||||
? <UserList
|
||||
isMulti={false}
|
||||
value={values.newOwner ? [{ label: values.newOwner.fullname, value: values.newOwner.id }] : []}
|
||||
loadOptions={loadUserOptions}
|
||||
onChange={(users: any) => setFieldValue('newOwner', users[0])}
|
||||
/>
|
||||
: <div className="pt7 pl9">{values.owner!.fullname}</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div className={classes.formItem}>
|
||||
<RadioList
|
||||
data={FORM.RADIO_LIST_DATA_VISIBILITY}
|
||||
curVal={values.visibility}
|
||||
name="visibility"
|
||||
onChange={(val: any) => setFieldValue('visibility', val)}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.formItem}>
|
||||
<Field
|
||||
name="name"
|
||||
label="团队名称"
|
||||
component={TextField}
|
||||
fullWidth={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.formItem}>
|
||||
<Field
|
||||
name="description"
|
||||
label="描述"
|
||||
component={TextField}
|
||||
fullWidth={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.formItem}>
|
||||
<div className={classes.formTitle}>项目成员</div>
|
||||
<UserList
|
||||
isMulti={true}
|
||||
loadOptions={loadUserOptions}
|
||||
selected={values.members!.map(x => ({ label: x.fullname, value: x.id }))}
|
||||
onChange={selected => setFieldValue('members', selected)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.ctl}>
|
||||
<Button type="submit" variant="contained" color="primary" className="mr1" disabled={isSubmitting}>提交</Button>
|
||||
<Button onClick={() => onClose()} disabled={isSubmitting}>取消</Button>
|
||||
</div>
|
||||
</Form>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default OrganizationForm
|
@ -1,35 +0,0 @@
|
||||
import React, { Component } from 'react'
|
||||
import { PropTypes, connect } from '../../family'
|
||||
import Organization from './Organization'
|
||||
|
||||
// 展示组件
|
||||
class OrganizationList extends Component {
|
||||
// DONE 2.1 补全 propTypes
|
||||
static propTypes = {
|
||||
name: PropTypes.string,
|
||||
organizations: PropTypes.array.isRequired
|
||||
}
|
||||
render () {
|
||||
let { name, organizations } = this.props
|
||||
if (!organizations.length) {
|
||||
return name
|
||||
? <div className='fontsize-14 text-center p40'>没有找到匹配 <strong>{name}</strong> 的团队。</div>
|
||||
: <div className='fontsize-14 text-center p40'>没有数据。</div>
|
||||
}
|
||||
return (
|
||||
<div className='OrganizationList'>
|
||||
{organizations.map(organization =>
|
||||
<Organization key={organization.id} organization={organization} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 容器组件
|
||||
const mapStateToProps = (state) => ({})
|
||||
const mapDispatchToProps = ({})
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(OrganizationList)
|
@ -0,0 +1,29 @@
|
||||
import React, { Component } from 'react'
|
||||
import { PropTypes } from '../../family'
|
||||
import Organization from './Organization'
|
||||
|
||||
// 展示组件
|
||||
class OrganizationList extends Component<any, any> {
|
||||
// DONE 2.1 补全 propTypes
|
||||
static propTypes = {
|
||||
name: PropTypes.string,
|
||||
organizations: PropTypes.array.isRequired,
|
||||
}
|
||||
render() {
|
||||
const { name, organizations } = this.props
|
||||
if (!organizations.length) {
|
||||
return name
|
||||
? <div className="fontsize-14 text-center p40">没有找到匹配 <strong>{name}</strong> 的团队。</div>
|
||||
: <div className="fontsize-14 text-center p40">没有数据。</div>
|
||||
}
|
||||
return (
|
||||
<div className="OrganizationList">
|
||||
{organizations.map((organization: any) =>
|
||||
<Organization key={organization.id} organization={organization} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default OrganizationList
|
@ -1,49 +0,0 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { contextTypes, childContextTypes, getChildContext, CreateButton, SearchGroup, mapDispatchToProps, OrganizationRepositoryListWithSpin, PaginationWithLocation } from '../repository/RepositoryListParts'
|
||||
import { Spin } from '../utils'
|
||||
import '../repository/Repository.css'
|
||||
|
||||
// 展示组件
|
||||
class OrganizationRepositoryList extends Component {
|
||||
static contextTypes = contextTypes
|
||||
static propTypes = {}
|
||||
static childContextTypes = childContextTypes
|
||||
getChildContext = getChildContext.bind(this)
|
||||
render () {
|
||||
let { location, auth, organization, repositories } = this.props
|
||||
if (!organization.id) return <Spin />
|
||||
|
||||
let isOwned = organization.owner.id === auth.id
|
||||
let isJoined = organization.members.find(itme => itme.id === auth.id)
|
||||
return (
|
||||
<section className='RepositoryListWrapper'>
|
||||
<div className='header'><span className='title'>{organization.name}</span></div>
|
||||
<nav className='toolbar clearfix'>
|
||||
{isOwned || isJoined
|
||||
? <CreateButton organization={organization} />
|
||||
: null
|
||||
}
|
||||
<SearchGroup name={location.params.name} />
|
||||
</nav>
|
||||
<div className='body'>
|
||||
<OrganizationRepositoryListWithSpin name={location.params.name} repositories={repositories} />
|
||||
</div>
|
||||
<div className='footer'>
|
||||
<PaginationWithLocation calculated={repositories.pagination} />
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 容器组件
|
||||
const mapStateToProps = (state) => ({
|
||||
auth: state.auth,
|
||||
organization: state.organization,
|
||||
repositories: state.repositories // TODO => organizationRepositories
|
||||
})
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(OrganizationRepositoryList)
|
@ -0,0 +1,46 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { CreateButton, SearchGroup, mapDispatchToProps, OrganizationRepositoryListWithSpin, PaginationWithLocation } from '../repository/RepositoryListParts'
|
||||
import { Spin } from '../utils'
|
||||
import '../repository/Repository.css'
|
||||
import { RootState } from 'actions/types'
|
||||
|
||||
// 展示组件
|
||||
class OrganizationRepositoryList extends Component<any, any> {
|
||||
render() {
|
||||
const { location, auth, organization, repositories } = this.props
|
||||
if (!organization || !organization.id) { return <Spin /> }
|
||||
|
||||
const isOwned = organization.owner.id === auth.id
|
||||
const isJoined = organization.members.find((item: any) => item.id === auth.id)
|
||||
return (
|
||||
<section className="RepositoryListWrapper">
|
||||
<div className="header"><span className="title">{organization.name}</span></div>
|
||||
<nav className="toolbar clearfix">
|
||||
{isOwned || isJoined
|
||||
? <CreateButton organization={organization} />
|
||||
: null
|
||||
}
|
||||
<SearchGroup name={location.params.name} />
|
||||
</nav>
|
||||
<div className="body">
|
||||
<OrganizationRepositoryListWithSpin name={location.params.name} repositories={repositories} />
|
||||
</div>
|
||||
<div className="footer">
|
||||
<PaginationWithLocation calculated={repositories.pagination} />
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 容器组件
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
auth: state.auth,
|
||||
organization: state.organization,
|
||||
repositories: state.repositories, // TODO => organizationRepositories
|
||||
})
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(OrganizationRepositoryList)
|
@ -1,38 +0,0 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { contextTypes, childContextTypes, getChildContext, RepositoriesTypeDropdown, SearchGroup, mapDispatchToProps, RepositoryListWithSpin, PaginationWithLocation } from './RepositoryListParts'
|
||||
import './Repository.css'
|
||||
|
||||
// 全部仓库
|
||||
class AllRepositoryList extends Component {
|
||||
static contextTypes = contextTypes
|
||||
static propTypes = {}
|
||||
static childContextTypes = childContextTypes
|
||||
getChildContext = getChildContext.bind(this)
|
||||
render () {
|
||||
let { location, match, repositories } = this.props
|
||||
return (
|
||||
<section className='RepositoryListWrapper'>
|
||||
<nav className='toolbar clearfix'>
|
||||
<RepositoriesTypeDropdown url={match.url} />
|
||||
<SearchGroup name={location.params.name} />
|
||||
</nav>
|
||||
<div className='body'>
|
||||
<RepositoryListWithSpin name={location.params.name} repositories={repositories} />
|
||||
</div>
|
||||
<div className='footer'>
|
||||
<PaginationWithLocation calculated={repositories.pagination} />
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
joiner: state.auth,
|
||||
repositories: state.repositories
|
||||
})
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(AllRepositoryList)
|
@ -0,0 +1,35 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { RepositoriesTypeDropdown, SearchGroup, mapDispatchToProps, RepositoryListWithSpin, PaginationWithLocation } from './RepositoryListParts'
|
||||
import './Repository.css'
|
||||
import { RootState } from 'actions/types'
|
||||
|
||||
// 全部仓库
|
||||
class AllRepositoryList extends Component<any, any> {
|
||||
render() {
|
||||
const { location, match, repositories } = this.props
|
||||
return (
|
||||
<section className="RepositoryListWrapper">
|
||||
<nav className="toolbar clearfix">
|
||||
<RepositoriesTypeDropdown url={match.url} />
|
||||
<SearchGroup name={location.params.name} />
|
||||
</nav>
|
||||
<div className="body">
|
||||
<RepositoryListWithSpin name={location.params.name} repositories={repositories} />
|
||||
</div>
|
||||
<div className="footer">
|
||||
<PaginationWithLocation calculated={repositories.pagination} />
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
joiner: state.auth,
|
||||
repositories: state.repositories,
|
||||
})
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(AllRepositoryList)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue