diff --git a/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormField.tsx b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormField.tsx
new file mode 100644
index 000000000..3384a69e8
--- /dev/null
+++ b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormField.tsx
@@ -0,0 +1,58 @@
+import React from "react";
+
+import {
+ FormControl,
+ FormHelperText,
+ FormLabel,
+ Input,
+ Textarea,
+} from "@mui/joy";
+
+
+interface SettingsFormFieldProps {
+ configKey: string;
+ helperText: string | React.ReactNode;
+ initialValue: string | number;
+ label: string;
+ type: string;
+}
+
+/**
+ * Displays a form field for user input of configuration values.
+ *
+ * @param props
+ * @param props.configKey
+ * @param props.helperText
+ * @param props.initialValue
+ * @param props.label
+ * @param props.type
+ * @return
+ */
+const SettingsFormField = ({
+ configKey,
+ helperText,
+ initialValue,
+ label,
+ type,
+}: SettingsFormFieldProps) => (
+
+
+ {label}
+
+ {"number" === type ?
+ :
+
+);
+
+
+export type {SettingsFormFieldProps};
+export default SettingsFormField;
diff --git a/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldSectionsGroup.css b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldSectionsGroup.css
new file mode 100644
index 000000000..88b09f8fd
--- /dev/null
+++ b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldSectionsGroup.css
@@ -0,0 +1,11 @@
+.settings-form-field-sections-group-container {
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ gap: 0.75rem;
+}
+
+.settings-form-field-sections-group {
+ gap: 0.5rem;
+}
diff --git a/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldSectionsGroup.tsx b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldSectionsGroup.tsx
new file mode 100644
index 000000000..eb0921047
--- /dev/null
+++ b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldSectionsGroup.tsx
@@ -0,0 +1,112 @@
+import React from "react";
+
+import {
+ AccordionGroup,
+ Box,
+ Link,
+} from "@mui/joy";
+
+import {
+ CONFIG_KEY,
+ LOCAL_STORAGE_KEY,
+} from "../../../../../typings/config";
+import {getConfig} from "../../../../../utils/config";
+import {SettingsFormFieldProps} from "./SettingsFormField";
+import SettingsFormFieldsSection from "./SettingsFormFieldsSection";
+import ThemeSwitchFormField from "./ThemeSwitchFormField";
+
+import "./SettingsFormFieldSectionsGroup.css";
+
+
+type SettingsFormFields = SettingsFormFieldProps | React.ReactNode;
+
+/**
+ * Gets form fields information for user input of configuration values.
+ *
+ * @return A list of form fields information or React nodes.
+ */
+const getConfigFormFieldSections = (): Array<{
+ name: string;
+ fields: SettingsFormFields[];
+}> => [
+ {
+ name: "Common",
+ fields: [
+ ,
+ {
+ configKey: LOCAL_STORAGE_KEY.PAGE_SIZE,
+ helperText: "Number of log messages to display per page.",
+ initialValue: getConfig(CONFIG_KEY.PAGE_SIZE),
+ label: "View: Page size",
+ type: "number",
+ },
+ ],
+ },
+ {
+ name: "KV-Pairs IR / JSON",
+ fields: [
+ {
+ configKey: LOCAL_STORAGE_KEY.DECODER_OPTIONS_FORMAT_STRING,
+ helperText: (
+
+ Format string for formatting a JSON log event as plain text. See the
+ {" "}
+
+ format string syntax docs
+
+ {" "}
+ or leave this blank to display the entire log event.
+
+ ),
+ initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).formatString,
+ label: "Decoder: Format string",
+ type: "text",
+ },
+ {
+ configKey: LOCAL_STORAGE_KEY.DECODER_OPTIONS_LOG_LEVEL_KEY,
+ helperText: "Key to extract the log level from.",
+ initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).logLevelKey,
+ label: "Decoder: Log level key",
+ type: "text",
+ },
+ {
+ configKey: LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_KEY,
+ helperText: "Key to extract the log timestamp from.",
+ initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).timestampKey,
+ label: "Decoder: Timestamp key",
+ type: "text",
+ },
+ ],
+ },
+];
+
+/**
+ * Displays a group of form fields for user input of configuration values.
+ *
+ * @return
+ */
+const SettingsFormFieldSectionsGroup = () => (
+
+
+ {getConfigFormFieldSections().map(
+ ({name, fields}) => (
+
+ )
+ )}
+
+
+);
+
+export type {SettingsFormFields};
+export default SettingsFormFieldSectionsGroup;
diff --git a/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldsSection.css b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldsSection.css
new file mode 100644
index 000000000..59405f8e0
--- /dev/null
+++ b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldsSection.css
@@ -0,0 +1,3 @@
+.settings-form-field-section-summary {
+ font-weight: 700 !important;
+}
diff --git a/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldsSection.tsx b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldsSection.tsx
new file mode 100644
index 000000000..6ccd6c7f9
--- /dev/null
+++ b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/SettingsFormFieldsSection.tsx
@@ -0,0 +1,54 @@
+import React from "react";
+
+import {
+ Accordion,
+ AccordionDetails,
+ AccordionSummary,
+} from "@mui/joy";
+
+import SettingsFormField, {SettingsFormFieldProps} from "./SettingsFormField";
+import {SettingsFormFields} from "./SettingsFormFieldSectionsGroup";
+
+import "./SettingsFormFieldsSection.css";
+
+
+interface SettingsFormFieldsSectionProps {
+ name: string;
+ fields: SettingsFormFields[];
+}
+
+/**
+ * Displays a section of form fields for user input of configuration values.
+ *
+ * @param props
+ * @param props.fields A list of form fields information or React nodes.
+ * @param props.name
+ * @return
+ */
+const SettingsFormFieldsSection = ({
+ fields,
+ name,
+}: SettingsFormFieldsSectionProps) => (
+
+
+ {name}
+
+
+ {fields.map(
+ (f, index) => (
+ React.isValidElement(f) ?
+ f :
+
+ )
+ )}
+
+
+);
+
+
+export default SettingsFormFieldsSection;
diff --git a/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/index.css b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/index.css
index d117e0ebb..645cff184 100644
--- a/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/index.css
+++ b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/index.css
@@ -6,11 +6,3 @@
height: 100%;
}
-
-.settings-form-fields-container {
- overflow-y: auto;
- display: flex;
- flex-direction: column;
- flex-grow: 1;
- gap: 0.75rem;
-}
diff --git a/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/index.tsx b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/index.tsx
index 139f7d353..7dcafbdda 100644
--- a/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/index.tsx
+++ b/src/components/CentralContainer/Sidebar/SidebarTabs/SettingsTabPanel/index.tsx
@@ -1,15 +1,8 @@
import React, {useCallback} from "react";
import {
- Box,
Button,
Divider,
- FormControl,
- FormHelperText,
- FormLabel,
- Input,
- Link,
- Textarea,
} from "@mui/joy";
import useNotificationStore from "../../../../../stores/notificationStore";
@@ -26,105 +19,13 @@ import {
TAB_NAME,
} from "../../../../../typings/tab";
import {ACTION_NAME} from "../../../../../utils/actions";
-import {
- getConfig,
- setConfig,
-} from "../../../../../utils/config";
+import {setConfig} from "../../../../../utils/config";
import CustomTabPanel from "../CustomTabPanel";
-import ThemeSwitchFormField from "./ThemeSwitchFormField";
+import SettingsFormFieldSectionsGroup from "./SettingsFormFieldSectionsGroup";
import "./index.css";
-/**
- * Gets form fields information for user input of configuration values.
- *
- * @return A list of form fields information.
- */
-const getConfigFormFields = () => [
- {
- helperText: (
-
- [Structured] Format string for formatting a structured log event as plain text.
- Leave blank to display the entire log event. See
- {" "}
-
- here
-
- {" "}
- for syntax.
-
- ),
- initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).formatString,
- key: LOCAL_STORAGE_KEY.DECODER_OPTIONS_FORMAT_STRING,
- label: "Decoder: Format string",
- type: "text",
- },
- {
- helperText: (
-
- [Structured] Key that maps to each log event's log level. See
- {" "}
-
- here
-
- {" "}
- for syntax.
-
- ),
- initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).logLevelKey,
- key: LOCAL_STORAGE_KEY.DECODER_OPTIONS_LOG_LEVEL_KEY,
- label: "Decoder: Log level key",
- type: "text",
- },
- {
- helperText: (
-
- [Structured] Key that maps to each log event's timestamp. See
- {" "}
-
- here
-
- {" "}
- for syntax.
-
- ),
- initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).timestampKey,
- key: LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_KEY,
- label: "Decoder: Timestamp key",
- type: "text",
- },
- {
- helperText: "[Unstructured-IR] Format string for timestamps in Day.js format.",
- initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).timestampFormatString,
- key: LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_FORMAT_STRING,
- label: "Decoder: Timestamp format string",
- type: "text",
- },
- {
- helperText: "Number of log messages to display per page.",
- initialValue: getConfig(CONFIG_KEY.PAGE_SIZE),
- key: LOCAL_STORAGE_KEY.PAGE_SIZE,
- label: "View: Page size",
- type: "number",
- },
-];
-
/**
* Handles the reset event for the configuration form.
*
@@ -191,27 +92,7 @@ const SettingsTabPanel = () => {
onReset={handleConfigFormReset}
onSubmit={handleConfigFormSubmit}
>
-
-
- {getConfigFormFields().map((field, index) => (
-
-
- {field.label}
-
- {"number" === field.type ?
- :
-
- ))}
-
+