Skip to content
This repository has been archived by the owner on Aug 4, 2020. It is now read-only.

Commit

Permalink
Only make api calls and state updates that are needed, update messeng…
Browse files Browse the repository at this point in the history
…er component to support autoclosing messages after timeout, now that there is no flashing after saving a secret add message for user on sercret save
  • Loading branch information
fieldju committed Dec 14, 2016
1 parent cf488fd commit a776c68
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 30 deletions.
86 changes: 71 additions & 15 deletions app/actions/manageSafetyDepositBoxActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ export function removeVaultSecretFromLocalStore(key) {
}
}

export function removeVaultNodePathKeyFromLocalStore(key) {
return {
type: actions.REMOVE_VAULT_KEY_FROM_LOCAL_STORE,
payload: key
}
}

export function showAddNewVaultSecret() {
return {
type: actions.SHOW_ADD_SECRET_FORM
Expand All @@ -154,31 +161,34 @@ export function hideAddNewVaultSecret() {
}
}

export function commitSecret(navigatedPath, data, token) {
export function commitSecret(navigatedPath, data, token, isNewVaultPath) {
let vaultData = {}
let key = data.path
let fullPath = `${navigatedPath}${key}`

data.kvMap.map((entry) => {
log.info("entry", entry)
vaultData[entry.key] = entry.value
})

log.info(vaultData)

return function (dispatch) {
let nestedFolder = key.split('/').length > 1;
// let the UI / state know that we are saving the secret, so that the user can't spam the save button
// but only if not a nested folder
if (! nestedFolder) {
dispatch(savingVaultSecret(fullPath))
}

// save the secret
axios({
method: 'post',
url: `/v1/secret/${navigatedPath}${data.path}`,
url: `/v1/secret/${fullPath}`,
data: vaultData,
headers: {'X-Vault-Token': token},
timeout: 60 * 1000 // 1 minute
})
.then((response) => {
log.info("SUCCESS", response)
var fullPath = `${navigatedPath}${data.path}`

dispatch(storeVaultSecret(fullPath, {}))
dispatch(savingVaultSecret(fullPath))
dispatch(fetchVaultPathKeys(navigatedPath, token))
dispatch(getVaultSecret(fullPath, token))
// once saved we can use the data we have locally to update the state, without additional API calls
dispatch(updateLocalStateAfterSaveCommit(navigatedPath, key, vaultData, isNewVaultPath))
})
.catch((response) => {
log.error("Failed to save Vault Secret data", response)
Expand All @@ -187,10 +197,49 @@ export function commitSecret(navigatedPath, data, token) {
}
}

/**
* After posting a secret to Vault we can update the local state to represent the new data
*
* @param prefix, the partial path to Vault Node / Secret (Sort of like a virtual folder)
* @param key, the key to the Vault Node / Secret
* @param data, the Vault secret data that was saved, we can store this and save an API call
* @param isNewVaultPath, boolean, if its a new secret we need to hide the add new form
*/
export function updateLocalStateAfterSaveCommit(prefix, key, data, isNewVaultPath) {
return (dispatch) => {
// we will only store the data, if its not in a nested virtual folder
let addSecretData = true;

// Update the piece of state that stores the keys that are available for the given navigated path.
// if a user added a nested secret that is in a folder
// ex: foo/bar/bam we would want to add foo/ to the state, so the folder foo shows up in the ui
let pieces = key.split('/')
if (pieces.length > 1) {
key = pieces[0] + '/'
addSecretData = false
}
dispatch(updateStoredKeys(key))

// Update the stored vault secret data for the given complete path, if the key is not a virtual folder
if (addSecretData) {
log.info('ADDING KEY DATA')
dispatch(storeVaultSecret(`${prefix}${key}`, data))
}

// if this is a new vault path remove the create new form
if (isNewVaultPath) {
dispatch(hideAddNewVaultSecret())
}

// finally lets let the user know we saved there data
dispatch(messengerActions.addNewMessageWithTimeout(`Successfully saved Vault secret at path: ${prefix}${key}`, 2500))
}
}

export function deleteVaultPathConfirm(navigatedPath, label, token) {
return (dispatch) => {
let yes = () => {
dispatch(deleteVaultPath(`${navigatedPath}`,`${label}`, token))
dispatch(deleteVaultPath(navigatedPath, label, token))
dispatch(modalActions.popModal())
}

Expand All @@ -216,8 +265,8 @@ export function deleteVaultPath(navigatedPath, label, token) {
timeout: 60 * 1000 // 1 minute
})
.then((response) => {
log.info("SUCCESS", response)
dispatch(fetchVaultPathKeys(navigatedPath, token))
dispatch(removeVaultSecretFromLocalStore(`${navigatedPath}${label}`))
dispatch(removeVaultNodePathKeyFromLocalStore(label))
})
.catch((response) => {
log.error("Failed to delete Vault Secret", response)
Expand Down Expand Up @@ -311,3 +360,10 @@ export function savingVaultSecret(path) {
payload: path
}
}

export function updateStoredKeys(key) {
return {
type: actions.ADD_VAULT_KEY_IF_NOT_PRESET,
payload: key
}
}
32 changes: 28 additions & 4 deletions app/actions/messengerActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,47 @@ import * as constants from '../constants/actions'
* adds a message to the messenger
* @param message A string or JSX element to be rendered in the messenger component
*/
export function addNewMessage(message) {
export function addNewMessage(message, id) {
window.scrollTo(0, 0)
return {
type: constants.ADD_MESSAGE,
payload: message
payload: {
message: message,
id: id ? id : guid()
}
}
}

export function removeMessage(indexToRemove) {
export function addNewMessageWithTimeout(message, timeout) {
return (dispatch => {
let id = guid()

dispatch(addNewMessage(message, id))
setTimeout(() => {
dispatch(removeMessage(id))
}, timeout)
})
}

export function removeMessage(id) {
return {
type: constants.REMOVE_MESSAGE,
payload: indexToRemove
payload: id
}
}

export function clearAllMessages() {
return {
type: constants.CLEAR_ALL_MESSAGES
}
}

function guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
4 changes: 2 additions & 2 deletions app/components/Messenger/Messenger.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ export default class Messenger extends Component {
<div id='messenger-container'>
{messages.map((message, index) =>
<div className="messenger-message" key={index}>
<div className="messenger-message-content">{message}</div>
<div className="messenger-message-content">{message.message}</div>
<div className="messenger-message-buttons">
<div className="messenger-message-buttons-acknowledge" onClick={() => {
dispatch(messengerActions.removeMessage(index))}
dispatch(messengerActions.removeMessage(message.id))}
}></div>
</div>
</div>
Expand Down
6 changes: 4 additions & 2 deletions app/components/VaultSecretForm/VaultSecretForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ export default class VaultSecretForm extends Component {
vaultToken,
handleSubmit,
pathReadOnly,
vaultSecretsData
vaultSecretsData,
formKey
} = this.props

return(
<div id="vault-add-new-secret-container">
<form id='vault-add-new-secret-form' onSubmit={handleSubmit( data => {
dispatch(mSDBActions.commitSecret(navigatedPath, data, vaultToken))
let isNewVaultPath = formKey == 'add-new-secret'
dispatch(mSDBActions.commitSecret(navigatedPath, data, vaultToken, isNewVaultPath))
})}>
<div id='new-vault-secret-path'>
<div id='new-vault-secret-path-label'>Path:</div>
Expand Down
2 changes: 2 additions & 0 deletions app/constants/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const SUBMITTED_NEW_SDB_REQUEST = 'SUBMITTED_NEW_SDB_REQUEST'
export const FETCHING_VAULT_SECRET = 'FETCHING_VAULT_SECRET'
export const FETCHED_VAULT_SECRET = 'FETCHED_VAULT_SECRET'
export const REMOVE_SECRET_FROM_LOCAL_STORE = 'REMOVE_SECRET_FROM_LOCAL_STORE'
export const REMOVE_VAULT_KEY_FROM_LOCAL_STORE = 'REMOVE_VAULT_KEY_FROM_LOCAL_STORE'
export const STORE_SDB_DATA = 'STORE_SDB_DATA'
export const TOGGLE_PERM_VIS = 'TOGGLE_PERM_VIS'
export const FETCHING_VAULT_KEYS = 'FETCHING_VAULT_KEYS'
Expand All @@ -41,6 +42,7 @@ export const SUBMITTING_EDIT_SDB_REQUEST = 'SUBMITTING_EDIT_SDB_REQUEST'
export const RESET_SUBMITTING_EDIT_SDB_REQUEST = 'RESET_SUBMITTING_EDIT_SDB_REQUEST'
export const CLEAR_VAULT_DATA = 'CLEAR_VAULT_DATA'
export const SAVING_VAULT_SECRET = 'SAVING_VAULT_SECRET'
export const ADD_VAULT_KEY_IF_NOT_PRESET = 'ADD_VAULT_KEY_IF_NOT_PRESET'

// Messenger
export const ADD_MESSAGE = 'ADD_MESSAGE'
Expand Down
42 changes: 39 additions & 3 deletions app/reducers/manageSafetyDepositBoxReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,44 @@ export default createReducer(initialState, {
hasFetchedKeys: true
})
},
[action.ADD_VAULT_KEY_IF_NOT_PRESET]: (state, payload) => {
let existingList = state.vaultPathKeys
let keyToAddIfMissing = payload
let newList = []
let isKeyPreset = false

for (let key in existingList) {
let value = existingList[key]
if (value == keyToAddIfMissing) {
isKeyPreset = true
}
newList.push(value)
}

if (! isKeyPreset) {
newList.push(keyToAddIfMissing)
}

return Object.assign({}, state, {
vaultPathKeys: newList
})
},
[action.REMOVE_VAULT_KEY_FROM_LOCAL_STORE]: (state, payload) => {
let existingList = state.vaultPathKeys
let newList = []
let keyToRemove = payload

for (let key in existingList) {
let value = existingList[key]
if (keyToRemove != value) {
newList.push(value)
}
}

return Object.assign({}, state, {
vaultPathKeys: newList
})
},
[action.FETCHING_VAULT_KEYS]: (state) => {
return Object.assign({}, state, {
hasFetchedKeys: false
Expand Down Expand Up @@ -143,13 +181,11 @@ export default createReducer(initialState, {
isFetching: false,
isUpdating: true,
isActive: true,
data: existingMap[fetchingKey]["data"]
data: existingMap[fetchingKey] ? existingMap[fetchingKey]['data'] : {}
}


return Object.assign({}, state, {
vaultSecretsData: newMap
})
}

})
11 changes: 7 additions & 4 deletions app/reducers/messengerReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export default createReducer(initialState, {
newMessages.push(message)
})

newMessages.push(payload)
newMessages.push({
message: payload.message,
id: payload.id
})

log.info("New Messages", newMessages)

Expand All @@ -27,10 +30,10 @@ export default createReducer(initialState, {
let currentMessages = state.messages
let newMessages = []
//noinspection JSUnresolvedVariable
let indexToRemove = payload
let idToRemove = payload

currentMessages.forEach((message, index) => {
if (index != indexToRemove) {
currentMessages.forEach((message) => {
if (message.id != idToRemove) {
newMessages.push(message)
}
})
Expand Down

0 comments on commit a776c68

Please sign in to comment.