Move & rename Settings boilerplate to dedicated shared Config boilerplate

pull/10616/head
Jared Scheib 2017-12-12 14:39:40 -08:00
parent 2119dcb60a
commit 74ffdab074
10 changed files with 160 additions and 130 deletions

View File

@ -10,8 +10,6 @@ import {
createOrganization as createOrganizationAJAX, createOrganization as createOrganizationAJAX,
updateOrganization as updateOrganizationAJAX, updateOrganization as updateOrganizationAJAX,
deleteOrganization as deleteOrganizationAJAX, deleteOrganization as deleteOrganizationAJAX,
getAuthSettings as getAuthSettingsAJAX,
updateAuthSettings as updateAuthSettingsAJAX,
} from 'src/admin/apis/chronograf' } from 'src/admin/apis/chronograf'
import {publishAutoDismissingNotification} from 'shared/dispatchers' import {publishAutoDismissingNotification} from 'shared/dispatchers'
@ -96,39 +94,6 @@ export const removeOrganization = organization => ({
}, },
}) })
export const getAuthSettingsRequested = () => ({
type: 'CHRONOGRAF_GET_AUTH_SETTINGS_REQUESTED',
})
export const getAuthSettingsCompleted = authSettings => ({
type: 'CHRONOGRAF_GET_AUTH_SETTINGS_COMPLETED',
payload: {
authSettings,
},
})
export const getAuthSettingsFailed = () => ({
type: 'CHRONOGRAF_GET_AUTH_SETTINGS_FAILED',
})
export const updateAuthSettingsRequested = authSettings => ({
type: 'CHRONOGRAF_UPDATE_AUTH_SETTINGS_REQUESTED',
payload: {
authSettings,
},
})
export const updateAuthSettingsCompleted = () => ({
type: 'CHRONOGRAF_UPDATE_AUTH_SETTINGS_COMPLETED',
})
export const updateAuthSettingsFailed = authSettings => ({
type: 'CHRONOGRAF_UPDATE_AUTH_SETTINGS_FAILED',
payload: {
authSettings,
},
})
// async actions (thunks) // async actions (thunks)
export const loadUsersAsync = url => async dispatch => { export const loadUsersAsync = url => async dispatch => {
try { try {
@ -266,30 +231,3 @@ export const deleteOrganizationAsync = organization => async dispatch => {
dispatch(addOrganization(organization)) dispatch(addOrganization(organization))
} }
} }
export const getAuthSettingsAsync = url => async dispatch => {
dispatch(getAuthSettingsRequested())
try {
const {data} = await getAuthSettingsAJAX(url)
dispatch(getAuthSettingsCompleted(data)) // TODO: change authSettings in actions & reducers to reflect final shape
} catch (error) {
dispatch(errorThrown(error))
dispatch(getAuthSettingsFailed())
}
}
export const updateAuthSettingsAsync = (
url,
oldAuthSettings,
updatedAuthSettings
) => async dispatch => {
const newAuthSettings = {...oldAuthSettings, ...updatedAuthSettings}
dispatch(updateAuthSettingsRequested(newAuthSettings))
try {
await updateAuthSettingsAJAX(url, newAuthSettings)
dispatch(updateAuthSettingsCompleted())
} catch (error) {
dispatch(errorThrown(error))
dispatch(updateAuthSettingsFailed(oldAuthSettings))
}
}

View File

@ -102,28 +102,3 @@ export const deleteOrganization = async organization => {
throw error throw error
} }
} }
export const getAuthSettings = async url => {
try {
return await AJAX({
method: 'GET',
url,
})
} catch (error) {
console.error(error)
throw error
}
}
export const updateAuthSettings = async (url, authSettings) => {
try {
return await AJAX({
method: 'PATCH',
url,
data: authSettings,
})
} catch (error) {
console.error(error)
throw error
}
}

View File

