mirror of
https://github.com/minio/minio.git
synced 2025-01-12 15:33:22 -05:00
Refactor browser dropdown links and components (#5562)
* refactor browser links and about modal Moved about modal to separate component and added unit tests. * refactor change password modal component * added unit tests for ChangePasswordModal * fix logout function in browser dropdown * remove older unused BrowserDropdown component * remove unused variables from BrowserDropdown component * show BrowserDropdown and StorageInfo only for LoggedIn users Non-loggedIn users will see a 'Login' button
This commit is contained in:
parent
6a42727e00
commit
bb0adea494
64
browser/app/js/browser/AboutModal.js
Normal file
64
browser/app/js/browser/AboutModal.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage (C) 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
|
import { Modal } from "react-bootstrap"
|
||||||
|
import logo from "../../img/logo.svg"
|
||||||
|
|
||||||
|
export const AboutModal = ({ serverInfo, hideAbout }) => {
|
||||||
|
const { version, memory, platform, runtime } = serverInfo
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className="modal-about modal-dark"
|
||||||
|
animation={false}
|
||||||
|
show={true}
|
||||||
|
onHide={hideAbout}
|
||||||
|
>
|
||||||
|
<button className="close" onClick={hideAbout}>
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
<div className="ma-inner">
|
||||||
|
<div className="mai-item hidden-xs">
|
||||||
|
<a href="https://minio.io" target="_blank">
|
||||||
|
<img className="maii-logo" src={logo} alt="" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="mai-item">
|
||||||
|
<ul className="maii-list">
|
||||||
|
<li>
|
||||||
|
<div>Version</div>
|
||||||
|
<small>{version}</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div>Memory</div>
|
||||||
|
<small>{memory}</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div>Platform</div>
|
||||||
|
<small>{platform}</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div>Runtime</div>
|
||||||
|
<small>{runtime}</small>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AboutModal
|
156
browser/app/js/browser/BrowserDropdown.js
Normal file
156
browser/app/js/browser/BrowserDropdown.js
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage (C) 2016, 2017, 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
|
import { connect } from "react-redux"
|
||||||
|
import { Dropdown } from "react-bootstrap"
|
||||||
|
import * as browserActions from "./actions"
|
||||||
|
import web from "../web"
|
||||||
|
import history from "../history"
|
||||||
|
import AboutModal from "./AboutModal"
|
||||||
|
import ChangePasswordModal from "./ChangePasswordModal"
|
||||||
|
|
||||||
|
export class BrowserDropdown extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
showAboutModal: false,
|
||||||
|
showChangePasswordModal: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showAbout(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
this.setState({
|
||||||
|
showAboutModal: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
hideAbout() {
|
||||||
|
this.setState({
|
||||||
|
showAboutModal: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
showChangePassword(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
this.setState({
|
||||||
|
showChangePasswordModal: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
hideChangePassword() {
|
||||||
|
this.setState({
|
||||||
|
showChangePasswordModal: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
const { fetchServerInfo } = this.props
|
||||||
|
fetchServerInfo()
|
||||||
|
}
|
||||||
|
fullScreen(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
let el = document.documentElement
|
||||||
|
if (el.requestFullscreen) {
|
||||||
|
el.requestFullscreen()
|
||||||
|
}
|
||||||
|
if (el.mozRequestFullScreen) {
|
||||||
|
el.mozRequestFullScreen()
|
||||||
|
}
|
||||||
|
if (el.webkitRequestFullscreen) {
|
||||||
|
el.webkitRequestFullscreen()
|
||||||
|
}
|
||||||
|
if (el.msRequestFullscreen) {
|
||||||
|
el.msRequestFullscreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logout(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
web.Logout()
|
||||||
|
history.replace("/login")
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { serverInfo } = this.props
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<Dropdown pullRight id="top-right-menu">
|
||||||
|
<Dropdown.Toggle noCaret>
|
||||||
|
<i className="fa fa-reorder" />
|
||||||
|
</Dropdown.Toggle>
|
||||||
|
<Dropdown.Menu className="dropdown-menu-right">
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://github.com/minio/minio">
|
||||||
|
Github <i className="fa fa-github" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="" onClick={this.fullScreen}>
|
||||||
|
Fullscreen <i className="fa fa-expand" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://docs.minio.io/">
|
||||||
|
Documentation <i className="fa fa-book" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a target="_blank" href="https://slack.minio.io">
|
||||||
|
Ask for help <i className="fa fa-question-circle" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="" id="show-about" onClick={this.showAbout.bind(this)}>
|
||||||
|
About <i className="fa fa-info-circle" />
|
||||||
|
</a>
|
||||||
|
{this.state.showAboutModal && (
|
||||||
|
<AboutModal
|
||||||
|
serverInfo={serverInfo}
|
||||||
|
hideAbout={this.hideAbout.bind(this)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="" onClick={this.showChangePassword.bind(this)}>
|
||||||
|
Change Password <i className="fa fa-cog" />
|
||||||
|
</a>
|
||||||
|
{this.state.showChangePasswordModal && (
|
||||||
|
<ChangePasswordModal
|
||||||
|
serverInfo={serverInfo}
|
||||||
|
hideChangePassword={this.hideChangePassword.bind(this)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="" id="logout" onClick={this.logout}>
|
||||||
|
Sign Out <i className="fa fa-sign-out" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</Dropdown.Menu>
|
||||||
|
</Dropdown>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
serverInfo: state.browser.serverInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
fetchServerInfo: () => dispatch(browserActions.fetchServerInfo())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(BrowserDropdown)
|
201
browser/app/js/browser/ChangePasswordModal.js
Normal file
201
browser/app/js/browser/ChangePasswordModal.js
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage (C) 2016, 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
|
import { connect } from "react-redux"
|
||||||
|
import web from "../web"
|
||||||
|
import * as alertActions from "../alert/actions"
|
||||||
|
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalHeader,
|
||||||
|
OverlayTrigger
|
||||||
|
} from "react-bootstrap"
|
||||||
|
import InputGroup from "./InputGroup"
|
||||||
|
|
||||||
|
export class ChangePasswordModal extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
accessKey: "",
|
||||||
|
secretKey: "",
|
||||||
|
keysReadOnly: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// When its shown, it loads the access key and secret key.
|
||||||
|
componentWillMount() {
|
||||||
|
const { serverInfo } = this.props
|
||||||
|
|
||||||
|
// Check environment variables first.
|
||||||
|
if (serverInfo.info.isEnvCreds) {
|
||||||
|
this.setState({
|
||||||
|
accessKey: "xxxxxxxxx",
|
||||||
|
secretKey: "xxxxxxxxx",
|
||||||
|
keysReadOnly: true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
web.GetAuth().then(data => {
|
||||||
|
this.setState({
|
||||||
|
accessKey: data.accessKey,
|
||||||
|
secretKey: data.secretKey
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle field changes from inside the modal.
|
||||||
|
accessKeyChange(e) {
|
||||||
|
this.setState({
|
||||||
|
accessKey: e.target.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
secretKeyChange(e) {
|
||||||
|
this.setState({
|
||||||
|
secretKey: e.target.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
secretKeyVisible(secretKeyVisible) {
|
||||||
|
this.setState({
|
||||||
|
secretKeyVisible
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the auth params and set them.
|
||||||
|
setAuth(e) {
|
||||||
|
const { showAlert } = this.props
|
||||||
|
const accessKey = this.state.accessKey
|
||||||
|
const secretKey = this.state.secretKey
|
||||||
|
web
|
||||||
|
.SetAuth({
|
||||||
|
accessKey,
|
||||||
|
secretKey
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
showAlert({
|
||||||
|
type: "success",
|
||||||
|
message: "Changed credentials"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
showAlert({
|
||||||
|
type: "danger",
|
||||||
|
message: err.message
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
generateAuth(e) {
|
||||||
|
web.GenerateAuth().then(data => {
|
||||||
|
this.setState({
|
||||||
|
accessKey: data.accessKey,
|
||||||
|
secretKey: data.secretKey,
|
||||||
|
secretKeyVisible: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { hideChangePassword } = this.props
|
||||||
|
return (
|
||||||
|
<Modal bsSize="sm" animation={false} show={true}>
|
||||||
|
<ModalHeader>Change Password</ModalHeader>
|
||||||
|
<ModalBody className="m-t-20">
|
||||||
|
<InputGroup
|
||||||
|
value={this.state.accessKey}
|
||||||
|
onChange={this.accessKeyChange.bind(this)}
|
||||||
|
id="accessKey"
|
||||||
|
label="Access Key"
|
||||||
|
name="accesskey"
|
||||||
|
type="text"
|
||||||
|
spellCheck="false"
|
||||||
|
required="required"
|
||||||
|
autoComplete="false"
|
||||||
|
align="ig-left"
|
||||||
|
readonly={this.state.keysReadOnly}
|
||||||
|
/>
|
||||||
|
<i
|
||||||
|
onClick={this.secretKeyVisible.bind(
|
||||||
|
this,
|
||||||
|
!this.state.secretKeyVisible
|
||||||
|
)}
|
||||||
|
className={
|
||||||
|
"toggle-password fa fa-eye " +
|
||||||
|
(this.state.secretKeyVisible ? "toggled" : "")
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<InputGroup
|
||||||
|
value={this.state.secretKey}
|
||||||
|
onChange={this.secretKeyChange.bind(this)}
|
||||||
|
id="secretKey"
|
||||||
|
label="Secret Key"
|
||||||
|
name="accesskey"
|
||||||
|
type={this.state.secretKeyVisible ? "text" : "password"}
|
||||||
|
spellCheck="false"
|
||||||
|
required="required"
|
||||||
|
autoComplete="false"
|
||||||
|
align="ig-left"
|
||||||
|
readonly={this.state.keysReadOnly}
|
||||||
|
/>
|
||||||
|
</ModalBody>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button
|
||||||
|
id="generate-keys"
|
||||||
|
className={
|
||||||
|
"btn btn-primary " + (this.state.keysReadOnly ? "hidden" : "")
|
||||||
|
}
|
||||||
|
onClick={this.generateAuth.bind(this)}
|
||||||
|
>
|
||||||
|
Generate
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
id="update-keys"
|
||||||
|
className={
|
||||||
|
"btn btn-success " + (this.state.keysReadOnly ? "hidden" : "")
|
||||||
|
}
|
||||||
|
onClick={this.setAuth.bind(this)}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
id="cancel-change-password"
|
||||||
|
className="btn btn-link"
|
||||||
|
onClick={hideChangePassword}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
serverInfo: state.browser.serverInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
showAlert: alert => dispatch(alertActions.set(alert))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ChangePasswordModal)
|
@ -17,12 +17,27 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import Path from "../objects/Path"
|
import Path from "../objects/Path"
|
||||||
import StorageInfo from "./StorageInfo"
|
import StorageInfo from "./StorageInfo"
|
||||||
|
import BrowserDropdown from "./BrowserDropdown"
|
||||||
|
import web from "../web"
|
||||||
|
import { minioBrowserPrefix } from "../constants"
|
||||||
|
|
||||||
export const Header = () => (
|
export const Header = () => {
|
||||||
|
const loggedIn = web.LoggedIn()
|
||||||
|
return (
|
||||||
<header className="fe-header">
|
<header className="fe-header">
|
||||||
<Path />
|
<Path />
|
||||||
<StorageInfo />
|
{loggedIn && <StorageInfo />}
|
||||||
|
<ul className="feh-actions">
|
||||||
|
{loggedIn ? (
|
||||||
|
<BrowserDropdown />
|
||||||
|
) : (
|
||||||
|
<a className="btn btn-danger" href={minioBrowserPrefix + "/login"}>
|
||||||
|
Login
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
</header>
|
</header>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default Header
|
export default Header
|
||||||
|
70
browser/app/js/browser/InputGroup.js
Normal file
70
browser/app/js/browser/InputGroup.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage (C) 2016, 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
let InputGroup = ({
|
||||||
|
label,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
type,
|
||||||
|
spellCheck,
|
||||||
|
required,
|
||||||
|
readonly,
|
||||||
|
autoComplete,
|
||||||
|
align,
|
||||||
|
className
|
||||||
|
}) => {
|
||||||
|
var input = (
|
||||||
|
<input
|
||||||
|
id={id}
|
||||||
|
name={name}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
className="ig-text"
|
||||||
|
type={type}
|
||||||
|
spellCheck={spellCheck}
|
||||||
|
required={required}
|
||||||
|
autoComplete={autoComplete}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
if (readonly)
|
||||||
|
input = (
|
||||||
|
<input
|
||||||
|
id={id}
|
||||||
|
name={name}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
className="ig-text"
|
||||||
|
type={type}
|
||||||
|
spellCheck={spellCheck}
|
||||||
|
required={required}
|
||||||
|
autoComplete={autoComplete}
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
<div className={"input-group " + align + " " + className}>
|
||||||
|
{input}
|
||||||
|
<i className="ig-helpers" />
|
||||||
|
<label className="ig-label">{label}</label>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InputGroup
|
@ -20,7 +20,7 @@ import classNames from "classnames"
|
|||||||
import logo from "../../img/logo.svg"
|
import logo from "../../img/logo.svg"
|
||||||
import Alert from "../alert/Alert"
|
import Alert from "../alert/Alert"
|
||||||
import * as actionsAlert from "../alert/actions"
|
import * as actionsAlert from "../alert/actions"
|
||||||
import InputGroup from "../components/InputGroup"
|
import InputGroup from "./InputGroup"
|
||||||
import { minioBrowserPrefix } from "../constants"
|
import { minioBrowserPrefix } from "../constants"
|
||||||
import web from "../web"
|
import web from "../web"
|
||||||
import { Redirect } from "react-router-dom"
|
import { Redirect } from "react-router-dom"
|
||||||
|
41
browser/app/js/browser/__tests__/AboutModal.test.js
Normal file
41
browser/app/js/browser/__tests__/AboutModal.test.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage (C) 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import { AboutModal } from "../AboutModal"
|
||||||
|
|
||||||
|
describe("AboutModal", () => {
|
||||||
|
const serverInfo = {
|
||||||
|
version: "test",
|
||||||
|
memory: "test",
|
||||||
|
platform: "test",
|
||||||
|
runtime: "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should render without crashing", () => {
|
||||||
|
shallow(<AboutModal serverInfo={serverInfo} />)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should call hideAbout when close button is clicked", () => {
|
||||||
|
const hideAbout = jest.fn()
|
||||||
|
const wrapper = shallow(
|
||||||
|
<AboutModal serverInfo={serverInfo} hideAbout={hideAbout} />
|
||||||
|
)
|
||||||
|
wrapper.find("button").simulate("click")
|
||||||
|
expect(hideAbout).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
63
browser/app/js/browser/__tests__/BrowserDropdown.test.js
Normal file
63
browser/app/js/browser/__tests__/BrowserDropdown.test.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage (C) 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import { BrowserDropdown } from "../BrowserDropdown"
|
||||||
|
|
||||||
|
describe("BrowserDropdown", () => {
|
||||||
|
const serverInfo = {
|
||||||
|
version: "test",
|
||||||
|
memory: "test",
|
||||||
|
platform: "test",
|
||||||
|
runtime: "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should render without crashing", () => {
|
||||||
|
shallow(
|
||||||
|
<BrowserDropdown serverInfo={serverInfo} fetchServerInfo={jest.fn()} />
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should call fetchServerInfo after its mounted", () => {
|
||||||
|
const fetchServerInfo = jest.fn()
|
||||||
|
const wrapper = shallow(
|
||||||
|
<BrowserDropdown
|
||||||
|
serverInfo={serverInfo}
|
||||||
|
fetchServerInfo={fetchServerInfo}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
expect(fetchServerInfo).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should show AboutModal when About link is clicked", () => {
|
||||||
|
const wrapper = shallow(
|
||||||
|
<BrowserDropdown serverInfo={serverInfo} fetchServerInfo={jest.fn()} />
|
||||||
|
)
|
||||||
|
wrapper.find("#show-about").simulate("click", { preventDefault: jest.fn() })
|
||||||
|
wrapper.update()
|
||||||
|
expect(wrapper.state("showAboutModal")).toBeTruthy()
|
||||||
|
expect(wrapper.find("AboutModal").length).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should logout and redirect to /login when logout is clicked", () => {
|
||||||
|
const wrapper = shallow(
|
||||||
|
<BrowserDropdown serverInfo={serverInfo} fetchServerInfo={jest.fn()} />
|
||||||
|
)
|
||||||
|
wrapper.find("#logout").simulate("click", { preventDefault: jest.fn() })
|
||||||
|
expect(window.location.pathname.endsWith("/login")).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
109
browser/app/js/browser/__tests__/ChangePasswordModal.test.js
Normal file
109
browser/app/js/browser/__tests__/ChangePasswordModal.test.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Minio Cloud Storage (C) 2018 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
|
import { shallow, mount } from "enzyme"
|
||||||
|
import { ChangePasswordModal } from "../ChangePasswordModal"
|
||||||
|
|
||||||
|
jest.mock("../../web", () => ({
|
||||||
|
GetAuth: jest.fn(() => {
|
||||||
|
return Promise.resolve({ accessKey: "test1", secretKey: "test2" })
|
||||||
|
}),
|
||||||
|
GenerateAuth: jest.fn(() => {
|
||||||
|
return Promise.resolve({ accessKey: "gen1", secretKey: "gen2" })
|
||||||
|
}),
|
||||||
|
SetAuth: jest.fn(({ accessKey, secretKey }) => {
|
||||||
|
if (accessKey == "test3" && secretKey == "test4") {
|
||||||
|
return Promise.resolve({})
|
||||||
|
} else {
|
||||||
|
return Promise.reject({ message: "Error" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe("ChangePasswordModal", () => {
|
||||||
|
const serverInfo = {
|
||||||
|
version: "test",
|
||||||
|
memory: "test",
|
||||||
|
platform: "test",
|
||||||
|
runtime: "test",
|
||||||
|
info: { isEnvCreds: false }
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should render without crashing", () => {
|
||||||
|
shallow(<ChangePasswordModal serverInfo={serverInfo} />)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should get the keys when its rendered", () => {
|
||||||
|
const wrapper = shallow(<ChangePasswordModal serverInfo={serverInfo} />)
|
||||||
|
setImmediate(() => {
|
||||||
|
expect(wrapper.state("accessKey")).toBe("test1")
|
||||||
|
expect(wrapper.state("secretKey")).toBe("test2")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should show readonly keys when isEnvCreds is true", () => {
|
||||||
|
const newServerInfo = { ...serverInfo, info: { isEnvCreds: true } }
|
||||||
|
const wrapper = shallow(<ChangePasswordModal serverInfo={newServerInfo} />)
|
||||||
|
expect(wrapper.state("accessKey")).toBe("xxxxxxxxx")
|
||||||
|
expect(wrapper.state("secretKey")).toBe("xxxxxxxxx")
|
||||||
|
expect(wrapper.find("#accessKey").prop("readonly")).toBeTruthy()
|
||||||
|
expect(wrapper.find("#secretKey").prop("readonly")).toBeTruthy()
|
||||||
|
expect(wrapper.find("#generate-keys").hasClass("hidden")).toBeTruthy()
|
||||||
|
expect(wrapper.find("#update-keys").hasClass("hidden")).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should generate accessKey and secretKey when Generate buttons is clicked", () => {
|
||||||
|
const wrapper = shallow(<ChangePasswordModal serverInfo={serverInfo} />)
|
||||||
|
wrapper.find("#generate-keys").simulate("click")
|
||||||
|
setImmediate(() => {
|
||||||
|
expect(wrapper.state("accessKey")).toBe("gen1")
|
||||||
|
expect(wrapper.state("secretKey")).toBe("gen2")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update accessKey and secretKey when Update button is clicked", () => {
|
||||||
|
const showAlert = jest.fn()
|
||||||
|
const wrapper = shallow(
|
||||||
|
<ChangePasswordModal serverInfo={serverInfo} showAlert={showAlert} />
|
||||||
|
)
|
||||||
|
wrapper
|
||||||
|
.find("#accessKey")
|
||||||
|
.simulate("change", { target: { value: "test3" } })
|
||||||
|
wrapper
|
||||||
|
.find("#secretKey")
|
||||||
|
.simulate("change", { target: { value: "test4" } })
|
||||||
|
wrapper.find("#update-keys").simulate("click")
|
||||||
|
setImmediate(() => {
|
||||||
|
expect(showAlert).toHaveBeenCalledWith({
|
||||||
|
type: "success",
|
||||||
|
message: "Changed credentials"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should call hideChangePassword when Cancel button is clicked", () => {
|
||||||
|
const hideChangePassword = jest.fn()
|
||||||
|
const wrapper = shallow(
|
||||||
|
<ChangePasswordModal
|
||||||
|
serverInfo={serverInfo}
|
||||||
|
hideChangePassword={hideChangePassword}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
wrapper.find("#cancel-change-password").simulate("click")
|
||||||
|
expect(hideChangePassword).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
@ -18,8 +18,25 @@ import React from "react"
|
|||||||
import { shallow } from "enzyme"
|
import { shallow } from "enzyme"
|
||||||
import Header from "../Header"
|
import Header from "../Header"
|
||||||
|
|
||||||
|
jest.mock("../../web", () => ({
|
||||||
|
LoggedIn: jest
|
||||||
|
.fn(() => true)
|
||||||
|
.mockReturnValueOnce(true)
|
||||||
|
.mockReturnValueOnce(false)
|
||||||
|
}))
|
||||||
describe("Header", () => {
|
describe("Header", () => {
|
||||||
it("should render without crashing", () => {
|
it("should render without crashing", () => {
|
||||||
shallow(<Header />)
|
shallow(<Header />)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should render Login button when the user has not LoggedIn", () => {
|
||||||
|
const wrapper = shallow(<Header />)
|
||||||
|
expect(wrapper.find("a").text()).toBe("Login")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should render StorageInfo and BrowserDropdown when the user has LoggedIn", () => {
|
||||||
|
const wrapper = shallow(<Header />)
|
||||||
|
expect(wrapper.find("Connect(BrowserDropdown)").length).toBe(1)
|
||||||
|
expect(wrapper.find("Connect(StorageInfo)").length).toBe(1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -21,6 +21,15 @@ import * as actionsCommon from "../actions"
|
|||||||
jest.mock("../../web", () => ({
|
jest.mock("../../web", () => ({
|
||||||
StorageInfo: jest.fn(() => {
|
StorageInfo: jest.fn(() => {
|
||||||
return Promise.resolve({ storageInfo: { Total: 100, Free: 60 } })
|
return Promise.resolve({ storageInfo: { Total: 100, Free: 60 } })
|
||||||
|
}),
|
||||||
|
ServerInfo: jest.fn(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
MinioVersion: "test",
|
||||||
|
MinioMemory: "test",
|
||||||
|
MinioPlatform: "test",
|
||||||
|
MinioRuntime: "test",
|
||||||
|
MinioGlobalInfo: "test"
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@ -38,4 +47,24 @@ describe("Common actions", () => {
|
|||||||
expect(actions).toEqual(expectedActions)
|
expect(actions).toEqual(expectedActions)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("creates common/SET_SERVER_INFO after fetching the server details", () => {
|
||||||
|
const store = mockStore()
|
||||||
|
const expectedActions = [
|
||||||
|
{
|
||||||
|
type: "common/SET_SERVER_INFO",
|
||||||
|
serverInfo: {
|
||||||
|
version: "test",
|
||||||
|
memory: "test",
|
||||||
|
platform: "test",
|
||||||
|
runtime: "test",
|
||||||
|
info: "test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return store.dispatch(actionsCommon.fetchServerInfo()).then(() => {
|
||||||
|
const actions = store.getActions()
|
||||||
|
expect(actions).toEqual(expectedActions)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -24,7 +24,8 @@ describe("common reducer", () => {
|
|||||||
storageInfo: {
|
storageInfo: {
|
||||||
total: 0,
|
total: 0,
|
||||||
free: 0
|
free: 0
|
||||||
}
|
},
|
||||||
|
serverInfo: {}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -67,4 +68,25 @@ describe("common reducer", () => {
|
|||||||
storageInfo: { total: 100, free: 40 }
|
storageInfo: { total: 100, free: 40 }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should handle SET_SERVER_INFO", () => {
|
||||||
|
expect(
|
||||||
|
reducer(undefined, {
|
||||||
|
type: actionsCommon.SET_SERVER_INFO,
|
||||||
|
serverInfo: {
|
||||||
|
version: "test",
|
||||||
|
memory: "test",
|
||||||
|
platform: "test",
|
||||||
|
runtime: "test",
|
||||||
|
info: "test"
|
||||||
|
}
|
||||||
|
}).serverInfo
|
||||||
|
).toEqual({
|
||||||
|
version: "test",
|
||||||
|
memory: "test",
|
||||||
|
platform: "test",
|
||||||
|
runtime: "test",
|
||||||
|
info: "test"
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -19,6 +19,7 @@ import web from "../web"
|
|||||||
export const TOGGLE_SIDEBAR = "common/TOGGLE_SIDEBAR"
|
export const TOGGLE_SIDEBAR = "common/TOGGLE_SIDEBAR"
|
||||||
export const CLOSE_SIDEBAR = "common/CLOSE_SIDEBAR"
|
export const CLOSE_SIDEBAR = "common/CLOSE_SIDEBAR"
|
||||||
export const SET_STORAGE_INFO = "common/SET_STORAGE_INFO"
|
export const SET_STORAGE_INFO = "common/SET_STORAGE_INFO"
|
||||||
|
export const SET_SERVER_INFO = "common/SET_SERVER_INFO"
|
||||||
|
|
||||||
export const toggleSidebar = () => ({
|
export const toggleSidebar = () => ({
|
||||||
type: TOGGLE_SIDEBAR
|
type: TOGGLE_SIDEBAR
|
||||||
@ -44,3 +45,23 @@ export const setStorageInfo = storageInfo => ({
|
|||||||
type: SET_STORAGE_INFO,
|
type: SET_STORAGE_INFO,
|
||||||
storageInfo
|
storageInfo
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const fetchServerInfo = () => {
|
||||||
|
return function(dispatch) {
|
||||||
|
return web.ServerInfo().then(res => {
|
||||||
|
const serverInfo = {
|
||||||
|
version: res.MinioVersion,
|
||||||
|
memory: res.MinioMemory,
|
||||||
|
platform: res.MinioPlatform,
|
||||||
|
runtime: res.MinioRuntime,
|
||||||
|
info: res.MinioGlobalInfo
|
||||||
|
}
|
||||||
|
dispatch(setServerInfo(serverInfo))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setServerInfo = serverInfo => ({
|
||||||
|
type: SET_SERVER_INFO,
|
||||||
|
serverInfo
|
||||||
|
})
|
||||||
|
@ -17,7 +17,11 @@
|
|||||||
import * as actionsCommon from "./actions"
|
import * as actionsCommon from "./actions"
|
||||||
|
|
||||||
export default (
|
export default (
|
||||||
state = { sidebarOpen: false, storageInfo: { total: 0, free: 0 } },
|
state = {
|
||||||
|
sidebarOpen: false,
|
||||||
|
storageInfo: { total: 0, free: 0 },
|
||||||
|
serverInfo: {}
|
||||||
|
},
|
||||||
action
|
action
|
||||||
) => {
|
) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
@ -33,6 +37,8 @@ export default (
|
|||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
storageInfo: action.storageInfo
|
storageInfo: action.storageInfo
|
||||||
})
|
})
|
||||||
|
case actionsCommon.SET_SERVER_INFO:
|
||||||
|
return { ...state, serverInfo: action.serverInfo }
|
||||||
default:
|
default:
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minio Cloud Storage (C) 2016, 2017 Minio, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
import connect from 'react-redux/lib/components/connect'
|
|
||||||
import Dropdown from 'react-bootstrap/lib/Dropdown'
|
|
||||||
|
|
||||||
let BrowserDropdown = ({fullScreenFunc, aboutFunc, settingsFunc, logoutFunc}) => {
|
|
||||||
return (
|
|
||||||
<li>
|
|
||||||
<Dropdown pullRight id="top-right-menu">
|
|
||||||
<Dropdown.Toggle noCaret>
|
|
||||||
<i className="fa fa-reorder"></i>
|
|
||||||
</Dropdown.Toggle>
|
|
||||||
<Dropdown.Menu className="dropdown-menu-right">
|
|
||||||
<li>
|
|
||||||
<a target="_blank" href="https://github.com/minio/minio">Github <i className="fa fa-github"></i></a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="" onClick={ fullScreenFunc }>Fullscreen <i className="fa fa-expand"></i></a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a target="_blank" href="https://docs.minio.io/">Documentation <i className="fa fa-book"></i></a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a target="_blank" href="https://slack.minio.io">Ask for help <i className="fa fa-question-circle"></i></a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="" onClick={ aboutFunc }>About <i className="fa fa-info-circle"></i></a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="" onClick={ settingsFunc }>Change Password <i className="fa fa-cog"></i></a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="" onClick={ logoutFunc }>Sign Out <i className="fa fa-sign-out"></i></a>
|
|
||||||
</li>
|
|
||||||
</Dropdown.Menu>
|
|
||||||
</Dropdown>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(state => state)(BrowserDropdown)
|
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minio Cloud Storage (C) 2016 Minio, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
let InputGroup = ({label, id, name, value, onChange, type, spellCheck, required, readonly, autoComplete, align, className}) => {
|
|
||||||
var input = <input id={ id }
|
|
||||||
name={ name }
|
|
||||||
value={ value }
|
|
||||||
onChange={ onChange }
|
|
||||||
className="ig-text"
|
|
||||||
type={ type }
|
|
||||||
spellCheck={ spellCheck }
|
|
||||||
required={ required }
|
|
||||||
autoComplete={ autoComplete } />
|
|
||||||
if (readonly)
|
|
||||||
input = <input id={ id }
|
|
||||||
name={ name }
|
|
||||||
value={ value }
|
|
||||||
onChange={ onChange }
|
|
||||||
className="ig-text"
|
|
||||||
type={ type }
|
|
||||||
spellCheck={ spellCheck }
|
|
||||||
required={ required }
|
|
||||||
autoComplete={ autoComplete }
|
|
||||||
disabled />
|
|
||||||
return <div className={ "input-group " + align + ' ' + className }>
|
|
||||||
{ input }
|
|
||||||
<i className="ig-helpers"></i>
|
|
||||||
<label className="ig-label">
|
|
||||||
{ label }
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default InputGroup
|
|
@ -1,204 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minio Cloud Storage (C) 2016 Minio, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
import connect from 'react-redux/lib/components/connect'
|
|
||||||
import * as actions from '../actions'
|
|
||||||
|
|
||||||
import Tooltip from 'react-bootstrap/lib/Tooltip'
|
|
||||||
import Modal from 'react-bootstrap/lib/Modal'
|
|
||||||
import ModalBody from 'react-bootstrap/lib/ModalBody'
|
|
||||||
import ModalHeader from 'react-bootstrap/lib/ModalHeader'
|
|
||||||
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'
|
|
||||||
import InputGroup from './InputGroup'
|
|
||||||
|
|
||||||
class SettingsModal extends React.Component {
|
|
||||||
|
|
||||||
// When the settings are shown, it loads the access key and secret key.
|
|
||||||
componentWillMount() {
|
|
||||||
const {web, dispatch} = this.props
|
|
||||||
const {serverInfo} = this.props
|
|
||||||
|
|
||||||
let accessKeyEnv = ''
|
|
||||||
let secretKeyEnv = ''
|
|
||||||
// Check environment variables first.
|
|
||||||
if (serverInfo.info.isEnvCreds) {
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
accessKey: 'xxxxxxxxx',
|
|
||||||
secretKey: 'xxxxxxxxx',
|
|
||||||
keysReadOnly: true
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
web.GetAuth()
|
|
||||||
.then(data => {
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
accessKey: data.accessKey,
|
|
||||||
secretKey: data.secretKey
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// When they are re-hidden, the keys are unloaded from memory.
|
|
||||||
componentWillUnmount() {
|
|
||||||
const {dispatch} = this.props
|
|
||||||
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
accessKey: '',
|
|
||||||
secretKey: '',
|
|
||||||
secretKeyVisible: false
|
|
||||||
}))
|
|
||||||
dispatch(actions.hideSettings())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle field changes from inside the modal.
|
|
||||||
accessKeyChange(e) {
|
|
||||||
const {dispatch} = this.props
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
accessKey: e.target.value
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
secretKeyChange(e) {
|
|
||||||
const {dispatch} = this.props
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
secretKey: e.target.value
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
secretKeyVisible(secretKeyVisible) {
|
|
||||||
const {dispatch} = this.props
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
secretKeyVisible
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the auth params and set them.
|
|
||||||
setAuth(e) {
|
|
||||||
e.preventDefault()
|
|
||||||
const {web, dispatch} = this.props
|
|
||||||
|
|
||||||
let accessKey = document.getElementById('accessKey').value
|
|
||||||
let secretKey = document.getElementById('secretKey').value
|
|
||||||
web.SetAuth({
|
|
||||||
accessKey,
|
|
||||||
secretKey
|
|
||||||
})
|
|
||||||
.then(data => {
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
accessKey: '',
|
|
||||||
secretKey: '',
|
|
||||||
secretKeyVisible: false
|
|
||||||
}))
|
|
||||||
dispatch(actions.hideSettings())
|
|
||||||
dispatch(actions.showAlert({
|
|
||||||
type: 'success',
|
|
||||||
message: 'Changed credentials'
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
accessKey: '',
|
|
||||||
secretKey: '',
|
|
||||||
secretKeyVisible: false
|
|
||||||
}))
|
|
||||||
dispatch(actions.hideSettings())
|
|
||||||
dispatch(actions.showAlert({
|
|
||||||
type: 'danger',
|
|
||||||
message: err.message
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
generateAuth(e) {
|
|
||||||
e.preventDefault()
|
|
||||||
const {dispatch} = this.props
|
|
||||||
|
|
||||||
web.GenerateAuth()
|
|
||||||
.then(data => {
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
secretKeyVisible: true
|
|
||||||
}))
|
|
||||||
dispatch(actions.setSettings({
|
|
||||||
accessKey: data.accessKey,
|
|
||||||
secretKey: data.secretKey
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
hideSettings(e) {
|
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
const {dispatch} = this.props
|
|
||||||
dispatch(actions.hideSettings())
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let {settings} = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal bsSize="sm" animation={ false } show={ true }>
|
|
||||||
<ModalHeader>
|
|
||||||
Change Password
|
|
||||||
</ModalHeader>
|
|
||||||
<ModalBody className="m-t-20">
|
|
||||||
<InputGroup value={ settings.accessKey }
|
|
||||||
onChange={ this.accessKeyChange.bind(this) }
|
|
||||||
id="accessKey"
|
|
||||||
label="Access Key"
|
|
||||||
name="accesskey"
|
|
||||||
type="text"
|
|
||||||
spellCheck="false"
|
|
||||||
required="required"
|
|
||||||
autoComplete="false"
|
|
||||||
align="ig-left"
|
|
||||||
readonly={ settings.keysReadOnly }></InputGroup>
|
|
||||||
<i onClick={ this.secretKeyVisible.bind(this, !settings.secretKeyVisible) } className={ "toggle-password fa fa-eye " + (settings.secretKeyVisible ? "toggled" : "") } />
|
|
||||||
<InputGroup value={ settings.secretKey }
|
|
||||||
onChange={ this.secretKeyChange.bind(this) }
|
|
||||||
id="secretKey"
|
|
||||||
label="Secret Key"
|
|
||||||
name="accesskey"
|
|
||||||
type={ settings.secretKeyVisible ? "text" : "password" }
|
|
||||||
spellCheck="false"
|
|
||||||
required="required"
|
|
||||||
autoComplete="false"
|
|
||||||
align="ig-left"
|
|
||||||
readonly={ settings.keysReadOnly }></InputGroup>
|
|
||||||
</ModalBody>
|
|
||||||
<div className="modal-footer">
|
|
||||||
<button className={ "btn btn-primary " + (settings.keysReadOnly ? "hidden" : "") } onClick={ this.generateAuth.bind(this) }>
|
|
||||||
Generate
|
|
||||||
</button>
|
|
||||||
<button href="" className={ "btn btn-success " + (settings.keysReadOnly ? "hidden" : "") } onClick={ this.setAuth.bind(this) }>
|
|
||||||
Update
|
|
||||||
</button>
|
|
||||||
<button href="" className="btn btn-link" onClick={ this.hideSettings.bind(this) }>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(state => {
|
|
||||||
return {
|
|
||||||
web: state.web,
|
|
||||||
settings: state.settings,
|
|
||||||
serverInfo: state.serverInfo
|
|
||||||
}
|
|
||||||
})(SettingsModal)
|
|
Loading…
Reference in New Issue
Block a user