Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new-log-viewer: Add support for loading files through open dialog or drag-and-drop; Display file name in the UI. #56

Merged
merged 22 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8644605
new-log-viewer: Add local file load support.
junhaoliao Aug 19, 2024
078942d
Display file name.
junhaoliao Aug 19, 2024
597913c
Moved OnFileOpenCallback type to a dedicated typings file.
junhaoliao Aug 20, 2024
1e6fa8a
Merge branch 'main' into load-local-file
junhaoliao Aug 28, 2024
110c4c4
Add drag-and-drop file load functionality.
junhaoliao Aug 28, 2024
fbbd93c
Prompts / Error messages improvement - Apply suggestions from code re…
junhaoliao Sep 1, 2024
37152fe
Remove redundant docs.
junhaoliao Sep 1, 2024
9d1774e
Remove obsolete css class name "drop-file-children-no-pointer-events"…
junhaoliao Sep 1, 2024
1cf2e96
Docs - Apply suggestions from code review
junhaoliao Sep 1, 2024
0c98294
Use global CSS variables for z-index in DropFileContainer.
junhaoliao Sep 1, 2024
08cda54
Use `rem` for font size in DropFileContainer's hover message.
junhaoliao Sep 1, 2024
f1aac58
Add docs about the range check for "dragleave".
junhaoliao Sep 1, 2024
7008fd1
Add `ylv-` prefix to yscope-log-viewer specific global variables.
junhaoliao Sep 1, 2024
81485ab
Set global font-family variables.
junhaoliao Sep 1, 2024
80acb4b
Set base font size for HTML to 16px.
junhaoliao Sep 1, 2024
87ba9f2
Docs improvement - Apply suggestions from code review
junhaoliao Sep 1, 2024
3ae6b02
Fix loadFile docs.
junhaoliao Sep 1, 2024
e776f5f
Backup and unset `filePath` in the URL, which can be restored after s…
junhaoliao Sep 1, 2024
d2bf145
Split font-family declaration into two lines for readability.
junhaoliao Sep 1, 2024
cb6c16f
CSS Docs - Apply suggestions from code review
junhaoliao Sep 1, 2024
9d8f949
Revert "Backup and unset `filePath` in the URL, which can be restored…
junhaoliao Sep 1, 2024
eba0aea
Clear filePath in the app URL when a local file gets loaded.
junhaoliao Sep 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions new-log-viewer/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
<meta name="keywords"
content="yscope clp debug debugging large log logs s3 scanner viewer vscode">
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" crossorigin href="https://fonts.gstatic.com">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto&display=swap">
</head>
<body>
<div id="root"></div>
Expand Down
31 changes: 31 additions & 0 deletions new-log-viewer/src/components/DropFileContainer/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.drop-file-container {
width: 100%;
height: 100%;
position: relative;
}

.drop-file-children {
width: 100%;
height: 100%;
}

.hover-mask {
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(2, 88, 168, 0.2);
display: flex;
align-items: center;
justify-content: center;
z-index: var(--ylv-drop-file-container-hover-mask-z-index);
}

.hover-message {
padding: 8px;
color: #616161;
font-size: 0.875rem;
kirkrodrigues marked this conversation as resolved.
Show resolved Hide resolved
font-family: var(--ylv-ui-font-family), sans-serif;
background-color: #f3f3f3;
z-index: var(--ylv-drop-file-container-hover-message-z-index);
}
96 changes: 96 additions & 0 deletions new-log-viewer/src/components/DropFileContainer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, {
useContext,
useState,
} from "react";

import {StateContext} from "../../contexts/StateContextProvider";
import {CURSOR_CODE} from "../../typings/worker";

import "./index.css";


interface DropFileContextProviderProps {
children: React.ReactNode;
}

