Merge pull request #5944 from influxdata/5942/influxdb_admin_filter_redux

feat(ui/admin): remember state of influxdb users/roles filters
pull/5949/head
Pavel Závora 2022-06-21 11:06:20 +02:00 committed by GitHub
commit cbbd0ea829
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 243 additions and 133 deletions

View File

@ -289,10 +289,14 @@ describe('InfluxDB', () => {
cy.get('th').contains('Users').should('exist') cy.get('th').contains('Users').should('exist')
}) })
cy.getByTestID('hide-users--toggle').click() cy.getByTestID('show-users--toggle').click()
cy.getByTestID('admin-table--head').within(() => { cy.getByTestID('admin-table--head').within(() => {
cy.get('th').contains('Users').should('not.exist') cy.get('th').contains('Users').should('not.exist')
}) })
cy.getByTestID('show-users--toggle').click()
cy.getByTestID('admin-table--head').within(() => {
cy.get('th').contains('Users').should('exist')
})
}) })
}) })
}) })

View File

@ -473,3 +473,18 @@ export const updateUserPasswordAsync = (user, password) => async dispatch => {
) )
} }
} }
export const changeSelectedDBs = (selectedDBs /* : string[] */) => ({
type: 'INFLUXDB_CHANGE_SELECTED_DBS',
payload: {
selectedDBs,
},
})
export const changeShowUsers = () => ({
type: 'INFLUXDB_CHANGE_SHOW_USERS',
})
export const changeShowRoles = () => ({
type: 'INFLUXDB_CHANGE_SHOW_ROLES',
})

View File

@ -0,0 +1,53 @@
import React from 'react'
import {connect, ResolveThunks} from 'react-redux'
import {changeSelectedDBs} from 'src/admin/actions/influxdb'
import {MultiSelectDropdown} from 'src/reusable_ui'
import {Database} from 'src/types/influxAdmin'
interface ConnectedProps {
databases: Database[]
selectedDBs: string[]
}
const mapStateToProps = ({adminInfluxDB: {databases, selectedDBs}}) => ({
databases,
selectedDBs,
})
const mapDispatchToProps = {
setSelectedDBs: changeSelectedDBs,
}
type ReduxDispatchProps = ResolveThunks<typeof mapDispatchToProps>
type Props = ConnectedProps & ReduxDispatchProps
const MultiDBSelector = ({databases, selectedDBs, setSelectedDBs}: Props) => {
return (
<div className="db-selector">
<MultiSelectDropdown
onChange={setSelectedDBs}
selectedIDs={selectedDBs}
emptyText="<no database>"
>
{databases.reduce(
(acc, db) => {
acc.push(
<MultiSelectDropdown.Item
key={db.name}
id={db.name}
value={{id: db.name}}
>
{db.name}
</MultiSelectDropdown.Item>
)
return acc
},
[
<MultiSelectDropdown.Item id="*" key="*" value={{id: '*'}}>
All Databases
</MultiSelectDropdown.Item>,
<MultiSelectDropdown.Divider id="" key="" />,
]
)}
</MultiSelectDropdown>
</div>
)
}
export default connect(mapStateToProps, mapDispatchToProps)(MultiDBSelector)

View File

