Hook up DBRP manager to backend

pull/1029/head
Andrew Watkins 2017-03-23 15:06:22 -07:00
parent 2c874e4e53
commit 9280741773
7 changed files with 136 additions and 54 deletions

View File

@ -1,25 +1,25 @@
import uuid from 'node-uuid';
import {
getUsers as getUsersAJAX,
getRoles as getRolesAJAX,
getPermissions as getPermissionsAJAX,
getDbsAndRps as getDbsAndRpsAJAX,
createUser as createUserAJAX,
createRole as createRoleAJAX,
createDatabase as createDatabaseAJAX,
createRetentionPolicy as createRetentionPolicyAJAX,
deleteUser as deleteUserAJAX,
deleteRole as deleteRoleAJAX,
deleteDatabase as deleteDatabaseAJAX,
deleteRetentionPolicy as deleteRetentionPolicyAJAX,
updateRole as updateRoleAJAX,
updateUser as updateUserAJAX,
updateRetentionPolicy as updateRetentionPolicyAJAX,
} from 'src/admin/apis'
import {
killQuery as killQueryProxy,
showDatabases,
showRetentionPolicies,
} from 'shared/apis/metaQuery'
import parseShowDatabases from 'src/shared/parsing/showDatabases'
import parseShowRetentionPolicies from 'src/shared/parsing/showRetentionPolicies'
import {publishNotification} from 'src/shared/actions/notifications';
import {ADMIN_NOTIFICATION_DELAY} from 'src/admin/constants'
@ -94,6 +94,16 @@ export const syncDatabase = (stale, synced) => ({
},
})
export const syncRetentionPolicy = (database, stale, synced) => ({
type: 'SYNC_RETENTION_POLICY',
payload: {
database,
stale,
synced,
},
})
export const editUser = (user, updates) => ({
type: 'EDIT_USER',
payload: {
@ -224,19 +234,8 @@ export const loadPermissionsAsync = (url) => async (dispatch) => {
}
export const loadDBsAndRPsAsync = (url) => async (dispatch) => {
const {data: dbs} = await showDatabases(url)
const {databases} = parseShowDatabases(dbs)
const {data: {results}} = await showRetentionPolicies(url, databases)
const retentionPolicies = results.map(parseShowRetentionPolicies)
const rps = retentionPolicies.map(rp => rp.retentionPolicies)
const dbsAndRps = databases.map((name, i) => ({
name,
links: {self: uuid.v4()},
retentionPolicies: rps[i].map(rp => ({...rp, links: {self: uuid.v4()}})),
}))
dispatch(loadDatabases(dbsAndRps))
const {data: {databases}} = await getDbsAndRpsAJAX(url)
dispatch(loadDatabases(databases))
}
export const createUserAsync = (url, user) => async (dispatch) => {
@ -265,10 +264,9 @@ export const createRoleAsync = (url, role) => async (dispatch) => {
export const createDatabaseAsync = (url, database) => async (dispatch) => {
try {
// TODO: implement once server is up
// const {data} = await createDatabaseAJAX(url, database)
const {data} = await createDatabaseAJAX(url, database)
dispatch(syncDatabase(database, data))
dispatch(publishNotification('success', 'Database created successfully'))
// dispatch(syncDatabase(database, {...data, id: uuid.v4()}))
} catch (error) {
// undo optimistic update
dispatch(publishNotification('error', `Failed to create database: ${error.data.message}`))
@ -276,26 +274,24 @@ export const createDatabaseAsync = (url, database) => async (dispatch) => {
}
}
export const createRetentionPolicyAsync = (url, retentionPolicy) => async (dispatch) => {
export const createRetentionPolicyAsync = (database, retentionPolicy) => async (dispatch) => {
try {
// TODO: implement once server is up
// const {data} = await createRetentionPolicyAJAX(url, retentionPolicy)
const {data} = await createRetentionPolicyAJAX(database.links.retentionPolicies, retentionPolicy)
dispatch(publishNotification('success', 'Retention policy created successfully'))
// dispatch(syncRetentionPolicy(retentionPolicy, {...data, id: uuid.v4()}))
dispatch(syncRetentionPolicy(database, retentionPolicy, data))
} catch (error) {
// undo optimistic update
dispatch(publishNotification('error', `Failed to create retention policy: ${error.data.message}`))
setTimeout(() => dispatch(removeRetentionPolicy(retentionPolicy)), ADMIN_NOTIFICATION_DELAY)
setTimeout(() => dispatch(removeRetentionPolicy(database, retentionPolicy)), ADMIN_NOTIFICATION_DELAY)
}
}
export const updateRetentionPolicyAsync = (database, retentionPolicy, updates) => async (dispatch) => {
try {
// TODO: implement once server is up
dispatch(editRetentionPolicy(database, retentionPolicy, updates))
// const {data} = await createRetentionPolicyAJAX(url, retentionPolicy)
const {data} = await updateRetentionPolicyAJAX(retentionPolicy.links.self, updates)
dispatch(publishNotification('success', 'Retention policy updated successfully'))
// dispatch(syncRetentionPolicy(retentionPolicy, {...data, id: uuid.v4()}))
dispatch(syncRetentionPolicy(database, data))
} catch (error) {
dispatch(publishNotification('error', `Failed to update retention policy: ${error.data.message}`))
}
@ -326,16 +322,24 @@ export const deleteUserAsync = (user, addFlashMessage) => (dispatch) => {
deleteUserAJAX(user.links.self, addFlashMessage, user.name)
}
export const deleteDatabaseAsync = (url, database) => (dispatch) => {
export const deleteDatabaseAsync = (database) => async (dispatch) => {
dispatch(removeDatabase(database))
dispatch(publishNotification('success', 'Database deleted'))
try {
await deleteDatabaseAJAX(database.links.self)
} catch (error) {
dispatch(publishNotification('error', `Failed to delete database: ${error.data.message}`))
}
}
// TODO: implement once server is up
// try {
// await deleteDatabaseAJAX(url, database.name)
// } catch (error) {
// dispatch(publishNotification('error', `Failed to delete database: ${error.data.message}`))
// }
export const deleteRetentionPolicyAsync = (database, retentionPolicy) => async (dispatch) => {
dispatch(removeRetentionPolicy(database, retentionPolicy))
dispatch(publishNotification('success', `Retention policy ${retentionPolicy.name} deleted`))
try {
await deleteRetentionPolicyAJAX(retentionPolicy.links.self)
} catch (error) {
dispatch(publishNotification('error', `Failed to delete retentionPolicy: ${error.data.message}`))
}
}
export const updateRoleUsersAsync = (role, users) => async (dispatch) => {

View File

@ -36,6 +36,18 @@ export const getPermissions = async (url) => {
}
}
export const getDbsAndRps = async (url) => {
try {
return await AJAX({
method: 'GET',
url,
})
} catch (error) {
console.error(error)
throw error
}
}
export const createUser = async (url, user) => {
try {
return await AJAX({
@ -84,6 +96,17 @@ export const createRetentionPolicy = async (url, retentionPolicy) => {
}
}
export const deleteRetentionPolicy = async (url) => {
try {
return await AJAX({
method: 'DELETE',
url,
})
} catch (error) {
throw error
}
}
export const deleteRole = async (url, addFlashMessage, rolename) => {
try {
const response = await AJAX({
@ -124,11 +147,11 @@ export const deleteUser = async (url, addFlashMessage, username) => {
}
}
export const deleteDatabase = async (url, name) => {
export const deleteDatabase = async (url) => {
try {
return await AJAX({
method: 'DELETE',
url: `${url}/${name}`,
url,
})
} catch (error) {
console.error(error)
@ -167,3 +190,18 @@ export const updateUser = async (url, roles, permissions) => {
throw error
}
}
export const updateRetentionPolicy = async (url, retentionPolicy) => {
try {
return await AJAX({
method: 'PUT',
url,
data: {
retentionPolicy,
},
})
} catch (error) {
console.error(error)
throw error
}
}

View File

@ -18,6 +18,7 @@ const DatabaseManager = ({
onCreateRetentionPolicy,
onUpdateRetentionPolicy,
onRemoveRetentionPolicy,
onDeleteRetentionPolicy,
}) => {
return (
<div className="panel panel-info">
@ -45,6 +46,7 @@ const DatabaseManager = ({
onCreateRetentionPolicy={onCreateRetentionPolicy}
onUpdateRetentionPolicy={onUpdateRetentionPolicy}
onRemoveRetentionPolicy={onRemoveRetentionPolicy}
onDeleteRetentionPolicy={onDeleteRetentionPolicy}
/>
)
}
@ -78,6 +80,7 @@ DatabaseManager.propTypes = {
onCreateRetentionPolicy: func,
onUpdateRetentionPolicy: func,
onRemoveRetentionPolicy: func,
onDeleteRetentionPolicy: func,
}
export default DatabaseManager

View File

@ -8,6 +8,7 @@ class DatabaseRow extends Component {
super(props)
this.state = {
isEditing: false,
isDeleting: false,
}
this.handleKeyDown = ::this.handleKeyDown
this.handleClickOutside = ::this.handleClickOutside
@ -16,6 +17,8 @@ class DatabaseRow extends Component {
this.handleCreate = ::this.handleCreate
this.handleUpdate = ::this.handleUpdate
this.getInputValues = ::this.getInputValues
this.handleStartDelete = ::this.handleStartDelete
this.handleEndDelete = ::this.handleEndDelete
}
componentWillMount() {
@ -30,12 +33,14 @@ class DatabaseRow extends Component {
retentionPolicy: {name, duration, replication, isDefault, isNew},
retentionPolicy,
database,
onDelete,
isRFDisplayed,
} = this.props
const {isEditing, isDeleting} = this.state
const formattedDuration = formatInfiniteDuration(duration)
if (this.state.isEditing) {
if (isEditing) {
return (
<tr>
<td>
@ -72,7 +77,7 @@ class DatabaseRow extends Component {
name="name"
type="number"
min="1"
defaultValue={replication}
defaultValue={replication || 1}
placeholder="how many nodes do you have"
onKeyDown={(e) => this.handleKeyDown(e, database)}
ref={(r) => this.replication = r}
@ -95,9 +100,13 @@ class DatabaseRow extends Component {
<td onClick={this.handleStartEdit}>{formattedDuration}</td>
{isRFDisplayed ? <td onClick={this.handleStartEdit}>{replication}</td> : null}
<td className="text-right">
<button className="btn btn-xs btn-danger admin-table--delete">
{`Delete ${name}`}
</button>
{
isDeleting ?
<YesNoButtons onConfirm={() => onDelete(database, retentionPolicy)} onCancel={this.handleEndDelete} /> :
<button className="btn btn-xs btn-danger admin-table--delete" onClick={this.handleStartDelete}>
{`Delete ${name}`}
</button>
}
</td>
</tr>
)
@ -105,6 +114,7 @@ class DatabaseRow extends Component {
handleClickOutside() {
this.handleEndEdit()
this.handleEndDelete()
}
handleStartEdit() {
@ -115,14 +125,22 @@ class DatabaseRow extends Component {
this.setState({isEditing: false})
}
handleStartDelete() {
this.setState({isDeleting: true})
}
handleEndDelete() {
this.setState({isDeleting: false})
}
handleCreate() {
const {database, onCreate} = this.props
const {database, retentionPolicy, onCreate} = this.props
const validInputs = this.getInputValues()
if (!validInputs) {
return
}
onCreate(database, validInputs)
onCreate(database, {...retentionPolicy, ...validInputs})
this.handleEndEdit()
}
@ -205,6 +223,7 @@ DatabaseRow.propTypes = {
onRemove: func,
onCreate: func,
onUpdate: func,
onDelete: func,
notify: func,
isRFDisplayed: bool,
}

View File

@ -22,6 +22,7 @@ const DatabaseTable = ({
onCreateRetentionPolicy,
onUpdateRetentionPolicy,
onRemoveRetentionPolicy,
onDeleteRetentionPolicy,
}) => {
return (
<div className="db-manager">
@ -57,6 +58,7 @@ const DatabaseTable = ({
onCreate={onCreateRetentionPolicy}
onUpdate={onUpdateRetentionPolicy}
onRemove={onRemoveRetentionPolicy}
onDelete={onDeleteRetentionPolicy}
isRFDisplayed={isRFDisplayed}
/>
)
@ -84,6 +86,7 @@ DatabaseTable.propTypes = {
onCreateRetentionPolicy: func,
onUpdateRetentionPolicy: func,
onRemoveRetentionPolicy: func,
onDeleteRetentionPolicy: func,
}
const DatabaseTableHeader = ({

View File

@ -15,9 +15,9 @@ class DatabaseManagerPage extends Component {
}
componentDidMount() {
const {source: {links: {proxy}}, actions} = this.props
const {source: {links: {databases}}, actions} = this.props
actions.loadDBsAndRPsAsync(proxy)
actions.loadDBsAndRPsAsync(databases)
}
render() {
@ -39,23 +39,24 @@ class DatabaseManagerPage extends Component {
onCreateRetentionPolicy={actions.createRetentionPolicyAsync}
onUpdateRetentionPolicy={actions.updateRetentionPolicyAsync}
onRemoveRetentionPolicy={actions.removeRetentionPolicy}
onDeleteRetentionPolicy={actions.deleteRetentionPolicyAsync}
/>
)
}
handleCreateDatabase(database) {
const {actions, notify} = this.props
const {actions, notify, source} = this.props
if (!database.name) {
return notify('error', 'Database name cannot be blank')
}
actions.createDatabaseAsync(database)
actions.createDatabaseAsync(source.links.databases, database)
}
handleKeyDownDatabase(e, database) {
const {key} = e
const {actions, notify} = this.props
const {actions, notify, source} = this.props
if (key === 'Escape') {
actions.removeDatabase(database)
@ -66,13 +67,13 @@ class DatabaseManagerPage extends Component {
return notify('error', 'Database name cannot be blank')
}
actions.createDatabaseAsync(database)
actions.createDatabaseAsync(source.links.databases, database)
}
}
handleDatabaseDeleteConfirm(database, e) {
const {key, target: {value}} = e
const {actions, source, notify} = this.props
const {actions, notify} = this.props
if (key === 'Escape') {
return actions.removeDatabaseDeleteCode(database)
@ -83,7 +84,7 @@ class DatabaseManagerPage extends Component {
return notify('error', `Please type DELETE ${database.name} to confirm`)
}
return actions.deleteDatabaseAsync(source, database)
return actions.deleteDatabaseAsync(database)
}
actions.editDatabase(database, {deleteCode: value})
@ -125,6 +126,7 @@ DatabaseManagerPage.propTypes = {
startDeleteDatabase: func,
removeDatabaseDeleteCode: func,
removeRetentionPolicy: func,
deleteRetentionPolicyAsync: func,
}),
notify: func,
}

View File

@ -99,6 +99,19 @@ export default function admin(state = initialState, action) {
const newState = {
databases: state.databases.map(db => db.links.self === stale.links.self ? {...synced} : db),
}
return {...state, ...newState}
}
case 'SYNC_RETENTION_POLICY': {
const {database, stale, synced} = action.payload
const newState = {
databases: state.databases.map(db => db.links.self === database.links.self ? {
...db,
retentionPolicies: db.retentionPolicies.map(rp => rp.links.self === stale.links.self ? {...synced} : rp),
} : db),
}
return {...state, ...newState}
}