@ -34,9 +34,9 @@ class OrganizationsTable extends Component {
this.setState({isCreatingOrganization: false}) this.setState({isCreatingOrganization: false})
} }
handleChangeAuthSettingsSuperAdminFirstUserOnly = superAdminFirstUserOnly => { handleChangeAuthConfigSuperAdminFirstUserOnly = superAdminFirstUserOnly => {
const {onUpdateAuthSettings} = this.props const {onUpdateAuthConfig} = this.props
onUpdateAuthSettings({superAdminFirstUserOnly}) onUpdateAuthConfig({superAdminFirstUserOnly})
} }
render() { render() {
@ -47,7 +47,7 @@ class OrganizationsTable extends Component {
onChooseDefaultRole, onChooseDefaultRole,
onTogglePublic, onTogglePublic,
currentOrganization, currentOrganization,
authSettings: {superAdminFirstUserOnly}, authConfig: {superAdminFirstUserOnly},
} = this.props } = this.props
const {isCreatingOrganization} = this.state const {isCreatingOrganization} = this.state
@ -102,7 +102,7 @@ class OrganizationsTable extends Component {
<table className="table v-center superadmin-settings"> <table className="table v-center superadmin-settings">
<thead> <thead>
<tr> <tr>
<th style={{width: 70}}>Settings</th> <th style={{width: 70}}>Config</th>
<th /> <th />
</tr> </tr>
</thead> </thead>
@ -113,7 +113,7 @@ class OrganizationsTable extends Component {
size="xs" size="xs"
active={superAdminFirstUserOnly} active={superAdminFirstUserOnly}
onToggle={ onToggle={
this.handleChangeAuthSettingsSuperAdminFirstUserOnly this.handleChangeAuthConfigSuperAdminFirstUserOnly
} }
/> />
</td> </td>
@ -146,9 +146,9 @@ OrganizationsTable.propTypes = {
onRenameOrg: func.isRequired, onRenameOrg: func.isRequired,
onTogglePublic: func.isRequired, onTogglePublic: func.isRequired,
onChooseDefaultRole: func.isRequired, onChooseDefaultRole: func.isRequired,
onUpdateAuthSettings: func.isRequired, onUpdateAuthConfig: func.isRequired,
authSettings: shape({ authConfig: shape({
superAdminFirstUserOnly: bool.isRequired, superAdminFirstUserOnly: bool,
}), }),
} }
export default OrganizationsTable export default OrganizationsTable

View File

@ -3,6 +3,7 @@ import {connect} from 'react-redux'
import {bindActionCreators} from 'redux' import {bindActionCreators} from 'redux'
import * as adminChronografActionCreators from 'src/admin/actions/chronograf' import * as adminChronografActionCreators from 'src/admin/actions/chronograf'
import * as configActionCreators from 'shared/actions/config'
import {getMeAsync} from 'shared/actions/auth' import {getMeAsync} from 'shared/actions/auth'
import OrganizationsTable from 'src/admin/components/chronograf/OrganizationsTable' import OrganizationsTable from 'src/admin/components/chronograf/OrganizationsTable'
@ -11,26 +12,27 @@ class OrganizationsPage extends Component {
componentDidMount() { componentDidMount() {
const { const {
links, links,
actions: {loadOrganizationsAsync, getAuthSettingsAsync}, actionsAdmin: {loadOrganizationsAsync},
actionsConfig: {getAuthConfigAsync},
} = this.props } = this.props
loadOrganizationsAsync(links.organizations) loadOrganizationsAsync(links.organizations)
getAuthSettingsAsync(links.config) getAuthConfigAsync(links.config)
} }
handleCreateOrganization = async organization => { handleCreateOrganization = async organization => {
const {links, actions: {createOrganizationAsync}} = this.props const {links, actionsAdmin: {createOrganizationAsync}} = this.props
await createOrganizationAsync(links.organizations, organization) await createOrganizationAsync(links.organizations, organization)
this.refreshMe() this.refreshMe()
} }
handleRenameOrganization = async (organization, name) => { handleRenameOrganization = async (organization, name) => {
const {actions: {updateOrganizationAsync}} = this.props const {actionsAdmin: {updateOrganizationAsync}} = this.props
await updateOrganizationAsync(organization, {...organization, name}) await updateOrganizationAsync(organization, {...organization, name})
this.refreshMe() this.refreshMe()
} }
handleDeleteOrganization = organization => { handleDeleteOrganization = organization => {
const {actions: {deleteOrganizationAsync}} = this.props const {actionsAdmin: {deleteOrganizationAsync}} = this.props
deleteOrganizationAsync(organization) deleteOrganizationAsync(organization)
this.refreshMe() this.refreshMe()
} }
@ -41,7 +43,7 @@ class OrganizationsPage extends Component {
} }
handleTogglePublic = organization => { handleTogglePublic = organization => {
const {actions: {updateOrganizationAsync}} = this.props const {actionsAdmin: {updateOrganizationAsync}} = this.props
updateOrganizationAsync(organization, { updateOrganizationAsync(organization, {
...organization, ...organization,
public: !organization.public, public: !organization.public,
@ -49,19 +51,23 @@ class OrganizationsPage extends Component {
} }
handleChooseDefaultRole = (organization, defaultRole) => { handleChooseDefaultRole = (organization, defaultRole) => {
const {actions: {updateOrganizationAsync}} = this.props const {actionsAdmin: {updateOrganizationAsync}} = this.props
updateOrganizationAsync(organization, {...organization, defaultRole}) updateOrganizationAsync(organization, {...organization, defaultRole})
// refreshMe is here to update the org's defaultRole in `me.organizations` // refreshMe is here to update the org's defaultRole in `me.organizations`
this.refreshMe() this.refreshMe()
} }
handleUpdateAuthSettings = updatedAuthSettings => { handleUpdateAuthConfig = updatedAuthConfig => {
const {actions: {updateAuthSettingsAsync}, authSettings, links} = this.props const {
updateAuthSettingsAsync(links.config, authSettings, updatedAuthSettings) actionsConfig: {updateAuthConfigAsync},
authConfig,
links,
} = this.props
updateAuthConfigAsync(links.config, authConfig, updatedAuthConfig)
} }
render() { render() {
const {organizations, currentOrganization, authSettings} = this.props const {organizations, currentOrganization, authConfig} = this.props
return ( return (
<OrganizationsTable <OrganizationsTable
@ -72,8 +78,8 @@ class OrganizationsPage extends Component {
onRenameOrg={this.handleRenameOrganization} onRenameOrg={this.handleRenameOrganization}
onTogglePublic={this.handleTogglePublic} onTogglePublic={this.handleTogglePublic}
onChooseDefaultRole={this.handleChooseDefaultRole} onChooseDefaultRole={this.handleChooseDefaultRole}
authSettings={authSettings} authConfig={authConfig}
onUpdateAuthSettings={this.handleUpdateAuthSettings} onUpdateAuthConfig={this.handleUpdateAuthConfig}
/> />
) )
} }
@ -84,7 +90,7 @@ const {arrayOf, bool, func, shape, string} = PropTypes
OrganizationsPage.propTypes = { OrganizationsPage.propTypes = {
links: shape({ links: shape({
organizations: string.isRequired, organizations: string.isRequired,
application: string.isRequired, config: string.isRequired,
}), }),
organizations: arrayOf( organizations: arrayOf(
shape({ shape({
@ -93,35 +99,39 @@ OrganizationsPage.propTypes = {
link: string, link: string,
}) })
), ),
actions: shape({ actionsAdmin: shape({
loadOrganizationsAsync: func.isRequired, loadOrganizationsAsync: func.isRequired,
createOrganizationAsync: func.isRequired, createOrganizationAsync: func.isRequired,
updateOrganizationAsync: func.isRequired, updateOrganizationAsync: func.isRequired,
deleteOrganizationAsync: func.isRequired, deleteOrganizationAsync: func.isRequired,
getAuthSettingsAsync: func.isRequired, }),
updateAuthSettingsAsync: func.isRequired, actionsConfig: shape({
getAuthConfigAsync: func.isRequired,
updateAuthConfigAsync: func.isRequired,
}), }),
getMe: func.isRequired, getMe: func.isRequired,
currentOrganization: shape({ currentOrganization: shape({
name: string.isRequired, name: string.isRequired,
id: string.isRequired, id: string.isRequired,
}), }),
authSettings: shape({ authConfig: shape({
superAdminFirstUserOnly: bool.isRequired, superAdminFirstUserOnly: bool,
}), }),
} }
const mapStateToProps = ({ const mapStateToProps = ({
links, links,
adminChronograf: {organizations, authSettings}, adminChronograf: {organizations},
config: {auth: authConfig},
}) => ({ }) => ({
links, links,
organizations, organizations,
authSettings, authConfig,
}) })
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(adminChronografActionCreators, dispatch), actionsAdmin: bindActionCreators(adminChronografActionCreators, dispatch),
actionsConfig: bindActionCreators(configActionCreators, dispatch),
getMe: bindActionCreators(getMeAsync, dispatch), getMe: bindActionCreators(getMeAsync, dispatch),
}) })

View File

@ -3,7 +3,7 @@ import {isSameUser} from 'shared/reducers/helpers/auth'
const initialState = { const initialState = {
users: [], users: [],
organizations: [], organizations: [],
authSettings: { authConfig: {
superAdminFirstUserOnly: true, superAdminFirstUserOnly: true,
}, },
} }
@ -94,16 +94,6 @@ const adminChronograf = (state = initialState, action) => {
), ),
} }
} }
case 'CHRONOGRAF_GET_AUTH_SETTINGS_COMPLETED':
case 'CHRONOGRAF_UPDATE_AUTH_SETTINGS_REQUESTED':
case 'CHRONOGRAF_UPDATE_AUTH_SETTINGS_FAILED': {
const {authSettings} = action.payload
return {
...state,
authSettings: {...authSettings}, // TODO: change to reflect final data shape
}
}
} }
return state return state

