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,
updateOrganization as updateOrganizationAJAX,
deleteOrganization as deleteOrganizationAJAX,
getAuthSettings as getAuthSettingsAJAX,
updateAuthSettings as updateAuthSettingsAJAX,
} from 'src/admin/apis/chronograf'
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)
export const loadUsersAsync = url => async dispatch => {
try {
@ -266,30 +231,3 @@ export const deleteOrganizationAsync = organization => async dispatch => {
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
}
}
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})
}
handleChangeAuthSettingsSuperAdminFirstUserOnly = superAdminFirstUserOnly => {
const {onUpdateAuthSettings} = this.props
onUpdateAuthSettings({superAdminFirstUserOnly})
handleChangeAuthConfigSuperAdminFirstUserOnly = superAdminFirstUserOnly => {
const {onUpdateAuthConfig} = this.props
onUpdateAuthConfig({superAdminFirstUserOnly})
}
render() {
@ -47,7 +47,7 @@ class OrganizationsTable extends Component {
onChooseDefaultRole,
onTogglePublic,
currentOrganization,
authSettings: {superAdminFirstUserOnly},
authConfig: {superAdminFirstUserOnly},
} = this.props
const {isCreatingOrganization} = this.state
@ -102,7 +102,7 @@ class OrganizationsTable extends Component {
<table className="table v-center superadmin-settings">
<thead>
<tr>
<th style={{width: 70}}>Settings</th>
<th style={{width: 70}}>Config</th>
<th />
</tr>
</thead>
@ -113,7 +113,7 @@ class OrganizationsTable extends Component {
size="xs"
active={superAdminFirstUserOnly}
onToggle={
this.handleChangeAuthSettingsSuperAdminFirstUserOnly
this.handleChangeAuthConfigSuperAdminFirstUserOnly
}
/>
</td>
@ -146,9 +146,9 @@ OrganizationsTable.propTypes = {
onRenameOrg: func.isRequired,
onTogglePublic: func.isRequired,
onChooseDefaultRole: func.isRequired,
onUpdateAuthSettings: func.isRequired,
authSettings: shape({
superAdminFirstUserOnly: bool.isRequired,
onUpdateAuthConfig: func.isRequired,
authConfig: shape({
superAdminFirstUserOnly: bool,
}),
}
export default OrganizationsTable

View File

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

View File

@ -3,7 +3,7 @@ import {isSameUser} from 'shared/reducers/helpers/auth'
const initialState = {
users: [],
organizations: [],
authSettings: {
authConfig: {
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

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 auth from './auth'
import config from './config'
import errors from './errors'
import links from './links'
import {notifications, dismissedNotifications} from './notifications'
@ -8,6 +9,7 @@ import sources from './sources'
export default {
app,
auth,
config,
errors,
links,
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 {
margin-top: 60px;
}