Skip to content

Commit

Permalink
LOTUS: (#84)
Browse files Browse the repository at this point in the history
- make fat html containing all assets itself
- add support for inline added base64 data to html input with id=embedded-file-input. If it exists, atson displays this data.

Co-authored-by: Vladislav Baluk <[email protected]>
  • Loading branch information
vlbaluk and vbalukAtlas committed Jul 10, 2024
1 parent ffef759 commit 0cb5f3f
Show file tree
Hide file tree
Showing 6 changed files with 1,948 additions and 1,277 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"d3": "7.8.5",
"d3-flame-graph": "4.1.3",
"flatted": "3.2.7",
"jszip": "^3.10.1",
"localforage": "1.10.0",
"prop-types": "15.8.1",
"react": "18.2.0",
Expand Down Expand Up @@ -53,7 +54,8 @@
"stylelint-config-standard": "34.0.0",
"stylelint-order": "6.0.3",
"typescript": "5.1.6",
"vite": "4.4.9",
"vite": "^5.3.3",
"vite-plugin-singlefile": "^2.0.2",
"vite-tsconfig-paths": "4.2.0",
"vitest": "0.34.2"
},
Expand Down
3 changes: 2 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import StuckThreadsPage from './components/StuckThreads/StuckThreadsPage';
import MonitorsPage from './components/Monitors/MonitorsPage';
import FlameGraphPage from './components/FlameGraph/FlameGraphPage';
import ThreadsOverviewPage from './components/ThreadsOverview/ThreadsOverviewPage';
import Index from './components/Index/Index';

const router = createHashRouter([
{
path: '/',
element: <FullPageDropzone />,
element: <Index />,
},
{
path: ':threadDumpsHash/*',
Expand Down
76 changes: 76 additions & 0 deletions src/components/EmbeddedDataIndex/EmbeddedDataIndex.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react';
import { Navigate } from 'react-router-dom';
import JSZip from 'jszip';
import { setParsedData } from '../../common/threadDumpsStorageService';
import Parser from '../../parser/Parser';
import ThreadDump from '../../types/ThreadDump';

type State = {
parsedDataKey: string | undefined;
hasCpuUsageInfo: boolean;
loadingEmbeddedData: boolean;
b64zip: string;
};

type Props = {
b64zip: string;
};

export default class EmbeddedDataIndex extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
parsedDataKey: undefined,
hasCpuUsageInfo: false,
loadingEmbeddedData: true,
b64zip: props.b64zip,
};
}

async componentDidMount(): Promise<void> {
const { b64zip } = this.state;
const zipBytes = atob(b64zip);
const zipFile = new File([new Uint8Array(zipBytes.split('').map((c) => c.charCodeAt(0)))], 'embedded.zip');
const zip = await new JSZip().loadAsync(zipFile);
const files = await Promise.all(zip.file(/.*\.txt/)
.map(async (zipEntry) => {
const blob = await zipEntry.async('blob');
return new File([blob], zipEntry.name);
}));

const parser = new Parser(this.onParsed);
parser.parseFiles(files);
}

private onParsed = (threadDumps: ThreadDump[]): void => {
const key = setParsedData(threadDumps);
this.setState((state) => ({
...state,
parsedDataKey: key,
hasCpuUsageInfo: threadDumps.some((dump) => dump.threads.some((thread) => thread.cpuUsage !== '0.00')),
loadingEmbeddedData: false,
}));
};

public render(): JSX.Element {
const { parsedDataKey, hasCpuUsageInfo, loadingEmbeddedData } = this.state;
if (loadingEmbeddedData) {
return <h1>Loading...</h1>;
}

if (parsedDataKey) {
if (hasCpuUsageInfo) {
return (
<Navigate to={`/${parsedDataKey}/summary`} />
);
}
return (
<Navigate to={`/${parsedDataKey}/similar-stacks`} />
);
}

return (
<h1>Loading...</h1>
);
}
}
31 changes: 31 additions & 0 deletions src/components/Index/Index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';

import EmbeddedDataIndex from '../EmbeddedDataIndex/EmbeddedDataIndex';
import FullPageDropzone from '../FullPageDropzone/FullPageDropzone';

export default class Index extends React.PureComponent<unknown, { b64zip: string | undefined }> {
constructor(props: unknown) {
super(props);
this.state = {
b64zip: undefined,
};
}

componentDidMount() {
let b64zip:string;
const embeddedFileInput = document.getElementById('embedded-file-input');
if (embeddedFileInput) {
b64zip = embeddedFileInput.getAttribute('value')!;
if (b64zip) this.setState((state) => ({ ...state, b64zip }));
}
}

public render(): JSX.Element {
const { b64zip } = this.state;
if (b64zip) {
return <EmbeddedDataIndex b64zip={b64zip} />;
}

return <FullPageDropzone />;
}
}
2 changes: 2 additions & 0 deletions vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import viteTsconfigPaths from 'vite-tsconfig-paths';
import { configDefaults } from 'vitest/dist/config';
import {viteSingleFile} from "vite-plugin-singlefile";

// https://vitejs.dev/config/
export default defineConfig({
Expand All @@ -24,5 +25,6 @@ export default defineConfig({
plugins: [
react(),
viteTsconfigPaths(),
viteSingleFile()
],
});
Loading

0 comments on commit 0cb5f3f

Please sign in to comment.