refactor(react/settings): add names to all form groups

This commit is contained in:
Elian Doran 2025-08-19 23:34:25 +03:00
parent 51291a61e6
commit 1d7799f981
No known key found for this signature in database
29 changed files with 144 additions and 154 deletions

View File

@ -107,7 +107,7 @@ function AddLinkDialogComponent() {
}}
show={shown}
>
<FormGroup label={t("add_link.note")}>
<FormGroup label={t("add_link.note")} name="note">
<NoteAutocomplete
inputRef={autocompleteRef}
onChange={setSuggestion}

View File

@ -64,7 +64,7 @@ function BranchPrefixDialogComponent() {
footer={<Button text={t("branch_prefix.save")} />}
show={shown}
>
<FormGroup label={t("branch_prefix.prefix")}>
<FormGroup label={t("branch_prefix.prefix")} name="prefix">
<div class="input-group">
<input class="branch-prefix-input form-control" value={prefix} ref={branchInput}
onChange={(e) => setPrefix((e.target as HTMLInputElement).value)} />

View File

@ -69,15 +69,15 @@ function CloneToDialogComponent() {
>
<h5>{t("clone_to.notes_to_clone")}</h5>
<NoteList style={{ maxHeight: "200px", overflow: "auto" }} noteIds={clonedNoteIds} />
<FormGroup label={t("clone_to.target_parent_note")}>
<FormGroup name="target-parent-note" label={t("clone_to.target_parent_note")}>
<NoteAutocomplete
placeholder={t("clone_to.search_for_note_by_its_name")}
onChange={setSuggestion}
inputRef={autoCompleteRef}
/>
</FormGroup>
<FormGroup label={t("clone_to.prefix_optional")} title={t("clone_to.cloned_note_prefix_title")}>
<FormTextBox name="clone-prefix" onChange={setPrefix} />
<FormGroup name="clone-prefix" label={t("clone_to.prefix_optional")} title={t("clone_to.cloned_note_prefix_title")}>
<FormTextBox onChange={setPrefix} />
</FormGroup>
</Modal>
)

View File

@ -4,7 +4,7 @@ import tree from "../../services/tree";
import Button from "../react/Button";
import FormCheckbox from "../react/FormCheckbox";
import FormFileUpload from "../react/FormFileUpload";
import FormGroup from "../react/FormGroup";
import FormGroup, { FormMultiGroup } from "../react/FormGroup";
import Modal from "../react/Modal";
import RawHtml from "../react/RawHtml";
import ReactBasicWidget from "../react/ReactBasicWidget";
@ -55,11 +55,11 @@ function ImportDialogComponent() {
footer={<Button text={t("import.import")} primary disabled={!files} />}
show={shown}
>
<FormGroup label={t("import.chooseImportFile")} description={<>{t("import.importDescription")} <strong>{ noteTitle }</strong></>}>
<FormGroup name="files" label={t("import.chooseImportFile")} description={<>{t("import.importDescription")} <strong>{ noteTitle }</strong></>}>
<FormFileUpload multiple onChange={setFiles} />
</FormGroup>
<FormGroup label={t("import.options")}>
<FormMultiGroup label={t("import.options")}>
<FormCheckbox
name="safe-import" hint={t("import.safeImportTooltip")} label={t("import.safeImport")}
currentValue={safeImport} onChange={setSafeImport}
@ -84,7 +84,7 @@ function ImportDialogComponent() {
name="replace-underscores-with-spaces" label={t("import.replaceUnderscoresWithSpaces")}
currentValue={replaceUnderscoresWithSpaces} onChange={setReplaceUnderscoresWithSpaces}
/>
</FormGroup>
</FormMultiGroup>
</Modal>
);
}

View File

@ -43,7 +43,7 @@ function IncludeNoteDialogComponent() {
footer={<Button text={t("include_note.button_include")} keyboardShortcut="Enter" />}
show={shown}
>
<FormGroup label={t("include_note.label_note")}>
<FormGroup name="note" label={t("include_note.label_note")}>
<NoteAutocomplete
placeholder={t("include_note.placeholder_search")}
onChange={setSuggestion}
@ -55,8 +55,9 @@ function IncludeNoteDialogComponent() {
/>
</FormGroup>
<FormGroup label={t("include_note.box_size_prompt")}>
<FormRadioGroup name="include-note-box-size"
<FormGroup name="include-note-box-size" label={t("include_note.box_size_prompt")}>
<FormRadioGroup
name="include-note-box-size"
currentValue={boxSize} onChange={setBoxSize}
values={[
{ label: t("include_note.box_size_small"), value: "small" },

View File

@ -57,7 +57,7 @@ function MoveToDialogComponent() {
<h5>{t("move_to.notes_to_move")}</h5>
<NoteList branchIds={movedBranchIds} />
<FormGroup label={t("move_to.target_parent_note")}>
<FormGroup name="parent-note" label={t("move_to.target_parent_note")}>
<NoteAutocomplete
onChange={setSuggestion}
inputRef={autoCompleteRef}

View File

@ -83,7 +83,7 @@ function NoteTypeChooserDialogComponent() {
show={shown}
stackable
>
<FormGroup label={t("note_type_chooser.change_path_prompt")}>
<FormGroup name="parent-note" label={t("note_type_chooser.change_path_prompt")}>
<NoteAutocomplete
onChange={setParentNote}
placeholder={t("note_type_chooser.search_placeholder")}
@ -95,7 +95,7 @@ function NoteTypeChooserDialogComponent() {
/>
</FormGroup>
<FormGroup label={t("note_type_chooser.modal_body")}>
<FormGroup name="note-type" label={t("note_type_chooser.modal_body")}>
<FormList onSelect={onNoteTypeSelected}>
{noteTypes.map((_item) => {
if (_item.title === "----") {

View File

@ -74,9 +74,8 @@ function PromptDialogComponent() {
show={shown}
stackable
>
<FormGroup label={opts.current?.message} labelRef={labelRef}>
<FormGroup name="prompt-dialog-answer" label={opts.current?.message} labelRef={labelRef}>
<FormTextBox
name="prompt-dialog-answer"
inputRef={answerRef}
currentValue={value} onChange={setValue}
readOnly={opts.current?.readOnly}

View File

@ -83,11 +83,8 @@ function SortChildNotesDialogComponent() {
label={t("sort_child_notes.sort_with_respect_to_different_character_sorting")}
currentValue={sortNatural} onChange={setSortNatural}
/>
<FormGroup className="form-check" label={t("sort_child_notes.natural_sort_language")} description={t("sort_child_notes.the_language_code_for_natural_sort")}>
<FormTextBox
name="sort-locale"
currentValue={sortLocale} onChange={setSortLocale}
/>
<FormGroup name="sort-locale" className="form-check" label={t("sort_child_notes.natural_sort_language")} description={t("sort_child_notes.the_language_code_for_natural_sort")}>
<FormTextBox currentValue={sortLocale} onChange={setSortLocale} />
</FormGroup>
</Modal>
)

View File

@ -51,13 +51,12 @@ function UploadAttachmentsDialogComponent() {
onHidden={() => setShown(false)}
show={shown}
>
<FormGroup label={t("upload_attachments.choose_files")} description={description}>
<FormGroup name="files" label={t("upload_attachments.choose_files")} description={description}>
<FormFileUpload onChange={setFiles} multiple />
</FormGroup>
<FormGroup label={t("upload_attachments.options")}>
<FormGroup name="shrink-images" label={t("upload_attachments.options")}>
<FormCheckbox
name="shrink-images"
hint={t("upload_attachments.tooltip")} label={t("upload_attachments.shrink_images")}
currentValue={shrinkImages} onChange={setShrinkImages}
/>

View File

@ -3,9 +3,11 @@ import { useEffect, useRef, useMemo, useCallback } from "preact/hooks";
import { escapeQuotes } from "../../services/utils";
import { ComponentChildren } from "preact";
import { CSSProperties, memo } from "preact/compat";
import { useUniqueName } from "./hooks";
interface FormCheckboxProps {
id?: string;
name?: string;
label: string | ComponentChildren;
/**
* If set, the checkbox label will be underlined and dotted, indicating a hint. When hovered, it will show the hint text.
@ -17,7 +19,8 @@ interface FormCheckboxProps {
containerStyle?: CSSProperties;
}
const FormCheckbox = memo(({ id, disabled, label, currentValue, onChange, hint, containerStyle }: FormCheckboxProps) => {
const FormCheckbox = memo(({ name, id: _id, disabled, label, currentValue, onChange, hint, containerStyle }: FormCheckboxProps) => {
const id = _id ?? useUniqueName(name);
const labelRef = useRef<HTMLLabelElement>(null);
// Fix: Move useEffect outside conditional

View File

@ -29,3 +29,15 @@ export default function FormGroup({ name, label, title, className, children, des
</div>
);
}
/**
* Similar to {@link FormGroup} but allows more than one child. Due to this behaviour, there is no automatic ID assignment.
*/
export function FormMultiGroup({ label, children }: { label: string, children: ComponentChildren }) {
return (
<div className={`form-group`}>
{label && <label>{label}</label>}
{children}
</div>
);
}

View File

@ -31,9 +31,9 @@ export default function FormRadioGroup({ values, ...restProps }: FormRadioProps)
export function FormInlineRadioGroup({ values, ...restProps }: FormRadioProps) {
return (
<>
<div role="group">
{values.map(({ value, label }) => (<FormRadio value={value} label={label} {...restProps} />))}
</>
</div>
)
}

View File

@ -6,6 +6,7 @@ import type { RefObject } from "preact";
import type { CSSProperties } from "preact/compat";
interface NoteAutocompleteProps {
id?: string;
inputRef?: RefObject<HTMLInputElement>;
text?: string;
placeholder?: string;
@ -18,7 +19,7 @@ interface NoteAutocompleteProps {
noteId?: string;
}
export default function NoteAutocomplete({ inputRef: _ref, text, placeholder, onChange, onTextChange, container, containerStyle, opts, noteId, noteIdChanged }: NoteAutocompleteProps) {
export default function NoteAutocomplete({ id, inputRef: _ref, text, placeholder, onChange, onTextChange, container, containerStyle, opts, noteId, noteIdChanged }: NoteAutocompleteProps) {
const ref = _ref ?? useRef<HTMLInputElement>(null);
useEffect(() => {
@ -74,6 +75,7 @@ export default function NoteAutocomplete({ inputRef: _ref, text, placeholder, on
return (
<div className="input-group" style={containerStyle}>
<input
id={id}
ref={ref}
className="note-autocomplete form-control"
placeholder={placeholder ?? t("add_link.search_note")} />

View File

@ -190,6 +190,6 @@ export function useTriliumOptions<T extends OptionNames>(...names: T[]) {
* @param prefix a prefix to add to the unique name.
* @returns a name with the given prefix and a random alpanumeric string appended to it.
*/
export function useUniqueName(prefix: string) {
return useMemo(() => prefix + "-" + utils.randomString(10), [ prefix]);
export function useUniqueName(prefix?: string) {
return useMemo(() => (prefix ? prefix + "-" : "") + utils.randomString(10), [ prefix ]);
}

View File

@ -28,9 +28,8 @@ function EnableAiSettings() {
return (
<>
<OptionsSection title={t("ai_llm.title")}>
<FormGroup description={t("ai_llm.enable_ai_description")}>
<FormGroup name="ai-enabled" description={t("ai_llm.enable_ai_description")}>
<FormCheckbox
name="ai-enabled"
label={t("ai_llm.enable_ai_features")}
currentValue={aiEnabled} onChange={(isEnabled) => {
if (isEnabled) {
@ -56,7 +55,7 @@ function ProviderSettings() {
return (
<OptionsSection title={t("ai_llm.provider_configuration")}>
<FormGroup label={t("ai_llm.selected_provider")} description={t("ai_llm.selected_provider_description")}>
<FormGroup name="selected-provider" label={t("ai_llm.selected_provider")} description={t("ai_llm.selected_provider_description")}>
<FormSelect
values={[
{ value: "", text: t("ai_llm.select_provider") },
@ -103,15 +102,14 @@ function ProviderSettings() {
<></>
}
<FormGroup label={t("ai_llm.temperature")} description={t("ai_llm.temperature_description")}>
<FormGroup name="ai-temperature" label={t("ai_llm.temperature")} description={t("ai_llm.temperature_description")}>
<FormTextBox
name="ai-temperature"
type="number" min="0" max="2" step="0.1"
currentValue={aiTemperature} onChange={setAiTemperature}
/>
</FormGroup>
<FormGroup label={t("ai_llm.system_prompt")} description={t("ai_llm.system_prompt_description")}>
<FormGroup name="system-prompt" label={t("ai_llm.system_prompt")} description={t("ai_llm.system_prompt_description")}>
<FormTextArea
rows={3}
currentValue={aiSystemPrompt} onBlur={setAiSystemPrompt}
@ -149,7 +147,7 @@ function SingleProviderSettings({ provider, title, apiKeyDescription, baseUrlDes
{!isValid && <Admonition type="caution">{validationErrorMessage}</Admonition> }
{apiKeyOption && (
<FormGroup label={t("ai_llm.api_key")} description={apiKeyDescription}>
<FormGroup name="api-key" label={t("ai_llm.api_key")} description={apiKeyDescription}>
<FormTextBox
type="password" autoComplete="off"
currentValue={apiKey} onChange={setApiKey}
@ -157,14 +155,14 @@ function SingleProviderSettings({ provider, title, apiKeyDescription, baseUrlDes
</FormGroup>
)}
<FormGroup label={t("ai_llm.url")} description={baseUrlDescription}>
<FormGroup name="base-url" label={t("ai_llm.url")} description={baseUrlDescription}>
<FormTextBox
currentValue={baseUrl ?? "https://api.openai.com/v1"} onChange={setBaseUrl}
/>
</FormGroup>
{isValid &&
<FormGroup label={t("ai_llm.model")} description={modelDescription}>
<FormGroup name="model" label={t("ai_llm.model")} description={modelDescription}>
<ModelSelector provider={provider} baseUrl={baseUrl} modelOption={modelOption} />
</FormGroup>
}

View File

@ -189,7 +189,7 @@ function Font({ title, fontFamilyOption, fontSizeOption }: { title: string, font
<>
<h5>{title}</h5>
<div className="row">
<FormGroup className="col-md-4" label={t("fonts.font_family")}>
<FormGroup name="font-family" className="col-md-4" label={t("fonts.font_family")}>
<FormSelectWithGroups
values={FONT_FAMILIES}
currentValue={fontFamily} onChange={setFontFamily}
@ -197,7 +197,7 @@ function Font({ title, fontFamilyOption, fontSizeOption }: { title: string, font
/>
</FormGroup>
<FormGroup className="col-md-6" label={t("fonts.size")}>
<FormGroup name="font-size" className="col-md-6" label={t("fonts.size")}>
<FormTextBoxWithUnit
name="tree-font-size"
type="number" min={50} max={200} step={10}
@ -217,7 +217,7 @@ function ElectronIntegration() {
return (
<OptionsSection title={t("electron_integration.desktop-application")}>
<FormGroup label={t("electron_integration.zoom-factor")} description={t("zoom_factor.description")}>
<FormGroup name="zoom-factor" label={t("electron_integration.zoom-factor")} description={t("zoom_factor.description")}>
<FormTextBox
type="number"
min="0.3" max="2.0" step="0.1"
@ -226,16 +226,16 @@ function ElectronIntegration() {
</FormGroup>
<hr/>
<FormGroup description={t("electron_integration.native-title-bar-description")}>
<FormGroup name="native-title-bar" description={t("electron_integration.native-title-bar-description")}>
<FormCheckbox
name="native-title-bar" label={t("electron_integration.native-title-bar")}
label={t("electron_integration.native-title-bar")}
currentValue={nativeTitleBarVisible} onChange={setNativeTitleBarVisible}
/>
</FormGroup>
<FormGroup description={t("electron_integration.background-effects-description")}>
<FormGroup name="background-effects" description={t("electron_integration.background-effects-description")}>
<FormCheckbox
name="background-effects" label={t("electron_integration.background-effects")}
label={t("electron_integration.background-effects")}
currentValue={backgroundEffects} onChange={setBackgroundEffects}
/>
</FormGroup>
@ -253,9 +253,8 @@ function MaxContentWidth() {
<FormText>{t("max_content_width.default_description")}</FormText>
<Column md={6}>
<FormGroup label={t("max_content_width.max_width_label")}>
<FormGroup name="max-content-width" label={t("max_content_width.max_width_label")}>
<FormTextBoxWithUnit
name="max-content-width"
type="number" min={MIN_CONTENT_WIDTH} step="10"
currentValue={maxContentWidth} onChange={setMaxContentWidth}
unit={t("max_content_width.max_width_unit")}

View File

@ -4,7 +4,7 @@ import server from "../../../services/server";
import toast from "../../../services/toast";
import Button from "../../react/Button";
import FormCheckbox from "../../react/FormCheckbox";
import FormGroup from "../../react/FormGroup";
import FormGroup, { FormMultiGroup } from "../../react/FormGroup";
import FormText from "../../react/FormText";
import { useTriliumOptionBool } from "../../react/hooks";
import OptionsSection from "./components/OptionsSection";
@ -45,7 +45,7 @@ export function AutomaticBackup() {
return (
<OptionsSection title={t("backup.automatic_backup")}>
<FormGroup label={t("backup.automatic_backup_description")}>
<FormMultiGroup label={t("backup.automatic_backup_description")}>
<FormCheckbox
name="daily-backup-enabled"
label={t("backup.enable_daily_backup")}
@ -63,7 +63,7 @@ export function AutomaticBackup() {
label={t("backup.enable_monthly_backup")}
currentValue={monthlyBackupEnabled} onChange={setMonthlyBackupEnabled}
/>
</FormGroup>
</FormMultiGroup>
<FormText>{t("backup.backup_recommendation")}</FormText>
</OptionsSection>

View File

@ -32,9 +32,8 @@ function Editor() {
return (
<OptionsSection title={t("code-editor-options.title")}>
<FormGroup description={t("vim_key_bindings.enable_vim_keybindings")}>
<FormGroup name="vim-keymap-enabled" description={t("vim_key_bindings.enable_vim_keybindings")}>
<FormCheckbox
name="vim-keymap-enabled"
label={t("vim_key_bindings.use_vim_keybindings_in_code_notes")}
currentValue={vimKeymapEnabled} onChange={setVimKeymapEnabled}
/>
@ -57,7 +56,7 @@ function Appearance() {
return (
<OptionsSection title={t("code_theme.title")}>
<div className="row" style={{ marginBottom: "15px" }}>
<FormGroup label={t("code_theme.color-scheme")} className="col-md-6" style={{ marginBottom: 0 }}>
<FormGroup name="color-scheme" label={t("code_theme.color-scheme")} className="col-md-6" style={{ marginBottom: 0 }}>
<FormSelect
values={themes}
keyProperty="id" titleProperty="name"

View File

@ -18,9 +18,8 @@ export default function AutoReadOnlySize({ label, option }: AutoReadOnlySizeProp
<OptionsSection title={t("text_auto_read_only_size.title")}>
<FormText>{t("text_auto_read_only_size.description")}</FormText>
<FormGroup label={label}>
<FormGroup name="auto-readonly-size-text" label={label}>
<FormTextBoxWithUnit
name="auto-readonly-size-text"
type="number" min={0}
unit={t("text_auto_read_only_size.unit")}
currentValue={autoReadonlyOpt} onChange={setAutoReadonlyOpt}

View File

@ -36,11 +36,11 @@ function LocalizationOptions() {
return (
<OptionsSection title={t("i18n.title")}>
<OptionsRow label={t("i18n.language")}>
<OptionsRow name="language" label={t("i18n.language")}>
<LocaleSelector locales={uiLocales} currentValue={locale} onChange={setLocale} />
</OptionsRow>
{isElectron() && <OptionsRow label={t("i18n.formatting-locale")}>
{isElectron() && <OptionsRow name="formatting-locale" label={t("i18n.formatting-locale")}>
<LocaleSelector locales={contentLocales} currentValue={formattingLocale} onChange={setFormattingLocale} />
</OptionsRow>}
@ -65,8 +65,7 @@ function DateSettings() {
return (
<>
<OptionsRow label={t("i18n.first-day-of-the-week")}>
<div role="group">
<OptionsRow name="first-day-of-week" label={t("i18n.first-day-of-the-week")}>
<FormInlineRadioGroup
name="first-day-of-week"
values={[
@ -75,11 +74,9 @@ function DateSettings() {
]}
currentValue={firstDayOfWeek} onChange={setFirstDayOfWeek}
/>
</div>
</OptionsRow>
<OptionsRow label={t("i18n.first-week-of-the-year")}>
<div role="group">
<OptionsRow name="first-week-of-year" label={t("i18n.first-week-of-the-year")}>
<FormRadioGroup
name="first-week-of-year"
currentValue={firstWeekOfYear} onChange={setFirstWeekOfYear}
@ -89,10 +86,9 @@ function DateSettings() {
{ value: "2", label: t("i18n.first-week-has-minimum-days") }
]}
/>
</div>
</OptionsRow>
{firstWeekOfYear === "2" && <OptionsRow label={t("i18n.min-days-in-first-week")}>
{firstWeekOfYear === "2" && <OptionsRow name="min-days-in-first-week" label={t("i18n.min-days-in-first-week")}>
<FormSelect
keyProperty="days"
currentValue={minDaysInFirstWeek} onChange={setMinDaysInFirstWeek}
@ -109,7 +105,7 @@ function DateSettings() {
{t("i18n.first-week-warning")}
</Admonition>
<OptionsRow centered>
<OptionsRow name="restart" centered>
<Button
text={t("electron_integration.restart-app-button")}
size="micro"

View File

@ -13,9 +13,8 @@ export default function ImageSettings() {
return (
<OptionsSection title={t("images.images_section_title")}>
<FormGroup description={t("images.download_images_description")}>
<FormGroup name="download-images-automatically" description={t("images.download_images_description")}>
<FormCheckbox
name="download-images-automatically"
label={t("images.download_images_automatically")}
currentValue={downloadImagesAutomatically} onChange={setDownloadImagesAutomatically}
/>
@ -29,18 +28,16 @@ export default function ImageSettings() {
currentValue={compressImages} onChange={setCompressImages}
/>
<FormGroup label={t("images.max_image_dimensions")} disabled={!compressImages}>
<FormGroup name="image-max-width-height" label={t("images.max_image_dimensions")} disabled={!compressImages}>
<FormTextBoxWithUnit
name="image-max-width-height"
type="number" min="1"
unit={t("images.max_image_dimensions_unit")}
currentValue={imageMaxWidthHeight} onChange={setImageMaxWidthHeight}
/>
</FormGroup>
<FormGroup label={t("images.jpeg_quality_description")} disabled={!compressImages}>
<FormGroup name="image-jpeg-quality" label={t("images.jpeg_quality_description")} disabled={!compressImages}>
<FormTextBoxWithUnit
name="image-jpeg-quality"
min="10" max="100" type="number"
unit={t("units.percentage")}
currentValue={imageJpegQuality} onChange={setImageJpegQuality}

View File

@ -4,7 +4,6 @@ import FormText from "../../react/FormText"
import OptionsSection from "./components/OptionsSection"
import FormCheckbox from "../../react/FormCheckbox"
import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks"
import FormGroup from "../../react/FormGroup"
import { FormInlineRadioGroup } from "../../react/FormRadioGroup"
import Admonition from "../../react/Admonition"
import { useCallback, useEffect, useMemo, useState } from "preact/hooks"

View File

@ -7,7 +7,7 @@ import FormText from "../../react/FormText";
import OptionsSection from "./components/OptionsSection";
import TimeSelector from "./components/TimeSelector";
import { useMemo } from "preact/hooks";
import { useTriliumOption, useTriliumOptionBool, useTriliumOptionInt, useTriliumOptionJson } from "../../react/hooks";
import { useTriliumOption, useTriliumOptionBool, useTriliumOptionJson } from "../../react/hooks";
import { SANITIZER_DEFAULT_ALLOWED_TAGS } from "@triliumnext/commons";
import FormCheckbox from "../../react/FormCheckbox";
import FormGroup from "../../react/FormGroup";
@ -51,7 +51,7 @@ function SearchEngineSettings() {
<OptionsSection title={t("search_engine.title")}>
<FormText>{t("search_engine.custom_search_engine_info")}</FormText>
<FormGroup label={t("search_engine.predefined_templates_label")}>
<FormGroup name="predefined-search-engine" label={t("search_engine.predefined_templates_label")}>
<FormSelect
values={searchEngines}
currentValue={customSearchEngineUrl}
@ -68,14 +68,14 @@ function SearchEngineSettings() {
/>
</FormGroup>
<FormGroup label={t("search_engine.custom_name_label")}>
<FormGroup name="custom-name" label={t("search_engine.custom_name_label")}>
<FormTextBox
currentValue={customSearchEngineName} onChange={setCustomSearchEngineName}
placeholder={t("search_engine.custom_name_placeholder")}
/>
</FormGroup>
<FormGroup label={t("search_engine.custom_url_label")}>
<FormGroup name="custom-url" label={t("search_engine.custom_url_label")}>
<FormTextBox
currentValue={customSearchEngineUrl} onChange={setCustomSearchEngineUrl}
placeholder={t("search_engine.custom_url_placeholder")}
@ -104,7 +104,7 @@ function NoteErasureTimeout() {
return (
<OptionsSection title={t("note_erasure_timeout.note_erasure_timeout_title")}>
<FormText>{t("note_erasure_timeout.note_erasure_description")}</FormText>
<FormGroup label={t("note_erasure_timeout.erase_notes_after")}>
<FormGroup name="erase-entities-after" label={t("note_erasure_timeout.erase_notes_after")}>
<TimeSelector
name="erase-entities-after"
optionValueId="eraseEntitiesAfterTimeInSeconds" optionTimeScaleId="eraseEntitiesAfterTimeScale"
@ -128,7 +128,7 @@ function AttachmentErasureTimeout() {
return (
<OptionsSection title={t("attachment_erasure_timeout.attachment_erasure_timeout")}>
<FormText>{t("attachment_erasure_timeout.attachment_auto_deletion_description")}</FormText>
<FormGroup label={t("attachment_erasure_timeout.erase_attachments_after")}>
<FormGroup name="erase-unused-attachments-after" label={t("attachment_erasure_timeout.erase_attachments_after")}>
<TimeSelector
name="erase-unused-attachments-after"
optionValueId="eraseUnusedAttachmentsAfterSeconds" optionTimeScaleId="eraseUnusedAttachmentsAfterTimeScale"
@ -157,7 +157,7 @@ function RevisionSnapshotInterval() {
components={{ doc: <a href="https://triliumnext.github.io/Docs/Wiki/note-revisions.html" class="external" />}}
/>
</FormText>
<FormGroup label={t("revisions_snapshot_interval.snapshot_time_interval_label")}>
<FormGroup name="revision-snapshot-time-interval" label={t("revisions_snapshot_interval.snapshot_time_interval_label")}>
<TimeSelector
name="revision-snapshot-time-interval"
optionValueId="revisionSnapshotTimeInterval" optionTimeScaleId="revisionSnapshotTimeIntervalTimeScale"
@ -175,9 +175,8 @@ function RevisionSnapshotLimit() {
<OptionsSection title={t("revisions_snapshot_limit.note_revisions_snapshot_limit_title")}>
<FormText>{t("revisions_snapshot_limit.note_revisions_snapshot_limit_description")}</FormText>
<FormGroup>
<FormGroup name="revision-snapshot-number-limit">
<FormTextBoxWithUnit
name="revision-snapshot-number-limit"
type="number" min={-1}
currentValue={revisionSnapshotNumberLimit}
unit={t("revisions_snapshot_limit.snapshot_number_limit_unit")}
@ -246,9 +245,8 @@ function ShareSettings() {
return (
<OptionsSection title={t("share.title")}>
<FormGroup description={t("share.redirect_bare_domain_description")}>
<FormGroup name="redirectBareDomain" description={t("share.redirect_bare_domain_description")}>
<FormCheckbox
name="redirectBareDomain"
label={t(t("share.redirect_bare_domain"))}
currentValue={redirectBareDomain}
onChange={async value => {
@ -269,9 +267,8 @@ function ShareSettings() {
/>
</FormGroup>
<FormGroup description={t("share.show_login_link_description")}>
<FormGroup name="showLoginInShareTheme" description={t("share.show_login_link_description")}>
<FormCheckbox
name="showLoginInShareTheme"
label={t("share.show_login_link")}
currentValue={showLogInShareTheme} onChange={setShowLogInShareTheme}
/>

View File

@ -72,25 +72,22 @@ function ChangePassword() {
toast.showError(result.message);
}
}}>
<FormGroup label={t("password.old_password")}>
<FormGroup name="old-password" label={t("password.old_password")}>
<FormTextBox
name="old-password"
type="password"
currentValue={oldPassword} onChange={setOldPassword}
/>
</FormGroup>
<FormGroup label={t("password.new_password")}>
<FormGroup name="new-password1" label={t("password.new_password")}>
<FormTextBox
name="new-password1"
type="password"
currentValue={newPassword1} onChange={setNewPassword1}
/>
</FormGroup>
<FormGroup label={t("password.new_password_confirmation")}>
<FormGroup name="new-password2" label={t("password.new_password_confirmation")}>
<FormTextBox
name="new-password2"
type="password"
currentValue={newPassword2} onChange={setNewPassword2}
/>
@ -114,7 +111,7 @@ function ProtectedSessionTimeout() {
<a class="tn-link" href="https://triliumnext.github.io/Docs/Wiki/protected-notes.html" className="external">{t("password.wiki")}</a> {t("password.for_more_info")}
</FormText>
<FormGroup label={t("password.protected_session_timeout_label")}>
<FormGroup name="protected-session-timeout" label={t("password.protected_session_timeout_label")}>
<TimeSelector
name="protected-session-timeout"
optionValueId="protectedSessionTimeout" optionTimeScaleId="protectedSessionTimeoutTimeScale"

View File

@ -81,9 +81,8 @@ export default function ShortcutSettings() {
<RawHtml html={t("shortcuts.electron_documentation")} />
</FormText>
<FormGroup>
<FormGroup name="keyboard-shortcut-filter">
<FormTextBox
name="keyboard-shortcut-filter"
placeholder={t("shortcuts.type_text_to_filter")}
currentValue={filter} onChange={(value) => setFilter(value.toLowerCase())}
/>

View File

@ -39,9 +39,8 @@ function ElectronSpellcheckSettings() {
currentValue={spellCheckEnabled} onChange={setSpellCheckEnabled}
/>
<FormGroup label={t("spellcheck.language_code_label")} description={t("spellcheck.multiple_languages_info")}>
<FormGroup name="spell-check-languages" label={t("spellcheck.language_code_label")} description={t("spellcheck.multiple_languages_info")}>
<FormTextBox
name="spell-check-languages"
placeholder={t("spellcheck.language_code_placeholder")}
currentValue={spellCheckLanguageCode} onChange={setSpellCheckLanguageCode}
/>

View File

@ -37,28 +37,27 @@ export function SyncConfiguration() {
});
e.preventDefault();
}}>
<FormGroup label={t("sync_2.server_address")}>
<FormGroup name="sync-server-host" label={t("sync_2.server_address")}>
<FormTextBox
name="sync-server-host"
placeholder="https://<host>:<port>"
currentValue={syncServerHost.current} onChange={(newValue) => syncServerHost.current = newValue}
/>
</FormGroup>
<FormGroup label={t("sync_2.proxy_label")} description={<>
<FormGroup name="sync-proxy" label={t("sync_2.proxy_label")}
description={<>
<strong>{t("sync_2.note")}:</strong> {t("sync_2.note_description")}<br/>
<RawHtml html={t("sync_2.special_value_description")} /></>}
<RawHtml html={t("sync_2.special_value_description")} />
</>}
>
<FormTextBox
name="sync-proxy"
placeholder="https://<host>:<port>"
currentValue={syncProxy.current} onChange={(newValue) => syncProxy.current = newValue}
/>
</FormGroup>
<FormGroup label={t("sync_2.timeout")}>
<FormGroup name="sync-server-timeout" label={t("sync_2.timeout")}>
<FormTextBoxWithUnit
name="sync-server-timeout"
min={1} max={10000000} type="number"
unit={t("sync_2.timeout_unit")}
currentValue={syncServerTimeout.current} onChange={(newValue) => syncServerTimeout.current = newValue}

View File

@ -154,7 +154,7 @@ function CodeBlockStyle() {
return (
<OptionsSection title={t("highlighting.title")}>
<div className="row" style={{ marginBottom: "15px" }}>
<FormGroup className="col-md-6" label={t("highlighting.color-scheme")} style={{ marginBottom: 0 }}>
<FormGroup name="theme" className="col-md-6" label={t("highlighting.color-scheme")} style={{ marginBottom: 0 }}>
<FormSelectWithGroups
values={themes}
keyProperty="val" titleProperty="title"
@ -244,7 +244,7 @@ function TableOfContent() {
<OptionsSection title={t("table_of_contents.title")}>
<FormText>{t("table_of_contents.description")}</FormText>
<FormGroup>
<FormGroup name="min-toc-headings">
<FormTextBoxWithUnit
type="number"
min={0} max={999999999999999} step={1}
@ -300,21 +300,20 @@ function DateTimeFormatOptions() {
/>
</FormText>
<FormGroup className="row align-items-center">
<FormGroup className="col-md-6" label={t("custom_date_time_format.format_string")}>
<div className="row align-items-center">
<FormGroup name="custom-date-time-format" className="col-md-6" label={t("custom_date_time_format.format_string")}>
<FormTextBox
name="custom-date-time-format"
placeholder="YYYY-MM-DD HH:mm"
currentValue={customDateTimeFormat || "YYYY-MM-DD HH:mm"} onChange={setCustomDateTimeFormat}
/>
</FormGroup>
<FormGroup className="col-md-6" label={t("custom_date_time_format.formatted_time")}>
<div className="formatted-date">
<FormGroup name="formatted-date" className="col-md-6" label={t("custom_date_time_format.formatted_time")}>
<div>
{formatDateTime(new Date(), customDateTimeFormat)}
</div>
</FormGroup>
</FormGroup>
</div>
</OptionsSection>
)
}