View File

@ -0,0 +1,67 @@
import {
getAuthConfig as getAuthConfigAJAX,
updateAuthConfig as updateAuthConfigAJAX,
} from 'shared/apis/config'
import {errorThrown} from 'shared/actions/errors'
export const getAuthConfigRequested = () => ({
type: 'CHRONOGRAF_GET_AUTH_CONFIG_REQUESTED',
})
export const getAuthConfigCompleted = authConfig => ({
type: 'CHRONOGRAF_GET_AUTH_CONFIG_COMPLETED',
payload: {
authConfig,
},
})
export const getAuthConfigFailed = () => ({
type: 'CHRONOGRAF_GET_AUTH_CONFIG_FAILED',
})
export const updateAuthConfigRequested = authConfig => ({
type: 'CHRONOGRAF_UPDATE_AUTH_CONFIG_REQUESTED',
payload: {
authConfig,
},
})
export const updateAuthConfigCompleted = () => ({
type: 'CHRONOGRAF_UPDATE_AUTH_CONFIG_COMPLETED',
})
export const updateAuthConfigFailed = authConfig => ({
type: 'CHRONOGRAF_UPDATE_AUTH_CONFIG_FAILED',
payload: {
authConfig,
},
})
// async actions (thunks)
export const getAuthConfigAsync = url => async dispatch => {
dispatch(getAuthConfigRequested())
try {
const {data} = await getAuthConfigAJAX(url)
dispatch(getAuthConfigCompleted(data)) // TODO: change authConfig in actions & reducers to reflect final shape
} catch (error) {
dispatch(errorThrown(error))
dispatch(getAuthConfigFailed())
}
}
export const updateAuthConfigAsync = (
url,
oldAuthConfig,
updatedAuthConfig
) => async dispatch => {
const newAuthConfig = {...oldAuthConfig, ...updatedAuthConfig}
dispatch(updateAuthConfigRequested(newAuthConfig))
try {
await updateAuthConfigAJAX(url, newAuthConfig)
dispatch(updateAuthConfigCompleted())
} catch (error) {
dispatch(errorThrown(error))
dispatch(updateAuthConfigFailed(oldAuthConfig))
}
}

