Refine settings descriptions

This commit is contained in:
murashit 2026-06-20 12:52:42 +09:00
parent e87035ab04
commit a2c359ea04
5 changed files with 25 additions and 43 deletions

View file

@ -19,19 +19,11 @@ export function ArchivedThreadSection({ state }: { state: ArchivedThreadSectionS
return (
<>
<SettingsGroup className="codex-panel-settings__dynamic-section codex-panel-settings__archived-section">
<SettingsHeading
dynamic
name="Thread archiving"
desc="Choose the default archive behavior and configure saved thread notes. Thread lists offer both archive choices; slash commands use the default."
/>
<SettingsHeading dynamic name="Thread archiving" desc="Set the default archive action and saved-note templates." />
<ArchiveExportSettings state={state} />
</SettingsGroup>
<SettingsGroup className="codex-panel-settings__dynamic-section codex-panel-settings__archived-threads-section">
<SettingsHeading
dynamic
name="Archived threads"
desc="Restore archived threads, or permanently delete archived threads you no longer need."
/>
<SettingsHeading dynamic name="Archived threads" desc="Restore or permanently delete archived Codex threads." />
{state.contentAvailable ? (
<ArchivedThreadList state={state} />
) : !state.loading && state.status ? (
@ -45,10 +37,7 @@ export function ArchivedThreadSection({ state }: { state: ArchivedThreadSectionS
function ArchiveExportSettings({ state }: { state: ArchivedThreadSectionState }): UiNode {
return (
<SettingsItems>
<SettingRow
name="Save note by default"
desc="When on, the default archive action saves a markdown note before archiving. When off, the default archives without saving. If saving fails, the thread stays active. Frontmatter includes title, thread_id, created, and optional tags."
>
<SettingRow name="Save note by default" desc="Save a Markdown note during the default archive action.">
<ToggleControl
checked={state.exportEnabled}
onChange={(checked) => {
@ -56,7 +45,7 @@ function ArchiveExportSettings({ state }: { state: ArchivedThreadSectionState })
}}
/>
</SettingRow>
<SettingRow name="Saved note folder" desc="Vault-relative folder for saved thread notes. The folder is created when needed.">
<SettingRow name="Saved note folder" desc="Vault folder for saved thread notes.">
<TextControl
placeholder="Codex archives"
value={state.exportFolderTemplate}
@ -65,10 +54,7 @@ function ArchiveExportSettings({ state }: { state: ArchivedThreadSectionState })
}}
/>
</SettingRow>
<SettingRow
name="Saved note filename"
desc="Filename template. Variables: {{date}}, {{time}}, {{title}}, {{id}}, {{shortId}}. Existing files get a numeric suffix."
>
<SettingRow name="Saved note filename" desc="Filename template. Supports {{date}}, {{time}}, {{title}}, {{id}}, and {{shortId}}.">
<TextControl
placeholder="{{date}} {{time}} {{title}} {{shortId}}.md"
value={state.exportFilenameTemplate}
@ -77,7 +63,7 @@ function ArchiveExportSettings({ state }: { state: ArchivedThreadSectionState })
}}
/>
</SettingRow>
<SettingRow name="Saved note tags" desc="Comma-separated fixed tags for saved notes. Leave empty to omit tags.">
<SettingRow name="Saved note tags" desc="Tags added to saved notes, separated by commas.">
<TextControl
placeholder="Codex, archive"
value={state.exportTags}

View file

@ -14,7 +14,7 @@ export function HelperSettingsSection({ state }: { state: HelperSettingsState })
<SettingsItems>
<ModelEffortSetting
name="Automatic thread naming"
desc="Choose the model and reasoning effort used to suggest thread names."
desc="Model and effort for generated thread names."
modelValue={state.threadNamingModel}
effortValue={state.threadNamingEffort}
models={state.models}
@ -23,7 +23,7 @@ export function HelperSettingsSection({ state }: { state: HelperSettingsState })
/>
<ModelEffortSetting
name="Selection rewrite"
desc="Choose the model and reasoning effort used by rewrite selection."
desc="Model and effort for rewriting selected note text."
modelValue={state.rewriteSelectionModel}
effortValue={state.rewriteSelectionEffort}
models={state.models}

View file

@ -8,7 +8,7 @@ import { SettingRow, SettingsGroup, SettingsHeading, SettingsItems, SettingsStat
export function HookSection({ state }: { state: HookSectionState }): UiNode {
return (
<SettingsGroup className="codex-panel-settings__dynamic-section codex-panel-settings__hook-section">
<SettingsHeading dynamic name="Hook status" desc="Review discovered hooks, trust changes, and turn hooks on or off." />
<SettingsHeading dynamic name="Hook status" desc="Trust, enable, or disable discovered Codex hooks." />
{state.contentAvailable ? (
<Hooks state={state} />
) : !state.loading && state.status ? (

View file

@ -10,8 +10,7 @@ import type { CodexPanelSettingTabHost } from "./host";
import { HookSection } from "./hook-section";
import type { SettingsSectionsState } from "./section-state";
const SETTINGS_INTRO_TEXT =
"Codex Panel stores only panel preferences. Models, sandboxing, approvals, MCP servers, hooks, and network access still come from Codex config.";
const SETTINGS_INTRO_TEXT = "Codex Panel stores panel preferences only. Runtime settings still come from Codex.";
const SEND_SHORTCUT_LABELS = {
enter: "Enter",
"mod-enter": "Cmd/Ctrl+Enter",
@ -103,7 +102,7 @@ export class CodexPanelSettingTab extends PluginSettingTab {
new Setting(configItems)
.setName("Codex executable")
.setDesc("Path used to start `codex app-server`. Use an absolute path if Obsidian cannot find `codex`.")
.setDesc("Command used to start `codex app-server`; use an absolute path if needed.")
.addText((text) => {
text.setPlaceholder(DEFAULT_CODEX_PATH).setValue(this.plugin.settings.codexPath);
const commitCodexPath = () => {
@ -119,7 +118,7 @@ export class CodexPanelSettingTab extends PluginSettingTab {
});
new Setting(configItems)
.setName("Show chat toolbar")
.setDesc("Show the chat panel toolbar. Slash commands, composer status controls, and the threads view remain available when hidden.")
.setDesc("Show the toolbar above the chat panel.")
.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.showToolbar).onChange(async (value) => {
this.plugin.settings.showToolbar = value;
@ -133,9 +132,7 @@ export class CodexPanelSettingTab extends PluginSettingTab {
const composerItems = createSettingsItems(composerSection);
new Setting(composerItems)
.setName("Send shortcut")
.setDesc(
"Choose how the composer sends messages. Shift+Enter inserts a newline when Enter sends. Obsidian hotkeys may intercept Cmd/Ctrl+Enter.",
)
.setDesc("Pick Enter or Cmd/Ctrl+Enter. Shift+Enter adds a newline when Enter sends.")
.addDropdown((dropdown) => {
dropdown.addOption("enter", SEND_SHORTCUT_LABELS.enter);
dropdown.addOption("mod-enter", SEND_SHORTCUT_LABELS["mod-enter"]);
@ -147,7 +144,7 @@ export class CodexPanelSettingTab extends PluginSettingTab {
});
new Setting(composerItems)
.setName("Scroll thread from composer edges")
.setDesc("When enabled, Up/Ctrl+P on the first composer line and Down/Ctrl+N on the last line scroll the thread.")
.setDesc("Use Up/Ctrl+P and Down/Ctrl+N at composer edges to scroll the thread.")
.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.scrollThreadFromComposerEdges).onChange(async (value) => {
this.plugin.settings.scrollThreadFromComposerEdges = value;

View file

@ -72,7 +72,7 @@ describe("settings tab", () => {
expect(buttonTexts(tab)).not.toContain("Load archive list");
expect(
tab.containerEl.querySelector(".codex-panel-settings__header.setting-item-heading .setting-item-description")?.textContent,
).toContain("Codex Panel stores only panel preferences");
).toContain("Codex Panel stores panel preferences only");
expect(tab.containerEl.querySelector(".codex-panel-settings__header button")?.getAttribute("data-icon")).toBe("refresh-cw");
expect(tab.containerEl.querySelector("h2")).toBeNull();
expect(tab.containerEl.querySelector(".codex-panel-settings__general-section.setting-group > .setting-items")?.children).toHaveLength(
@ -85,14 +85,14 @@ describe("settings tab", () => {
expect(
tab.containerEl.querySelector(".codex-panel-settings__archived-section > .setting-item-heading .setting-item-description")
?.textContent,
).toContain("Choose the default archive behavior");
).toContain("Set the default archive action");
expect(
tab.containerEl.querySelector(".codex-panel-settings__archived-threads-section > .setting-item-heading .setting-item-description")
?.textContent,
).toContain("Restore archived threads");
).toContain("Restore or permanently delete");
expect(
tab.containerEl.querySelector(".codex-panel-settings__hook-section > .setting-item-heading .setting-item-description")?.textContent,
).toContain("Review discovered hooks");
).toContain("Trust, enable, or disable");
expect(
tab.containerEl.querySelector(
".codex-panel-settings__archived-section.setting-group > .setting-items:not(.codex-panel-settings__dynamic-list)",
@ -117,7 +117,7 @@ describe("settings tab", () => {
]);
});
it("saves the send shortcut setting and warns about Obsidian hotkeys", async () => {
it("saves the send shortcut setting and describes newline behavior", async () => {
const saveSettings = vi.fn().mockResolvedValue(undefined);
const tab = newSettingsTab({ saveSettings });
@ -131,8 +131,8 @@ describe("settings tab", () => {
await flushPromises();
expect(saveSettings).toHaveBeenCalledOnce();
expect(settingDesc(tab, "Send shortcut")).toContain("Obsidian hotkeys");
expect(tab.containerEl.querySelector(".codex-panel-settings__section-status")?.textContent ?? "").not.toContain("Obsidian hotkeys");
expect(settingDesc(tab, "Send shortcut")).toContain("Shift+Enter adds a newline");
expect(tab.containerEl.querySelector(".codex-panel-settings__section-status")?.textContent ?? "").not.toContain("Shift+Enter");
});
it("saves the toolbar visibility setting and refreshes open panels", async () => {
@ -150,7 +150,7 @@ describe("settings tab", () => {
expect(saveSettings).toHaveBeenCalledOnce();
expect(refreshOpenViews).toHaveBeenCalledOnce();
expect(settingDesc(tab, "Show chat toolbar")).toContain("Slash commands");
expect(settingDesc(tab, "Show chat toolbar")).toContain("toolbar above the chat panel");
});
it("saves the composer edge scroll setting", async () => {
@ -198,10 +198,9 @@ describe("settings tab", () => {
await flushPromises();
expect(saveSettings).toHaveBeenCalledTimes(4);
expect(tab.containerEl.textContent).toContain("title, thread_id, created, and optional tags");
expect(settingDesc(tab, "Save note by default")).toContain("default archive action");
expect(settingDesc(tab, "Save note by default")).toContain("If saving fails");
expect(settingDesc(tab, "Saved note tags")).toContain("Leave empty to omit tags");
expect(settingDesc(tab, "Saved note filename")).toContain("{{shortId}}");
expect(settingDesc(tab, "Saved note tags")).toContain("separated by commas");
});
it("refreshes models, hooks, and archived threads from the global refresh button", async () => {
@ -730,7 +729,7 @@ describe("settings tab", () => {
tab.display();
await flushPromises();
expect(tab.containerEl.textContent).toContain("Restore archived threads, or permanently delete archived threads you no longer need.");
expect(tab.containerEl.textContent).toContain("Restore or permanently delete archived Codex threads.");
expect(tab.containerEl.textContent).not.toContain("Loaded 1 hook from Codex app server.");
expect(tab.containerEl.textContent).not.toContain("Loaded 1 archived thread from Codex app server.");
expect(tab.containerEl.querySelector(".codex-panel-settings__hook-section .setting-item-heading")?.textContent).toContain(