Skip to content

Commit

Permalink
Merge branch 'main' into settings-tab
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/components/modals/SettingsModal/SettingsDialog.tsx
  • Loading branch information
junhaoliao committed Mar 2, 2025
2 parents c9d425b + 19fd738 commit b3e5104
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 124 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @y-scope/maintainers
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
IconButton,
IconButtonProps,
Tooltip,
} from "@mui/joy";


interface ToggleIconButtonProps extends IconButtonProps {
children: React.ReactNode;
isChecked: boolean;
tooltipTitle: string;
}

/**
* An icon button that can visually show icon pressed status.
*
* @param props
* @param props.children
* @param props.isChecked
* @param props.tooltipTitle
* @param props.rest
* @return
*/
const ToggleIconButton = ({
children,
isChecked,
tooltipTitle,
...rest
}: ToggleIconButtonProps) => {
return (
<Tooltip
title={tooltipTitle}
>
<span>
<IconButton
aria-pressed={isChecked}
{...rest}
>
{children}
</IconButton>
</span>
</Tooltip>
);
};

export default ToggleIconButton;
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
}

.query-option-button {
width: 1.5rem !important;
min-width: 0 !important;
height: 1.5rem !important;
min-height: 0 !important;

font-family: Inter, sans-serif !important;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ import React, {
import {
AccordionGroup,
Box,
IconButton,
LinearProgress,
Stack,
Textarea,
ToggleButtonGroup,
Tooltip,
} from "@mui/joy";

import UnfoldLessIcon from "@mui/icons-material/UnfoldLess";
Expand All @@ -30,33 +28,11 @@ import {isDisabled} from "../../../../../utils/states";
import CustomTabPanel from "../CustomTabPanel";
import PanelTitleButton from "../PanelTitleButton";
import ResultsGroup from "./ResultsGroup";
import ToggleIconButton from "./ToggleIconButton";

import "./index.css";


enum QUERY_OPTION {
IS_CASE_SENSITIVE = "isCaseSensitive",
IS_REGEX = "isRegex",
}

/**
* Determines if the query is case-sensitive based on the provided query options.
*
* @param queryOptions
* @return True if the query is case-sensitive.
*/
const getIsCaseSensitive =
(queryOptions: QUERY_OPTION[]) => queryOptions.includes(QUERY_OPTION.IS_CASE_SENSITIVE);

/**
* Determines if the query is a regular expression based on the provided query options.
*
* @param queryOptions
* @return True if the query is a regular expression.
*/
const getIsRegex =
(queryOptions: QUERY_OPTION[]) => queryOptions.includes(QUERY_OPTION.IS_REGEX);

/**
* Displays a panel for submitting queries and viewing query results.
*
Expand All @@ -65,17 +41,18 @@ const getIsRegex =
const SearchTabPanel = () => {
const {queryProgress, queryResults, startQuery, uiState} = useContext(StateContext);
const [isAllExpanded, setIsAllExpanded] = useState<boolean>(true);
const [queryOptions, setQueryOptions] = useState<QUERY_OPTION[]>([]);
const [queryString, setQueryString] = useState<string>("");
const [isCaseSensitive, setIsCaseSensitive] = useState<boolean>(false);
const [isRegex, setIsRegex] = useState<boolean>(false);

const handleCollapseAllButtonClick = () => {
setIsAllExpanded((v) => !v);
};

const handleQuerySubmit = (newArgs: Partial<QueryArgs>) => {
startQuery({
isCaseSensitive: getIsCaseSensitive(queryOptions),
isRegex: getIsRegex(queryOptions),
isCaseSensitive: isCaseSensitive,
isRegex: isRegex,
queryString: queryString,
...newArgs,
});
Expand All @@ -86,15 +63,14 @@ const SearchTabPanel = () => {
handleQuerySubmit({queryString: ev.target.value});
};

const handleQueryOptionsChange = (
_: React.MouseEvent<HTMLElement>,
newOptions: QUERY_OPTION[]
) => {
setQueryOptions(newOptions);
handleQuerySubmit({
isCaseSensitive: getIsCaseSensitive(newOptions),
isRegex: getIsRegex(newOptions),
});
const handleCaseSensitivityButtonClick = () => {
handleQuerySubmit({isCaseSensitive: !isCaseSensitive});
setIsCaseSensitive(!isCaseSensitive);
};

const handleRegexButtonClick = () => {
handleQuerySubmit({isRegex: !isRegex});
setIsRegex(!isRegex);
};

const isQueryInputBoxDisabled = isDisabled(uiState, UI_ELEMENT.QUERY_INPUT_BOX);
Expand Down Expand Up @@ -124,36 +100,34 @@ const SearchTabPanel = () => {
placeholder={"Search"}
size={"sm"}
endDecorator={
<ToggleButtonGroup
disabled={isQueryInputBoxDisabled}
size={"sm"}
<Stack
direction={"row"}
spacing={0.25}
value={queryOptions}
variant={"plain"}
onChange={handleQueryOptionsChange}
>
<Tooltip title={"Match case"}>
<span>
<IconButton
className={"query-option-button"}
value={QUERY_OPTION.IS_CASE_SENSITIVE}
>
Aa
</IconButton>
</span>
</Tooltip>

<Tooltip title={"Use regular expression"}>
<span>
<IconButton
className={"query-option-button"}
value={QUERY_OPTION.IS_REGEX}
>
.*
</IconButton>
</span>
</Tooltip>
</ToggleButtonGroup>
<ToggleIconButton
className={"query-option-button"}
disabled={isQueryInputBoxDisabled}
isChecked={isCaseSensitive}
size={"sm"}
tooltipTitle={"Match case"}
variant={"plain"}
onClick={handleCaseSensitivityButtonClick}
>
Aa
</ToggleIconButton>

<ToggleIconButton
className={"query-option-button"}
disabled={isQueryInputBoxDisabled}
isChecked={isRegex}
size={"sm"}
tooltipTitle={"Use regular expression"}
variant={"plain"}
onClick={handleRegexButtonClick}
>
.*
</ToggleIconButton>
</Stack>
}
slotProps={{
textarea: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from "@mui/joy";

import {NotificationContext} from "../../../../../contexts/NotificationContextProvider";
import {StateContext} from "../../../../../contexts/StateContextProvider";
import {Nullable} from "../../../../../typings/common";
import {
CONFIG_KEY,
Expand All @@ -26,6 +27,7 @@ import {
TAB_DISPLAY_NAMES,
TAB_NAME,
} from "../../../../../typings/tab";
import {ACTION_NAME} from "../../../../../utils/actions";
import {
getConfig,
setConfig,
Expand All @@ -36,11 +38,17 @@ import ThemeSwitchFormField from "./ThemeSwitchFormField";
import "./index.css";


const CONFIG_FORM_FIELDS = [
/**
* Gets form fields information for user input of configuration values.
*
* @return A list of form fields information.
*/
const getConfigFormFields = () => [
{
helperText: (
<span>
{"[JSON] Format string for formatting a JSON log event as plain text. See the "}
[JSON] Format string for formatting a JSON log event as plain text. See the
{" "}
<Link
href={"https://docs.yscope.com/yscope-log-viewer/main/user-guide/format-struct-logs-overview.html"}
level={"body-sm"}
Expand All @@ -49,7 +57,8 @@ const CONFIG_FORM_FIELDS = [
>
format string syntax docs
</Link>
{" or leave this blank to display the entire log event."}
{" "}
or leave this blank to display the entire log event.
</span>
),
initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).formatString,
Expand Down Expand Up @@ -98,41 +107,42 @@ const handleConfigFormReset = (ev: React.FormEvent) => {
*/
const SettingsTabPanel = () => {
const {postPopUp} = useContext(NotificationContext);
const {loadPageByAction} = useContext(StateContext);

const handleConfigFormSubmit = useCallback(
(ev: React.FormEvent) => {
ev.preventDefault();
const formData = new FormData(ev.target as HTMLFormElement);
const getFormDataValue = (key: string) => formData.get(key) as string;
const handleConfigFormSubmit = useCallback((ev: React.FormEvent) => {
ev.preventDefault();
const formData = new FormData(ev.target as HTMLFormElement);
const getFormDataValue = (key: string) => formData.get(key) as string;

const formatString = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_FORMAT_STRING);
const logLevelKey = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_LOG_LEVEL_KEY);
const timestampKey = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_KEY);
const pageSize = getFormDataValue(LOCAL_STORAGE_KEY.PAGE_SIZE);
const formatString = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_FORMAT_STRING);
const logLevelKey = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_LOG_LEVEL_KEY);
const timestampKey = getFormDataValue(LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_KEY);
const pageSize = getFormDataValue(LOCAL_STORAGE_KEY.PAGE_SIZE);

let error: Nullable<string> = null;
error ||= setConfig({
key: CONFIG_KEY.DECODER_OPTIONS,
value: {formatString, logLevelKey, timestampKey},
});
error ||= setConfig({
key: CONFIG_KEY.PAGE_SIZE,
value: Number(pageSize),
});
let error: Nullable<string> = null;
error ||= setConfig({
key: CONFIG_KEY.DECODER_OPTIONS,
value: {formatString, logLevelKey, timestampKey},
});
error ||= setConfig({
key: CONFIG_KEY.PAGE_SIZE,
value: Number(pageSize),
});

if (null !== error) {
postPopUp({
level: LOG_LEVEL.ERROR,
message: error,
timeoutMillis: DO_NOT_TIMEOUT_VALUE,
title: "Unable to apply config.",
});
} else {
window.location.reload();
}
},
[postPopUp],
);
if (null !== error) {
postPopUp({
level: LOG_LEVEL.ERROR,
message: error,
timeoutMillis: DO_NOT_TIMEOUT_VALUE,
title: "Unable to apply config.",
});
} else {
loadPageByAction({code: ACTION_NAME.RELOAD, args: null});
}
}, [
loadPageByAction,
postPopUp,
]);

return (
<CustomTabPanel
Expand All @@ -147,7 +157,7 @@ const SettingsTabPanel = () => {
>
<Box className={"settings-form-fields-container"}>
<ThemeSwitchFormField/>
{CONFIG_FORM_FIELDS.map((field, index) => (
{getConfigFormFields().map((field, index) => (
<FormControl key={index}>
<FormLabel>
{field.label}
Expand All @@ -167,7 +177,7 @@ const SettingsTabPanel = () => {
color={"primary"}
type={"submit"}
>
Apply & Reload
Apply
</Button>
<Button
color={"neutral"}
Expand Down
Loading

0 comments on commit b3e5104

Please sign in to comment.