/**
* A container element to add drag & drop functionality to the child elements.
*
* @param props
* @param props.children
* @return
*/
const DropFileContainer = ({children}: DropFileContextProviderProps) => {
const {loadFile} = useContext(StateContext);
const [isFileHovering, setIsFileHovering] = useState(false);

const handleDrag = (ev: React.DragEvent<HTMLDivElement>) => {
ev.preventDefault();
ev.stopPropagation();

if ("dragenter" === ev.type) {
setIsFileHovering(true);
} else if ("dragleave" === ev.type) {
// Only stop the hover effect if the pointer leaves the bounding rectangle of the
// DropFileContainer.
//
// NOTE: "dragleave" could get fired when the wrapped `children` receive focus. Setting
// `pointer-events: none` on the children is viable but could cause the children to be
// unresponsive. So instead, we use the solution below.
const {bottom, left, right, top} = ev.currentTarget.getBoundingClientRect();
if (ev.clientX >= left && ev.clientX <= right &&
ev.clientY >= top && ev.clientY <= bottom) {
return;
}

setIsFileHovering(false);
}
};

const handleDrop = (ev: React.DragEvent<HTMLDivElement>) => {
ev.preventDefault();
ev.stopPropagation();

setIsFileHovering(false);

const [file] = ev.dataTransfer.files;
if ("undefined" === typeof file) {
console.warn("No file dropped.");

return;
}
loadFile(file, {code: CURSOR_CODE.LAST_EVENT, args: null});
};

return (
<div
className={"drop-file-container"}
onDragEnter={handleDrag}
onDragLeave={handleDrag}
onDragOver={handleDrag}
onDrop={handleDrop}
>
<div
className={"drop-file-children"}
onDrop={handleDrop}
>
{children}
{isFileHovering && (
<div
className={"hover-mask"}
onDrop={handleDrop}
>
<div
className={"hover-message"}
onDrop={handleDrop}
>
Drop file to view
</div>
</div>
)}
</div>
</div>
);
};

export default DropFileContainer;
25 changes: 23 additions & 2 deletions new-log-viewer/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ import {
LOCAL_STORAGE_KEY,
THEME_NAME,
} from "../typings/config";
import {CURSOR_CODE} from "../typings/worker";
import {ACTION_NAME} from "../utils/actions";
import {
getConfig,
setConfig,
} from "../utils/config";
import {openFile} from "../utils/file";
import {
getFirstItemNumInNextChunk,
getLastItemNumInPrevChunk,
} from "../utils/math";
import DropFileContainer from "./DropFileContainer";
import Editor from "./Editor";
import {goToPositionAndCenter} from "./Editor/MonacoInstance/utils";

