let storage = new Storage();
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleInputChange(event) {
this.props.onSearchInput(event.target.value);
}
handleSubmit(event) {
this.props.onSearchSubmit(event);
}
render() {
let btn =
Generate
if (this.props != null && this.props.appName != null) {
btn =
}
return (
{btn}
);
}
}
class DeleteAppButton extends React.Component {
render() {
return (
Delete {this.props.appName}
)
}
}
class Message extends React.Component {
render() {
var variants = {
"status": "info",
"progress": "info",
"failure": "danger",
"done": "success"
}
switch (this.props.action) {
case 'done':
case 'failure':
case 'status':
return (
{this.props.message}
)
break;
case 'progress':
return (
{this.props.message}
)
break;
case 'choose':
const items = JSON.parse(this.props.message);
return (
Choose a Dump
Multiple cluster dumps were found, please pick one:
{items.map((item, index) => {
let url = new URL(window.location.href);
url.searchParams.set('search', item);
return ({item}
)
})}
)
case 'kubeconfig':
var encodedKubeconfig = "data:text/yaml;charset=utf-8;base64,"+ btoa(this.props.message);
return (
Kubeconfig
Download kubeconfig
{this.props.message}
)
break;
case 'link':
return (
{this.props.message}
)
break;
default:
return (
)
}
}
}
class ResourceQuotaStatus extends React.Component {
render() {
if (this.props === null || this.props.resourceQuota === null) {
return (
)
}
let used = this.props.resourceQuota.used;
let hard = this.props.resourceQuota.hard;
if (typeof used == "undefined" || typeof hard == "undefined") {
return (
)
}
return (
)
}
}
class Status extends React.Component {
render() {
if (this.props.messages.length == 0) {
return (
);
} else {
return(
{
this.props.messages.map(item =>
)
}
);
}
}
}
class AppsList extends React.Component {
render() {
let appCount = Object.keys(this.props.apps).length;
if (appCount === 0) {
return false;
}
let header = Currently running KAS instances
let apps = Object.keys(this.props.apps).map(k => {
return (
{k}
{
this.props.onDeleteApp(k)
}}
appName={k}
/>
)
})
return
{header}
{apps}
}
}
class SearchForm extends React.Component {
constructor(props) {
super(props);
this.state = {
querySearch: '',
searchInput: '',
messages: [],
appName: null,
apps: storage.getData(),
ws: null,
resourceQuota: {
used: 0,
hard: 0,
}
};
this.handleSearchInput = this.handleSearchInput.bind(this);
this.handleSearchSubmit = this.handleSearchSubmit.bind(this);
this.handleDeleteAppInternal = this.handleDeleteAppInternal.bind(this);
this.handleDeleteApp = this.handleDeleteApp.bind(this);
this.handleDeleteCurrentApp = this.handleDeleteCurrentApp.bind(this);
this.addMessage = this.addMessage.bind(this);
this.sendWSMessage = this.sendWSMessage.bind(this);
this.connect = this.connect.bind(this);
this.check = this.check.bind(this);
this.search = this.search.bind(this);
}
handleSearchInput(searchInput) {
this.setState({searchInput: searchInput});
}
handleSearchSubmit(event) {
event.preventDefault();
if (this.state.searchInput.length == 0) {
return;
}
this.search(this.state.searchInput);
}
sendWSMessage(message) {
// add messages to queue if connection is not ready
if (!this.state.ws || this.state.ws.readyState != WebSocket.OPEN) {
if (this.state.ws) {
console.log("ws.readyState " + this.state.ws.readyState);
}
if (!this.ws_msgs) this.ws_msgs = []
console.log("Added message " + message + " to queue");
this.ws_msgs.push(message)
} else {
console.log("Sending message " + message);
this.state.ws.send(message)
}
}
search(input) {
try {
this.state.messages = [];
this.sendWSMessage(JSON.stringify({
'action': 'new',
'message': input,
}));
} catch (error) {
console.log(error);
}
}
handleDeleteApp(appName) {
console.log(appName)
if (this.state.appName === appName) {
this.handleDeleteCurrentApp()
} else {
this.handleDeleteAppInternal(appName)
}
}
handleDeleteCurrentApp() {
this.handleDeleteAppInternal(this.state.appName)
// Remove message with app-label from the list
let newMessages = this.state.messages.slice(1, this.state.messages.length)
this.setState(state => ({
messages: newMessages,
appName: null,
}))
}
handleDeleteAppInternal(appName) {
try {
this.sendWSMessage(JSON.stringify({
'action': 'delete',
'message': appName
}))
storage.removeInstance(appName)
this.setState(state => ({
apps: storage.getData(),
}))
} catch (error) {
console.log(error)
}
}
addMessage(message) {
this.setState(state => ({ messages: [...state.messages, message] }))
if (message.action === "app-label") {
this.setState(state => ({appName: message.message}))
}
if (message.action === "done") {
// Remove message with progress from the list
let newMessages = this.state.messages.filter(function(message){
return message.action != "progress";
});
this.setState(state => ({ messages: newMessages }))
if (message.data != null) {
storage.addInstance(message.data.hash, message.data.url)
}
this.setState(state => ({apps: storage.getData()}))
}
if (message.action === "rquota") {
let rquotaStatus = JSON.parse(message.message)
this.setState(state => ({
resourceQuota: {
used: rquotaStatus.used,
hard: rquotaStatus.hard,
}
}))
}
}
check () {
const { ws } = this.state;
if (!ws || ws.readyState == WebSocket.CLOSED) this.connect(); //check if websocket instance is closed, if so call `connect` function.
};
connect () {
var loc = window.location;
var ws_uri;
if (loc.protocol === "https:") {
ws_uri = "wss:";
} else {
ws_uri = "ws:";
}
ws_uri += "//" + loc.host;
ws_uri += "/ws/status";
var ws = new WebSocket(ws_uri);
let that = this;
var connectInterval;
// websocket onopen event listener
ws.onopen = () => {
console.log("websocket connected");
that.setState({ ws: ws });
that.timeout = 250; // reset timer to 250 on open of websocket connection
clearTimeout(connectInterval); // clear Interval on on open of websocket connection
// Send messages if there's a queue
while (that.ws_msgs && that.ws_msgs.length > 0) {
ws.send(that.ws_msgs.pop())
}
};
// websocket onclose event listener
ws.onclose = e => {
console.log(
`Socket is closed. Reconnect will be attempted in ${Math.min(
10000 / 1000,
(that.timeout + that.timeout) / 1000
)} second.`,
e.reason
);
that.timeout = that.timeout + that.timeout; //increment retry interval
connectInterval = setTimeout(this.check, Math.min(10000, that.timeout)); //call check function after timeout
};
// websocket onerror event listener
ws.onerror = err => {
console.error(
"Socket encountered error: ",
err.message,
"Closing socket"
);
ws.close();
};
ws.onmessage = evt => {
console.log("Received " + evt.data);
const message = JSON.parse(evt.data);
this.addMessage(message)
}
this.setState({ ws: ws });
}
componentDidMount() {
this.check();
this.timeout = 0;
if (!this.state.searchInput) {
let params = (new URL(window.location)).searchParams;
let searchInput = params.get('search');
if (searchInput && searchInput != this.state.querySearch) {
this.state.querySearch = searchInput;
this.handleSearchInput(searchInput);
this.search(searchInput);
}
}
}
render() {
let messages;
let searchClass;
if(this.state.appName != null) {
messages =
searchClass = null;
} else {
messages = [];
searchClass = 'search-center';
}
return (
KAS as a service
{messages}
);
}
}
ReactDOM.render(
,
document.getElementById('container')
);