Merge pull request #141 from garasubo/gh-56

#56: add download buttton
This commit is contained in:
Eric Herbrandson
2020-10-17 11:45:26 -05:00
committed by GitHub
3 changed files with 62 additions and 4 deletions
+7 -1
View File
@@ -1,6 +1,6 @@
import _ from 'lodash';
import {Base64} from 'js-base64';
import {request, post, stream, apiFactory, apiFactoryWithNamespace} from './apiProxy';
import { request, post, stream, apiFactory, apiFactoryWithNamespace, requestText } from './apiProxy';
import log from '../utils/log';
import {K8sEvent, Namespace, TODO, Metrics, PersistentVolume, Node, Pod, ClusterRole, ClusterRoleBinding, ConfigMap, RoleBinding, Secret, ServiceAccount, StorageClass} from '../utils/types';
@@ -41,6 +41,7 @@ const apis = {
testAuth,
getRules,
logs,
logsAll,
swagger,
exec,
metrics: metricsFactory(),
@@ -162,6 +163,11 @@ function exec(namespace: string, name: string, container: string, cb: DataCallba
return stream(url, cb, {additionalProtocols, isJson: false});
}
function logsAll(namespace: string, name: string, container: string, showPrevious: boolean) {
const url = `/api/v1/namespaces/${namespace}/pods/${name}/log?container=${container}&previous=${showPrevious}`;
return requestText(url);
}
function logs(namespace: string, name: string, container: string, tailLines: number, showPrevious: boolean, cb: DataCallback<string[]>) {
const items: string[] = [];
const url = `/api/v1/namespaces/${namespace}/pods/${name}/log?container=${container}&previous=${showPrevious}&tailLines=${tailLines}&follow=true`;
+10 -2
View File
@@ -25,7 +25,7 @@ const BASE_HTTP_URL = isDev && hostname === 'localhost' ? 'http://localhost:4654
const BASE_WS_URL = BASE_HTTP_URL.replace('http', 'ws');
const JSON_HEADERS = {Accept: 'application/json', 'Content-Type': 'application/json'};
export async function request(path: string, params?: any, autoLogoutOnAuthError = true) {
async function requestInner(path: string, params?: any, autoLogoutOnAuthError = true) {
const opts = Object.assign({headers: {}}, params);
const token = getToken();
@@ -55,7 +55,15 @@ export async function request(path: string, params?: any, autoLogoutOnAuthError
throw error;
}
return response.json();
return response;
}
export async function request(path: string, params?: any, autoLogoutOnAuthError = true) {
return (await requestInner(path, params, autoLogoutOnAuthError)).json();
}
export async function requestText(path: string, params?: any, autoLogoutOnAuthError = true) {
return (await requestInner(path, params, autoLogoutOnAuthError)).text();
}
export function apiFactory<T extends ApiItem<any, any>>(group: string, version: string, resource: string) {
+45 -1
View File
@@ -9,6 +9,9 @@ import InputFilter from '../components/inputFilter';
import Loading from '../components/loading';
import api from '../services/api';
import {Pod} from '../utils/types';
import Button from '../components/button';
import LogsSvg from '../art/logsSvg';
import LoadingSvg from '../art/loadingSvg';
type Props = {
namespace: string;
@@ -23,6 +26,7 @@ type State = {
container?: string;
initContainers?: string[];
filter?: string;
logDownloading: boolean;
}
export default class Logs extends Base<Props, State> {
@@ -31,6 +35,7 @@ export default class Logs extends Base<Props, State> {
state: State = {
showPrevious: false,
items: [],
logDownloading: false,
};
constructor(props: Props) {
@@ -41,6 +46,7 @@ export default class Logs extends Base<Props, State> {
// than once during the wait timeout."
const options = {leading: true, trailing: true, maxWait: 1000};
this.debouncedSetState = _.debounce(this.setState.bind(this), 100, options);
this.startDownloadLog = this.startDownloadLog.bind(this);
}
componentDidMount() {
@@ -85,9 +91,38 @@ export default class Logs extends Base<Props, State> {
});
}
startDownloadLog() {
const {namespace, name} = this.props;
const {container, showPrevious = false, logDownloading} = this.state;
if (!container || logDownloading) {
return;
}
this.setState({logDownloading: true}, async () => {
const message = await api.logsAll(namespace, name, container, showPrevious).catch(() => {
this.setState({logDownloading: false});
});
if (message) {
const blob = new Blob([message], {
type: 'text/plain;charset=utf8',
});
const url = window.URL.createObjectURL(blob);
const element = document.createElement('a');
element.setAttribute('href', url);
element.setAttribute('download', `${name}.log`);
element.click();
window.URL.revokeObjectURL(url);
this.setState({logDownloading: false});
}
});
}
render() {
const {namespace, name} = this.props;
const {items, container, containers = [], initContainers = [], filter = '', showPrevious = false} = this.state;
const {items, container, containers = [], initContainers = [], filter = '', showPrevious = false, logDownloading} = this.state;
const lowercaseFilter = filter.toLowerCase();
const filteredLogs = items.filter(x => x.toLowerCase().includes(lowercaseFilter));
@@ -133,10 +168,19 @@ export default class Logs extends Base<Props, State> {
<div className='logs_showPreviousLabel'>Previous</div>
</label>
<InputFilter
filter={filter}
onChange={x => this.setState({filter: x})}
/>
<Button
className="button_clear log_downloadButton"
title="Download Log"
onClick={this.startDownloadLog}
>
{logDownloading ? <LoadingSvg /> : <LogsSvg />}
</Button>
</div>
<div className='contentPanel'>