Expand Down Expand Up @@ -164,8 +167,10 @@ const handleLogEventNumInputChange = (ev: React.ChangeEvent<HTMLInputElement>) =
*/
const Layout = () => {
const {
pageNum,
fileName,
loadFile,
numEvents,
pageNum,
} = useContext(StateContext);
const {logEventNum} = useContext(UrlContext);

Expand All @@ -176,6 +181,12 @@ const Layout = () => {
copyPermalinkToClipboard({}, {logEventNum: numEvents});
};

const handleOpenFileButtonClick = () => {
openFile((file) => {
loadFile(file, {code: CURSOR_CODE.LAST_EVENT, args: null});
});
};

/**
* Handles custom actions in the editor.
*
Expand Down Expand Up @@ -251,15 +262,25 @@ const Layout = () => {
PageNum -
{" "}
{pageNum}
{" "}
| FileName -
{" "}
{fileName}
</h3>

<button onClick={handleCopyLinkButtonClick}>
Copy link to last log
</button>

<button onClick={handleOpenFileButtonClick}>
Open File
</button>

<ConfigForm/>
<div style={{flexDirection: "column", flexGrow: 1}}>
<Editor onCustomAction={handleCustomAction}/>
<DropFileContainer>
<Editor onCustomAction={handleCustomAction}/>
</DropFileContainer>
</div>
</div>
</>
Expand Down
18 changes: 14 additions & 4 deletions new-log-viewer/src/contexts/StateContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React, {

import {Nullable} from "../typings/common";
import {CONFIG_KEY} from "../typings/config";
import {SEARCH_PARAM_NAMES} from "../typings/url";
import {
BeginLineNumToLogEventNumMap,
CURSOR_CODE,
Expand All @@ -26,6 +27,7 @@ import {
} from "../utils/math";
import {
updateWindowUrlHashParams,
updateWindowUrlSearchParams,
URL_HASH_PARAMS_DEFAULT,
URL_SEARCH_PARAMS_DEFAULT,
UrlContext,
Expand All @@ -34,6 +36,7 @@ import {

interface StateContextType {
beginLineNumToLogEventNum: BeginLineNumToLogEventNumMap,
fileName: string,
loadFile: (fileSrc: FileSrcType, cursor: CursorType) => void,
logData: string,
numEvents: number,
Expand All @@ -45,8 +48,9 @@ const StateContext = createContext<StateContextType>({} as StateContextType);
/**
* Default values of the state object.
*/
const STATE_DEFAULT = Object.freeze({
const STATE_DEFAULT: Readonly<StateContextType> = Object.freeze({
beginLineNumToLogEventNum: new Map<number, number>(),
fileName: "",
loadFile: () => null,
logData: "Loading...",
numEvents: 0,
Expand Down Expand Up @@ -106,6 +110,7 @@ const getLastLogEventNum = (beginLineNumToLogEventNum: BeginLineNumToLogEventNum
const StateContextProvider = ({children}: StateContextProviderProps) => {
kirkrodrigues marked this conversation as resolved.
Show resolved Hide resolved
const {filePath, logEventNum} = useContext(UrlContext);

const [fileName, setFileName] = useState<string>(STATE_DEFAULT.fileName);
const [logData, setLogData] = useState<string>(STATE_DEFAULT.logData);
const [numEvents, setNumEvents] = useState<number>(STATE_DEFAULT.numEvents);
const beginLineNumToLogEventNumRef =
Expand All @@ -127,16 +132,17 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
const {code, args} = ev.data;
console.log(`[MainWorker -> Renderer] code=${code}`);
switch (code) {
case WORKER_RESP_CODE.LOG_FILE_INFO:
setFileName(args.fileName);
setNumEvents(args.numEvents);
break;
case WORKER_RESP_CODE.PAGE_DATA: {
setLogData(args.logs);
beginLineNumToLogEventNumRef.current = args.beginLineNumToLogEventNum;
const lastLogEventNum = getLastLogEventNum(args.beginLineNumToLogEventNum);
updateLogEventNumInUrl(lastLogEventNum, logEventNumRef.current);
break;
}
case WORKER_RESP_CODE.NUM_EVENTS:
setNumEvents(args.numEvents);
break;
case WORKER_RESP_CODE.NOTIFICATION:
// TODO: notifications should be shown in the UI when the NotificationProvider
// is added
Expand All @@ -149,6 +155,9 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
}, []);

const loadFile = useCallback((fileSrc: FileSrcType, cursor: CursorType) => {
if ("string" !== typeof fileSrc) {
updateWindowUrlSearchParams({[SEARCH_PARAM_NAMES.FILE_PATH]: null});
}
if (null !== mainWorkerRef.current) {
mainWorkerRef.current.terminate();
}
Expand Down Expand Up @@ -244,6 +253,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
<StateContext.Provider
value={{
beginLineNumToLogEventNum: beginLineNumToLogEventNumRef.current,
fileName: fileName,
loadFile: loadFile,
logData: logData,
numEvents: numEvents,
Expand Down
20 changes: 20 additions & 0 deletions new-log-viewer/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,23 @@ html, body, #root {
height: 100%;
width: 100%;
}

html {
font-size: 16px;
}

:root {
/* font-family globals */
--ylv-ui-font-family: -apple-system, BlinkMacSystemFont, system-ui, Ubuntu, "Droid Sans",
Roboto;

/* z-index globals
*
* Other z-index values in the project for reference:
* ```
* .monaco-editor .minimap { z-index: 5; }
* ```
*/
--ylv-drop-file-container-hover-mask-z-index: 10;
--ylv-drop-file-container-hover-message-z-index: 11;
}
10 changes: 7 additions & 3 deletions new-log-viewer/src/services/LogFileManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import JsonlDecoder from "./decoders/JsonlDecoder";
*
* @param fileSrc The source of the file to load. This can be a string representing a URL, or a File
* object.
* @return A promise that resolves with the number of log events found in the file.
* @return A promise that resolves with an object containing the file name and file data.
* @throws {Error} If the file source type is not supported.
*/
const loadFile = async (fileSrc: FileSrcType)
Expand All @@ -32,8 +32,8 @@ const loadFile = async (fileSrc: FileSrcType)
fileName = getBasenameFromUrlOrDefault(fileSrc);
fileData = await getUint8ArrayFrom(fileSrc, () => null);
} else {
// TODO: support file loading via Open / Drag-n-drop
throw new Error("Read from file not yet supported");
fileName = fileSrc.name;
fileData = new Uint8Array(await fileSrc.arrayBuffer());
}

return {
Expand Down Expand Up @@ -77,6 +77,10 @@ class LogFileManager {
this.#decoder = this.#initDecoder(decoderOptions);
}

get fileName () {
return this.#fileName;
}

get numEvents () {
return this.#numEvents;
}
Expand Down
8 changes: 4 additions & 4 deletions new-log-viewer/src/services/MainWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ onmessage = async (ev: MessageEvent<MainWorkerReqMessage>) => {
args.decoderOptions
);

postResp(
WORKER_RESP_CODE.NUM_EVENTS,
{numEvents: LOG_FILE_MANAGER.numEvents}
);
postResp(WORKER_RESP_CODE.LOG_FILE_INFO, {
fileName: LOG_FILE_MANAGER.fileName,
numEvents: LOG_FILE_MANAGER.numEvents,
});
postResp(
WORKER_RESP_CODE.PAGE_DATA,
LOG_FILE_MANAGER.loadPage(args.cursor)
Expand Down
3 changes: 3 additions & 0 deletions new-log-viewer/src/typings/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type OnFileOpenCallback = (file: File) => void;

export type {OnFileOpenCallback};
Loading