View File

@ -0,0 +1,26 @@
import AJAX from 'src/utils/ajax'
export const getAuthConfig = async url => {
try {
return await AJAX({
method: 'GET',
url,
})
} catch (error) {
console.error(error)
throw error
}
}
export const updateAuthConfig = async (url, authConfig) => {
try {
return await AJAX({
method: 'PATCH',
url,
data: authConfig,
})
} catch (error) {
console.error(error)
throw error
}
}

View File

@ -0,0 +1,22 @@
const initialState = {
links: {},
auth: {},
}
const config = (state = initialState, action) => {
switch (action.type) {
case 'CHRONOGRAF_GET_AUTH_CONFIG_COMPLETED':
case 'CHRONOGRAF_UPDATE_AUTH_CONFIG_REQUESTED':
case 'CHRONOGRAF_UPDATE_AUTH_CONFIG_FAILED': {
const {authConfig: auth} = action.payload
return {
...state,
auth: {...auth},
}
}
}
return state
}
export default config

View File

@ -1,5 +1,6 @@
import app from './app' import app from './app'
import auth from './auth' import auth from './auth'
import config from './config'
import errors from './errors' import errors from './errors'
import links from './links' import links from './links'
import {notifications, dismissedNotifications} from './notifications' import {notifications, dismissedNotifications} from './notifications'
@ -8,6 +9,7 @@ import sources from './sources'
export default { export default {
app, app,
auth, auth,
config,
errors, errors,
links, links,
notifications, notifications,

View File

@ -165,7 +165,7 @@ input[type="text"].form-control.orgs-table--input {
} }
/* Settings table beneath organizations table */ /* Config table beneath organizations table */
.panel .panel-body table.table.superadmin-settings { .panel .panel-body table.table.superadmin-settings {
margin-top: 60px; margin-top: 60px;
} }