@ -142,7 +142,7 @@ const RolePage = ({
) )
) )
}, },
[roleDBPermissions, changedPermissions, setChangedPermissions] [roleDBPermissions, changedPermissions]
) )
const permissionsChanged = !!Object.keys(changedPermissions).length const permissionsChanged = !!Object.keys(changedPermissions).length
const changePermissions = useMemo( const changePermissions = useMemo(

View File

@ -6,6 +6,7 @@ import {Source, NotificationAction} from 'src/types'
import {UserRole, User, Database} from 'src/types/influxAdmin' import {UserRole, User, Database} from 'src/types/influxAdmin'
import {notify as notifyAction} from 'src/shared/actions/notifications' import {notify as notifyAction} from 'src/shared/actions/notifications'
import { import {
changeShowUsers,
createRoleAsync, createRoleAsync,
filterRoles as filterRolesAction, filterRoles as filterRolesAction,
} from 'src/admin/actions/influxdb' } from 'src/admin/actions/influxdb'
@ -21,14 +22,14 @@ import FancyScrollbar from 'src/shared/components/FancyScrollbar'
import NoEntities from 'src/admin/components/influxdb/NoEntities' import NoEntities from 'src/admin/components/influxdb/NoEntities'
import RoleRow from 'src/admin/components/RoleRow' import RoleRow from 'src/admin/components/RoleRow'
import {useCallback} from 'react' import {useCallback} from 'react'
import allOrParticularSelection from '../../util/allOrParticularSelection'
import {computeEntitiesDBPermissions} from '../../util/computeEffectiveDBPermissions' import {computeEntitiesDBPermissions} from '../../util/computeEffectiveDBPermissions'
import useDebounce from 'src/utils/useDebounce' import useDebounce from 'src/utils/useDebounce'
import useChangeEffect from 'src/utils/useChangeEffect' import useChangeEffect from 'src/utils/useChangeEffect'
import {ComponentSize, MultiSelectDropdown, SlideToggle} from 'src/reusable_ui' import {ComponentSize, SlideToggle} from 'src/reusable_ui'
import CreateRoleDialog, { import CreateRoleDialog, {
validateRoleName, validateRoleName,
} from 'src/admin/components/influxdb/CreateRoleDialog' } from 'src/admin/components/influxdb/CreateRoleDialog'
import MultiDBSelector from 'src/admin/components/influxdb/MultiDBSelector'
const validateRole = ( const validateRole = (
role: Pick<UserRole, 'name'>, role: Pick<UserRole, 'name'>,
@ -41,16 +42,22 @@ const validateRole = (
return true return true
} }
const mapStateToProps = ({adminInfluxDB: {databases, users, roles}}) => ({ const mapStateToProps = ({
adminInfluxDB: {databases, users, roles, selectedDBs, showUsers, rolesFilter},
}) => ({
databases, databases,
users, users,
roles, roles,
selectedDBs,
showUsers,
rolesFilter,
}) })
const mapDispatchToProps = { const mapDispatchToProps = {
filterRoles: filterRolesAction, filterRoles: filterRolesAction,
createRole: createRoleAsync, createRole: createRoleAsync,
notify: notifyAction, notify: notifyAction,
toggleShowUsers: changeShowUsers,
} }
interface OwnProps { interface OwnProps {
@ -60,6 +67,9 @@ interface ConnectedProps {
databases: Database[] databases: Database[]
users: User[] users: User[]
roles: UserRole[] roles: UserRole[]
selectedDBs: string[]
showUsers: boolean
rolesFilter: string
} }
type ReduxDispatchProps = ResolveThunks<typeof mapDispatchToProps> type ReduxDispatchProps = ResolveThunks<typeof mapDispatchToProps>
@ -71,30 +81,26 @@ const RolesPage = ({
users, users,
roles, roles,
databases, databases,
selectedDBs,
showUsers,
rolesFilter,
router, router,
filterRoles, filterRoles,
createRole, createRole,
toggleShowUsers,
notify, notify,
}: Props) => { }: Props) => {
const rolesPage = useMemo( const rolesPage = useMemo(
() => `/sources/${source.id}/admin-influxdb/roles`, () => `/sources/${source.id}/admin-influxdb/roles`,
[source] [source]
) )
// filter databases // database columns
const [selectedDBs, setSelectedDBs] = useState<string[]>(['*'])
const visibleDBNames = useMemo<string[]>(() => { const visibleDBNames = useMemo<string[]>(() => {
if (selectedDBs.includes('*')) { if (selectedDBs.includes('*')) {
return databases.map(db => db.name) return databases.map(db => db.name)
} }
return selectedDBs return selectedDBs
}, [databases, selectedDBs]) }, [databases, selectedDBs])
const changeSelectedDBs = useCallback(
(newDBs: string[]) =>
setSelectedDBs((oldDBs: string[]) => {
return allOrParticularSelection(oldDBs, newDBs)
}),
[setSelectedDBs]
)
// effective permissions // effective permissions
const visibleRoles = useMemo(() => roles.filter(x => !x.hidden), [roles]) const visibleRoles = useMemo(() => roles.filter(x => !x.hidden), [roles])
@ -103,23 +109,14 @@ const RolesPage = ({
[visibleDBNames, visibleRoles] [visibleDBNames, visibleRoles]
) )
// filter users // filter roles
const [filterText, setFilterText] = useState('') const [filterText, setFilterText] = useState(rolesFilter)
const changeFilterText = useCallback(e => setFilterText(e.target.value), [ const changeFilterText = useCallback(e => setFilterText(e.target.value), [])
setFilterText,
])
const debouncedFilterText = useDebounce(filterText, 200) const debouncedFilterText = useDebounce(filterText, 200)
useChangeEffect(() => { useChangeEffect(() => {
filterRoles(debouncedFilterText) filterRoles(debouncedFilterText)
}, [debouncedFilterText]) }, [debouncedFilterText])
// hide users
const [showUsers, setShowUsers] = useState(true)
const changeHideUsers = useCallback(() => setShowUsers(!showUsers), [
showUsers,
setShowUsers,
])
const [createVisible, setCreateVisible] = useState(false) const [createVisible, setCreateVisible] = useState(false)
const createNew = useCallback( const createNew = useCallback(
async (role: {name: string}) => { async (role: {name: string}) => {
@ -159,40 +156,13 @@ const RolesPage = ({
/> />
<span className="icon search" /> <span className="icon search" />
</div> </div>
<div className="db-selector"> <MultiDBSelector />
<MultiSelectDropdown
onChange={changeSelectedDBs}
selectedIDs={selectedDBs}
emptyText="<no database>"
>
{databases.reduce(
(acc, db) => {
acc.push(
<MultiSelectDropdown.Item
key={db.name}
id={db.name}
value={{id: db.name}}
>
{db.name}
</MultiSelectDropdown.Item>
)
return acc
},
[
<MultiSelectDropdown.Item id="*" key="*" value={{id: '*'}}>
All Databases
</MultiSelectDropdown.Item>,
<MultiSelectDropdown.Divider id="" key="" />,
]
)}
</MultiSelectDropdown>
</div>
<div className="hide-roles-toggle"> <div className="hide-roles-toggle">
<SlideToggle <SlideToggle
active={showUsers} active={showUsers}
onChange={changeHideUsers} onChange={toggleShowUsers}
size={ComponentSize.ExtraSmall} size={ComponentSize.ExtraSmall}
entity="users" dataTest="show-users--toggle"
/> />
Show Users Show Users
</div> </div>

View File

@ -173,7 +173,7 @@ const UserPage = ({
) )
) )
}, },
[userDBPermissions, changedPermissions, setChangedPermissions] [userDBPermissions, changedPermissions]
) )
const permissionsChanged = !!Object.keys(changedPermissions).length const permissionsChanged = !!Object.keys(changedPermissions).length
const changePermissions = useMemo( const changePermissions = useMemo(

View File

@ -5,6 +5,7 @@ import {Source, NotificationAction} from 'src/types'
import {UserRole, User, Database} from 'src/types/influxAdmin' import {UserRole, User, Database} from 'src/types/influxAdmin'
import {notify as notifyAction} from 'src/shared/actions/notifications' import {notify as notifyAction} from 'src/shared/actions/notifications'
import { import {
changeShowRoles,
createUserAsync, createUserAsync,
filterUsers as filterUsersAction, filterUsers as filterUsersAction,
} from 'src/admin/actions/influxdb' } from 'src/admin/actions/influxdb'
@ -22,15 +23,14 @@ import NoEntities from 'src/admin/components/influxdb/NoEntities'
import UserRow from 'src/admin/components/UserRow' import UserRow from 'src/admin/components/UserRow'
import useDebounce from 'src/utils/useDebounce' import useDebounce from 'src/utils/useDebounce'
import useChangeEffect from 'src/utils/useChangeEffect' import useChangeEffect from 'src/utils/useChangeEffect'
import MultiSelectDropdown from 'src/reusable_ui/components/dropdowns/MultiSelectDropdown'
import {ComponentSize, SlideToggle} from 'src/reusable_ui' import {ComponentSize, SlideToggle} from 'src/reusable_ui'
import {computeEffectiveUserDBPermissions} from '../../util/computeEffectiveDBPermissions' import {computeEffectiveUserDBPermissions} from '../../util/computeEffectiveDBPermissions'
import allOrParticularSelection from '../../util/allOrParticularSelection'
import CreateUserDialog, { import CreateUserDialog, {
validatePassword, validatePassword,
validateUserName, validateUserName,
} from '../../components/influxdb/CreateUserDialog' } from '../../components/influxdb/CreateUserDialog'
import {withRouter, WithRouterProps} from 'react-router' import {withRouter, WithRouterProps} from 'react-router'
import MultiDBSelector from 'src/admin/components/influxdb/MultiDBSelector'
const validateUser = ( const validateUser = (
user: Pick<User, 'name' | 'password'>, user: Pick<User, 'name' | 'password'>,
@ -47,15 +47,21 @@ const validateUser = (
return true return true
} }
const mapStateToProps = ({adminInfluxDB: {databases, users, roles}}) => ({ const mapStateToProps = ({
adminInfluxDB: {databases, users, roles, selectedDBs, showRoles, usersFilter},
}) => ({
databases, databases,
users, users,
roles, roles,
selectedDBs,
showRoles,
usersFilter,
}) })
const mapDispatchToProps = { const mapDispatchToProps = {
filterUsers: filterUsersAction, filterUsers: filterUsersAction,
createUser: createUserAsync, createUser: createUserAsync,
toggleShowRoles: changeShowRoles,
notify: notifyAction, notify: notifyAction,
} }
@ -66,6 +72,9 @@ interface ConnectedProps {
databases: Database[] databases: Database[]
users: User[] users: User[]
roles: UserRole[] roles: UserRole[]
selectedDBs: string[]
showRoles: boolean
usersFilter: string
} }
type ReduxDispatchProps = ResolveThunks<typeof mapDispatchToProps> type ReduxDispatchProps = ResolveThunks<typeof mapDispatchToProps>
@ -77,9 +86,13 @@ const UsersPage = ({
databases, databases,
users, users,
roles, roles,
selectedDBs,
showRoles,
usersFilter,
notify, notify,
createUser, createUser,
filterUsers, filterUsers,
toggleShowRoles,
}: Props) => { }: Props) => {
const [isEnterprise, usersPage] = useMemo( const [isEnterprise, usersPage] = useMemo(
() => [ () => [
@ -88,21 +101,13 @@ const UsersPage = ({
], ],
[source] [source]
) )
// filter databases // database columns
const [selectedDBs, setSelectedDBs] = useState<string[]>(['*'])
const visibleDBNames = useMemo<string[]>(() => { const visibleDBNames = useMemo<string[]>(() => {
if (selectedDBs.includes('*')) { if (selectedDBs.includes('*')) {
return databases.map(db => db.name) return databases.map(db => db.name)
} }
return selectedDBs return selectedDBs
}, [databases, selectedDBs]) }, [databases, selectedDBs])
const changeSelectedDBs = useCallback(
(newDBs: string[]) =>
setSelectedDBs((oldDBs: string[]) => {
return allOrParticularSelection(oldDBs, newDBs)
}),
[setSelectedDBs]
)
// effective permissions // effective permissions
const visibleUsers = useMemo(() => users.filter(x => !x.hidden), [users]) const visibleUsers = useMemo(() => users.filter(x => !x.hidden), [users])
@ -113,22 +118,13 @@ const UsersPage = ({
) )
// filter users // filter users
const [filterText, setFilterText] = useState('') const [filterText, setFilterText] = useState(usersFilter)
const changeFilterText = useCallback(e => setFilterText(e.target.value), [ const changeFilterText = useCallback(e => setFilterText(e.target.value), [])
setFilterText,
])
const debouncedFilterText = useDebounce(filterText, 200) const debouncedFilterText = useDebounce(filterText, 200)
useChangeEffect(() => { useChangeEffect(() => {
filterUsers(debouncedFilterText) filterUsers(debouncedFilterText)
}, [debouncedFilterText]) }, [debouncedFilterText])
// hide role
const [showRoles, setShowRoles] = useState(true)
const changeHideRoles = useCallback(() => setShowRoles(!showRoles), [
showRoles,
setShowRoles,
])
const [createVisible, setCreateVisible] = useState(false) const [createVisible, setCreateVisible] = useState(false)
const createNew = useCallback( const createNew = useCallback(
async (user: {name: string; password: string}) => { async (user: {name: string; password: string}) => {
@ -169,39 +165,12 @@ const UsersPage = ({
/> />
<span className="icon search" /> <span className="icon search" />
</div> </div>
<div className="db-selector" data-test="db-selector"> <MultiDBSelector />
<MultiSelectDropdown
onChange={changeSelectedDBs}
selectedIDs={selectedDBs}
emptyText="<no database>"
>
{databases.reduce(
(acc, db) => {
acc.push(
<MultiSelectDropdown.Item
key={db.name}
id={db.name}
value={{id: db.name}}
>
{db.name}
</MultiSelectDropdown.Item>
)
return acc
},
[
<MultiSelectDropdown.Item id="*" key="*" value={{id: '*'}}>
All Databases
</MultiSelectDropdown.Item>,
<MultiSelectDropdown.Divider id="" key="" />,
]
)}
</MultiSelectDropdown>
</div>
{isEnterprise && ( {isEnterprise && (
<div className="hide-roles-toggle"> <div className="hide-roles-toggle">
<SlideToggle <SlideToggle
active={showRoles} active={showRoles}
onChange={changeHideRoles} onChange={toggleShowRoles}
size={ComponentSize.ExtraSmall} size={ComponentSize.ExtraSmall}
/> />
Show Roles Show Roles

View File

@ -6,6 +6,7 @@ import {
changeNamedCollection, changeNamedCollection,
computeNamedChanges, computeNamedChanges,
} from '../util/changeNamedCollection' } from '../util/changeNamedCollection'
import allOrParticularSelection from '../util/allOrParticularSelection'
const querySorters = { const querySorters = {
'+time'(queries) { '+time'(queries) {
@ -37,8 +38,7 @@ const identity = x => x
function sortQueries(queries, queriesSort) { function sortQueries(queries, queriesSort) {
return (querySorters[queriesSort] || identity)(queries) return (querySorters[queriesSort] || identity)(queries)
} }
export const initialState = {
const initialState = {
users: [], users: [],
roles: [], roles: [],
permissions: [], permissions: [],
@ -46,16 +46,21 @@ const initialState = {
queriesSort: '-time', queriesSort: '-time',
queryIDToKill: null, queryIDToKill: null,
databases: [], databases: [],
selectedDBs: ['*'],
showUsers: true,
showRoles: true,
usersFilter: '',
rolesFilter: '',
} }
const adminInfluxDB = (state = initialState, action) => { const adminInfluxDB = (state = initialState, action) => {
switch (action.type) { switch (action.type) {
case 'INFLUXDB_LOAD_USERS': { case 'INFLUXDB_LOAD_USERS': {
return {...state, ...action.payload} return {...state, ...action.payload, usersFilter: ''}
} }
case 'INFLUXDB_LOAD_ROLES': { case 'INFLUXDB_LOAD_ROLES': {
return {...state, ...action.payload} return {...state, ...action.payload, rolesFilter: ''}
} }
case 'INFLUXDB_LOAD_PERMISSIONS': { case 'INFLUXDB_LOAD_PERMISSIONS': {
@ -63,7 +68,9 @@ const adminInfluxDB = (state = initialState, action) => {
} }
case 'INFLUXDB_LOAD_DATABASES': { case 'INFLUXDB_LOAD_DATABASES': {
return {...state, ...action.payload} const databases = action.payload.databases
const selectedDBs = initialState.selectedDBs
return {...state, databases, selectedDBs}
} }
case 'INFLUXDB_ADD_DATABASE': { case 'INFLUXDB_ADD_DATABASE': {
@ -333,7 +340,7 @@ const adminInfluxDB = (state = initialState, action) => {
return u return u
}), }),
} }
return {...state, ...newState} return {...state, ...newState, usersFilter: text}
} }
case 'INFLUXDB_FILTER_ROLES': { case 'INFLUXDB_FILTER_ROLES': {
@ -344,7 +351,7 @@ const adminInfluxDB = (state = initialState, action) => {
return r return r
}), }),
} }
return {...state, ...newState} return {...state, ...newState, rolesFilter: text}
} }
case 'INFLUXDB_KILL_QUERY': { case 'INFLUXDB_KILL_QUERY': {
@ -359,6 +366,18 @@ const adminInfluxDB = (state = initialState, action) => {
case 'INFLUXDB_SET_QUERY_TO_KILL': { case 'INFLUXDB_SET_QUERY_TO_KILL': {
return {...state, ...action.payload} return {...state, ...action.payload}
} }
case 'INFLUXDB_CHANGE_SELECTED_DBS': {
const newDBs = action.payload.selectedDBs
const oldDBs = state.selectedDBs || ['*']
const selectedDBs = allOrParticularSelection(oldDBs, newDBs)
return {...state, selectedDBs}
}
case 'INFLUXDB_CHANGE_SHOW_USERS': {
return {...state, showUsers: !state.showUsers}
}
case 'INFLUXDB_CHANGE_SHOW_ROLES': {
return {...state, showRoles: !state.showRoles}
}
} }
return state return state

View File

@ -10,6 +10,7 @@ import {defaultTableData} from 'src/logs/constants'
import {VERSION, GIT_SHA} from 'src/shared/constants' import {VERSION, GIT_SHA} from 'src/shared/constants'
import {LocalStorage} from 'src/types/localStorage' import {LocalStorage} from 'src/types/localStorage'
import {initialState as adminInfluxDBInitialState} from './admin/reducers/influxdb'
export const loadLocalStorage = ( export const loadLocalStorage = (
errorsQueue: any[] errorsQueue: any[]
@ -39,7 +40,7 @@ export const loadLocalStorage = (
delete state.VERSION delete state.VERSION
delete state.GIT_SHA delete state.GIT_SHA
state.adminInfluxDB = {...adminInfluxDBInitialState, ...state.adminInfluxDB}
return state return state
} catch (error) { } catch (error) {
console.error(notifyLoadLocalSettingsFailed(error).message) console.error(notifyLoadLocalSettingsFailed(error).message)
@ -55,6 +56,7 @@ export const saveToLocalStorage = ({
dashTimeV1: {ranges, refreshes}, dashTimeV1: {ranges, refreshes},
logs, logs,
script, script,
adminInfluxDB: {showUsers, showRoles},
}: LocalStorage): void => { }: LocalStorage): void => {
try { try {
const dashTimeV1 = { const dashTimeV1 = {
@ -104,6 +106,7 @@ export const saveToLocalStorage = ({
}, },
tableTime: minimalLogs.tableTime || {}, tableTime: minimalLogs.tableTime || {},
}, },
adminInfluxDB: {showRoles, showUsers},
}) })
) )
} catch (err) { } catch (err) {

View File

@ -14,7 +14,7 @@ interface Props {
color?: ComponentColor color?: ComponentColor
disabled?: boolean disabled?: boolean
tooltipText?: string tooltipText?: string
entity?: string dataTest?: string
} }
@ErrorHandling @ErrorHandling
@ -27,14 +27,14 @@ class SlideToggle extends Component<Props> {
} }
public render() { public render() {
const {tooltipText} = this.props const {tooltipText, dataTest} = this.props
return ( return (
<div <div
className={this.className} className={this.className}
onClick={this.handleClick} onClick={this.handleClick}
title={tooltipText} title={tooltipText}
data-test={this.dataTest} data-test={dataTest}
> >
<div className="slide-toggle--knob" /> <div className="slide-toggle--knob" />
</div> </div>
@ -59,12 +59,6 @@ class SlideToggle extends Component<Props> {
{active, disabled} {active, disabled}
) )
} }
private get dataTest(): string {
const {active, entity} = this.props
return active ? `hide-${entity}--toggle` : `show-${entity}--toggle`
}
} }
export default SlideToggle export default SlideToggle

View File

@ -10,6 +10,10 @@ export interface LocalStorage {
logs: LogsState logs: LogsState
telegrafSystemInterval: string telegrafSystemInterval: string
hostPageDisabled: boolean hostPageDisabled: boolean
adminInfluxDB: {
showUsers: boolean
showRoles: boolean
}
} }
export type VERSION = string export type VERSION = string

View File

@ -7,6 +7,7 @@ import {
syncRole, syncRole,
editDatabase, editDatabase,
editRetentionPolicyRequested, editRetentionPolicyRequested,
loadUsers,
loadRoles, loadRoles,
loadPermissions, loadPermissions,
deleteRole, deleteRole,
@ -19,6 +20,10 @@ import {
removeDatabaseDeleteCode, removeDatabaseDeleteCode,
loadQueries, loadQueries,
setQueriesSort, setQueriesSort,
loadDatabases,
changeSelectedDBs,
changeShowUsers,
changeShowRoles,
} from 'src/admin/actions/influxdb' } from 'src/admin/actions/influxdb'
import {NEW_DEFAULT_DATABASE, NEW_EMPTY_RP} from 'src/admin/constants' import {NEW_DEFAULT_DATABASE, NEW_EMPTY_RP} from 'src/admin/constants'
@ -137,6 +142,17 @@ describe('Admin.InfluxDB.Reducers', () => {
state = {databases: [db1, db2]} state = {databases: [db1, db2]}
}) })
it('can load databases', () => {
const {databases, selectedDBs} = reducer(
undefined,
loadDatabases([{name: 'db1'}])
)
expect({databases, selectedDBs}).toEqual({
databases: [{name: 'db1'}],
selectedDBs: ['*'],
})
})
it('can add a database', () => { it('can add a database', () => {
const actual = reducer(state, addDatabase()) const actual = reducer(state, addDatabase())
const expected = [{...NEW_DEFAULT_DATABASE, isEditing: true}, db1, db2] const expected = [{...NEW_DEFAULT_DATABASE, isEditing: true}, db1, db2]
@ -209,7 +225,15 @@ describe('Admin.InfluxDB.Reducers', () => {
expect(actual.databases).toEqual(expected) expect(actual.databases).toEqual(expected)
}) })
}) })
it('it can load users', () => {
const {users: d, usersFilter} = reducer(state, loadUsers({users}))
const expected = {
users,
usersFilter: '',
}
expect({users: d, usersFilter}).toEqual(expected)
})
it('it can sync a stale user', () => { it('it can sync a stale user', () => {
const staleUser = {...u1, roles: []} const staleUser = {...u1, roles: []}
state = {users: [u2, staleUser], roles: []} state = {users: [u2, staleUser], roles: []}
@ -315,13 +339,14 @@ describe('Admin.InfluxDB.Reducers', () => {
expect(actual.users).toEqual(expected.users) expect(actual.users).toEqual(expected.users)
}) })
it('it can load the roles', () => { it('it can load roles', () => {
const actual = reducer(state, loadRoles({roles})) const {roles: d, rolesFilter} = reducer(state, loadRoles({roles}))
const expected = { const expected = {
roles, roles,
rolesFilter: '',
} }
expect(actual.roles).toEqual(expected.roles) expect({roles: d, rolesFilter}).toEqual(expected)
}) })
it('it can delete a non-existing role', () => { it('it can delete a non-existing role', () => {
@ -382,15 +407,16 @@ describe('Admin.InfluxDB.Reducers', () => {
const text = 'x' const text = 'x'
const actual = reducer(state, filterRoles(text)) const {roles: d, rolesFilter} = reducer(state, filterRoles(text))
const expected = { const expected = {
roles: [ roles: [
{...r1, hidden: false}, {...r1, hidden: false},
{...r2, hidden: true}, {...r2, hidden: true},
], ],
rolesFilter: text,
} }
expect(actual.roles).toEqual(expected.roles) expect({roles: d, rolesFilter}).toEqual(expected)
}) })
it('can filter users w/ "zero" text', () => { it('can filter users w/ "zero" text', () => {
@ -400,15 +426,16 @@ describe('Admin.InfluxDB.Reducers', () => {
const text = 'zero' const text = 'zero'
const actual = reducer(state, filterUsers(text)) const {users: d, usersFilter} = reducer(state, filterUsers(text))
const expected = { const expected = {
users: [ users: [
{...u1, hidden: true}, {...u1, hidden: true},
{...u2, hidden: false}, {...u2, hidden: false},
], ],
usersFilter: text,
} }
expect(actual.users).toEqual(expected.users) expect({users: d, usersFilter}).toEqual(expected)
}) })
// Permissions // Permissions
@ -488,4 +515,56 @@ describe('Admin.InfluxDB.Reducers', () => {
expect(actual.queries[2].id).toEqual(1) expect(actual.queries[2].id).toEqual(1)
}) })
}) })
describe('filters', () => {
it('can change selected DBS', () => {
const testPairs = [
{
prev: undefined,
change: ['db1'],
next: ['db1'],
},
{
prev: [],
change: ['db1'],
next: ['db1'],
},
{
prev: ['db1'],
change: ['db1', '*'],
next: ['*'],
},
{
prev: ['*'],
change: ['db1', '*'],
next: ['db1'],
},
{
prev: ['db1'],
change: [],
next: [],
},
]
testPairs.forEach(({prev, change, next}) => {
const {selectedDBs} = reducer(
{selectedDBs: prev},
changeSelectedDBs(change)
)
expect(selectedDBs).toEqual(next)
})
})
it('can change showUsers flag', () => {
const vals = [undefined, true, false]
vals.forEach(prev => {
const {showUsers} = reducer({showUsers: prev}, changeShowUsers())
expect(showUsers).toEqual(!prev)
})
})
it('can change showRoles flag', () => {
const vals = [undefined, true, false]
vals.forEach(prev => {
const {showRoles} = reducer({showRoles: prev}, changeShowRoles())
expect(showRoles).toEqual(!prev)
})
})
})
}) })