Skip to content

fix: use persisted source functions when toggling search tool#9548

Open
Subash-Mohan wants to merge 2 commits intomainfrom
fix-search-state-persistence
Open

fix: use persisted source functions when toggling search tool#9548
Subash-Mohan wants to merge 2 commits intomainfrom
fix-search-state-persistence

Conversation

@Subash-Mohan
Copy link
Contributor

@Subash-Mohan Subash-Mohan commented Mar 23, 2026

Description

  • Fixed search state not persisting to localStorage when toggling the search tool on/off in the
    ActionsPopover
  • Previously, handleToggleTool used setSelectedSources and
    setSelectedSources(configuredSources) directly, which bypassed the localStorage persistence
    layer
  • Now uses enableSources(), baseEnableAllSources(), and baseDisableAllSources() which properly
    persist state to localStorage
    ticket - https://linear.app/onyx-app/issue/ENG-3753/tool-status-saving-is-wrong

How Has This Been Tested?

Tested by enabling the tool, sending the message, and confirming that the internal search tool remains enabled even after refreshing the page.

Additional Options

  • [Optional] Please cherry-pick this PR to the latest release version.
  • [Optional] Override Linear Check

Summary by cubic

Fixes wrong tool status saving (ENG-3753) by persisting the search tool’s enable/disable state and selected sources when toggled in the ActionsPopover, and adds ARIA labels for the toggle and connector buttons to improve accessibility. Replaces direct setSelectedSources with enableSources, baseEnableAllSources, and baseDisableAllSources so state is written to localStorage and survives refresh.

Written for commit d9be78c. Summary will update on new commits.

@Subash-Mohan Subash-Mohan requested a review from a team as a code owner March 23, 2026 13:01
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 23, 2026

Greptile Summary

This PR fixes a localStorage persistence bug (ENG-3753) in ActionsPopover where toggling the internal search tool on/off called setSelectedSources directly, bypassing the useSourcePreferences hook's persistence layer. The fix replaces these calls with enableSources, baseEnableAllSources, and baseDisableAllSources, which write selected sources to localStorage via persistSourcePreferencesState. Aria-labels are also added to the slash button and connector button in ActionLineItem to support the new E2E tests, which verify that source and tool states survive a page reload.

Key changes:

  • handleToggleTool in index.tsx now calls the hook's persistence-aware functions instead of calling setSelectedSources directly
  • ActionLineItem.tsx gains aria-label attributes needed for both accessibility and E2E test selectors
  • New E2E test suite (actions_popover.spec.ts) and utility helpers (tools.ts) cover the toggle + reload persistence flow

Issues found:

  • baseEnableAllSources() is called when re-enabling with no prior sources, but unlike the local enableAllSources wrapper it does not filter by agentAccessibleSources. Sources that the agent lacks access to may be inadvertently enabled in this path.
  • The openSourceManagement test utility hardcodes button[aria-label="Configure Connectors"], which will fail if no connectors exist (label becomes "Add Connectors").
  • The cleanup re-enable step in the "persist across reload" test is in the test body rather than an afterEach, making it fragile if a preceding assertion fails in serial mode.
  • any typing is used for the /api/tool response in beforeAll, which violates the strict-typing standard.

Confidence Score: 3/5

  • The core persistence fix is correct, but re-enabling the search tool with no prior sources may activate sources the agent shouldn't access — needs the agentAccessibleSources filter to be applied.
  • The main bug fix (replacing raw setSelectedSources with hook persistence functions) is logically sound and directly addresses the reported issue. However, baseEnableAllSources skips the agentAccessibleSources filtering that the local wrapper enableAllSources performs, which could expose inaccessible sources in a specific re-enable path. The test infrastructure has reliability concerns (fragile cleanup, hardcoded aria-label selector). These lower confidence from a clean merge.
  • web/src/refresh-components/popovers/ActionsPopover/index.tsx — the baseEnableAllSources() call at line 856 needs the accessibility filter; web/tests/e2e/utils/tools.tsopenSourceManagement selector needs to handle both connector label states.

Important Files Changed

Filename Overview
web/src/refresh-components/popovers/ActionsPopover/index.tsx Core fix replaces setSelectedSources calls with enableSources/baseEnableAllSources/baseDisableAllSources to add localStorage persistence; however, baseEnableAllSources bypasses the agentAccessibleSources filter present in the local enableAllSources wrapper, potentially re-enabling inaccessible sources on toggle-on.
web/src/refresh-components/popovers/ActionsPopover/ActionLineItem.tsx Adds aria-label to the slash (enable/disable) button and the connector navigation button; required by the new E2E tests and improves accessibility.
web/tests/e2e/chat/actions_popover.spec.ts New E2E test suite covering search tool toggle persistence and source preference persistence; cleanup step for disabled-tool state is in the test body (not afterEach), making it fragile if a serial test fails mid-run. Also uses any typing for API response objects.
web/tests/e2e/utils/tools.ts Adds three well-documented utilities (toggleToolDisabled, openSourceManagement, getSourceToggle); openSourceManagement hardcodes "Configure Connectors" aria-label and will fail if called when there are no connectors.

Sequence Diagram

sequenceDiagram
    participant User
    participant ActionsPopover
    participant useSourcePreferences
    participant localStorage

    Note over User,localStorage: Toggle Search Tool OFF
    User->>ActionsPopover: click slash button (handleToggleTool)
    ActionsPopover->>ActionsPopover: store selectedSources in previouslyEnabledSourcesRef
    ActionsPopover->>useSourcePreferences: baseDisableAllSources()
    useSourcePreferences->>ActionsPopover: setSelectedSources([])
    useSourcePreferences->>localStorage: persistSourcePreferencesState([], configuredSources)

    Note over User,localStorage: Toggle Search Tool ON
    User->>ActionsPopover: click slash button (handleToggleTool)
    alt previouslyEnabledSourcesRef.current.length > 0
        ActionsPopover->>useSourcePreferences: enableSources(previous)
        useSourcePreferences->>ActionsPopover: setSelectedSources(previous)
        useSourcePreferences->>localStorage: persistSourcePreferencesState(previous, configuredSources)
    else no previous sources
        ActionsPopover->>useSourcePreferences: baseEnableAllSources()
        useSourcePreferences->>ActionsPopover: setSelectedSources(ALL configuredSources)
        useSourcePreferences->>localStorage: persistSourcePreferencesState(configuredSources, configuredSources)
        Note over ActionsPopover: ⚠️ agentAccessibleSources filter skipped
    end
    ActionsPopover->>ActionsPopover: previouslyEnabledSourcesRef.current = []
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: web/src/refresh-components/popovers/ActionsPopover/index.tsx
Line: 856

Comment:
**`baseEnableAllSources` bypasses `agentAccessibleSources` filter**

When re-enabling the search tool with no previously saved sources, `baseEnableAllSources()` is called. This calls `enableSources(configuredSources)` inside `useSourcePreferences`, where `configuredSources` is all configured sources derived from `availableSources` — without filtering by `agentAccessibleSources`.

The local `enableAllSources` wrapper (defined around line 381) explicitly filters sources by `agentAccessibleSources` before calling `setSelectedSources`. By bypassing the wrapper, sources that the agent doesn't have access to may be re-enabled when the search tool is toggled back on from a "no previous sources" state.

Compare:
- **Wrapper `enableAllSources` (line 381–393):** Filters by `agentAccessibleSources`, then calls `setSelectedSources`.
- **`baseEnableAllSources` (from hook):** Calls `enableSources(configuredSources)` with ALL configured sources, no accessibility filter.

The fix should call the local wrapper `enableAllSources` — but since it uses `setSelectedSources` directly (which was the original bug), that wrapper also needs to be updated to persist via `enableSources`. A cleaner approach would be to update the `enableAllSources` wrapper to delegate to `baseEnableAllSources` while retaining the accessibility filter:

```typescript
const enableAllSources = useCallback(() => {
  const allConfiguredSources = getConfiguredSources(availableSources);
  const accessibleSources = allConfiguredSources.filter(
    (s) =>
      agentAccessibleSources === null ||
      agentAccessibleSources.has(s.uniqueKey)
  );
  enableSources(accessibleSources); // ← persist + set state

  if (internalSearchTool) {
    setForcedToolIds([internalSearchTool.id]);
  }
}, [...]);
```

Then `handleToggleTool` can call `enableAllSources()` (the wrapper) safely.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: web/tests/e2e/chat/actions_popover.spec.ts
Line: 72-76

Comment:
**Avoid `any` type annotation**

Using `any` for the tool response type suppresses TypeScript's type-checking, which is inconsistent with the team's strict typing standards.

Consider defining an inline or shared type, or at minimum using `unknown` with a type assertion:

```suggestion
    allTools.forEach((t: { in_code_tool_id?: string; id: number }) => {
```

**Context Used:** Use explicit type annotations for variables to enh... ([source](https://app.greptile.com/review/custom-context?memory=instruction-4))

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: web/tests/e2e/utils/tools.ts
Line: 64-66

Comment:
**`openSourceManagement` hardcodes `"Configure Connectors"` label — will break when no connectors exist**

The utility always targets `button[aria-label="Configure Connectors"]`, but `ActionLineItem` now conditionally sets the aria-label to either `"Add Connectors"` (when `isSearchToolWithNoConnectors`) or `"Configure Connectors"` (when connectors exist). If called in a test environment where the file connector setup fails (or in a future test that runs before connector creation), the locator will match nothing and the test will fail with an opaque timeout error.

Consider using a combined selector to handle both states, similar to how `toggleToolDisabled` handles the dual-label button:

```suggestion
  await searchOption
    .locator(
      'button[aria-label="Configure Connectors"], button[aria-label="Add Connectors"]'
    )
    .click();
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: web/tests/e2e/chat/actions_popover.spec.ts
Line: 259-261

Comment:
**Cleanup step in test body is fragile when preceding assertions fail**

The "re-enable the tool for cleanup" step at the end of the test body (commented `// Re-enable the tool for cleanup (serial tests follow)`) runs only if all previous assertions pass. If any assertion earlier in this test fails, the search tool remains disabled for the remainder of the suite.

Since the suite is in `serial` mode and all tests share the same browser state, a more reliable pattern is to add an `afterEach` that always re-enables the tool:

```typescript
test.afterEach(async ({ page }) => {
  // Ensure search tool is re-enabled between tests
  await loginAs(page, "admin");
  await page.goto("/app");
  await page.waitForLoadState("networkidle");
  // ... re-enable logic
});
```

Or, scope the disable/re-enable test to its own isolated browser context rather than relying on in-body cleanup.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix: enhance accessibility for tool togg..." | Re-trigger Greptile

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

@github-actions
Copy link
Contributor

🖼️ Visual Regression Report

Project Changed Added Removed Unchanged Report
admin 1 0 0 121 View Report
exclusive 0 0 0 8 ✅ No changes

Copy link
Contributor

@Danelegend Danelegend left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we get some playwright tests. I feel like I saw a previous PR that removed persistence for a reason

@github-actions
Copy link
Contributor

Preview Deployment

Status Preview Commit Updated
https://onyx-preview-j6y2jxqkl-danswer.vercel.app d9be78c 2026-03-24 14:08:28 UTC

enableSources(previous);
} else {
setSelectedSources(configuredSources);
baseEnableAllSources();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 baseEnableAllSources bypasses agentAccessibleSources filter

When re-enabling the search tool with no previously saved sources, baseEnableAllSources() is called. This calls enableSources(configuredSources) inside useSourcePreferences, where configuredSources is all configured sources derived from availableSources — without filtering by agentAccessibleSources.

The local enableAllSources wrapper (defined around line 381) explicitly filters sources by agentAccessibleSources before calling setSelectedSources. By bypassing the wrapper, sources that the agent doesn't have access to may be re-enabled when the search tool is toggled back on from a "no previous sources" state.

Compare:

  • Wrapper enableAllSources (line 381–393): Filters by agentAccessibleSources, then calls setSelectedSources.
  • baseEnableAllSources (from hook): Calls enableSources(configuredSources) with ALL configured sources, no accessibility filter.

The fix should call the local wrapper enableAllSources — but since it uses setSelectedSources directly (which was the original bug), that wrapper also needs to be updated to persist via enableSources. A cleaner approach would be to update the enableAllSources wrapper to delegate to baseEnableAllSources while retaining the accessibility filter:

const enableAllSources = useCallback(() => {
  const allConfiguredSources = getConfiguredSources(availableSources);
  const accessibleSources = allConfiguredSources.filter(
    (s) =>
      agentAccessibleSources === null ||
      agentAccessibleSources.has(s.uniqueKey)
  );
  enableSources(accessibleSources); // ← persist + set state

  if (internalSearchTool) {
    setForcedToolIds([internalSearchTool.id]);
  }
}, [...]);

Then handleToggleTool can call enableAllSources() (the wrapper) safely.

Prompt To Fix With AI
This is a comment left during a code review.
Path: web/src/refresh-components/popovers/ActionsPopover/index.tsx
Line: 856

Comment:
**`baseEnableAllSources` bypasses `agentAccessibleSources` filter**

When re-enabling the search tool with no previously saved sources, `baseEnableAllSources()` is called. This calls `enableSources(configuredSources)` inside `useSourcePreferences`, where `configuredSources` is all configured sources derived from `availableSources` — without filtering by `agentAccessibleSources`.

The local `enableAllSources` wrapper (defined around line 381) explicitly filters sources by `agentAccessibleSources` before calling `setSelectedSources`. By bypassing the wrapper, sources that the agent doesn't have access to may be re-enabled when the search tool is toggled back on from a "no previous sources" state.

Compare:
- **Wrapper `enableAllSources` (line 381–393):** Filters by `agentAccessibleSources`, then calls `setSelectedSources`.
- **`baseEnableAllSources` (from hook):** Calls `enableSources(configuredSources)` with ALL configured sources, no accessibility filter.

The fix should call the local wrapper `enableAllSources` — but since it uses `setSelectedSources` directly (which was the original bug), that wrapper also needs to be updated to persist via `enableSources`. A cleaner approach would be to update the `enableAllSources` wrapper to delegate to `baseEnableAllSources` while retaining the accessibility filter:

```typescript
const enableAllSources = useCallback(() => {
  const allConfiguredSources = getConfiguredSources(availableSources);
  const accessibleSources = allConfiguredSources.filter(
    (s) =>
      agentAccessibleSources === null ||
      agentAccessibleSources.has(s.uniqueKey)
  );
  enableSources(accessibleSources); // ← persist + set state

  if (internalSearchTool) {
    setForcedToolIds([internalSearchTool.id]);
  }
}, [...]);
```

Then `handleToggleTool` can call `enableAllSources()` (the wrapper) safely.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +72 to +76
new Set([...(currentConfig.tool_ids || []), ...desiredToolIds])
);

await page.request.patch("/api/admin/default-assistant", {
data: { tool_ids: uniqueToolIds },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Avoid any type annotation

Using any for the tool response type suppresses TypeScript's type-checking, which is inconsistent with the team's strict typing standards.

Consider defining an inline or shared type, or at minimum using unknown with a type assertion:

Suggested change
new Set([...(currentConfig.tool_ids || []), ...desiredToolIds])
);
await page.request.patch("/api/admin/default-assistant", {
data: { tool_ids: uniqueToolIds },
allTools.forEach((t: { in_code_tool_id?: string; id: number }) => {

Context Used: Use explicit type annotations for variables to enh... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: web/tests/e2e/chat/actions_popover.spec.ts
Line: 72-76

Comment:
**Avoid `any` type annotation**

Using `any` for the tool response type suppresses TypeScript's type-checking, which is inconsistent with the team's strict typing standards.

Consider defining an inline or shared type, or at minimum using `unknown` with a type assertion:

```suggestion
    allTools.forEach((t: { in_code_tool_id?: string; id: number }) => {
```

**Context Used:** Use explicit type annotations for variables to enh... ([source](https://app.greptile.com/review/custom-context?memory=instruction-4))

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +64 to +66
await searchOption
.locator('button[aria-label="Configure Connectors"]')
.click();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 openSourceManagement hardcodes "Configure Connectors" label — will break when no connectors exist

The utility always targets button[aria-label="Configure Connectors"], but ActionLineItem now conditionally sets the aria-label to either "Add Connectors" (when isSearchToolWithNoConnectors) or "Configure Connectors" (when connectors exist). If called in a test environment where the file connector setup fails (or in a future test that runs before connector creation), the locator will match nothing and the test will fail with an opaque timeout error.

Consider using a combined selector to handle both states, similar to how toggleToolDisabled handles the dual-label button:

Suggested change
await searchOption
.locator('button[aria-label="Configure Connectors"]')
.click();
await searchOption
.locator(
'button[aria-label="Configure Connectors"], button[aria-label="Add Connectors"]'
)
.click();
Prompt To Fix With AI
This is a comment left during a code review.
Path: web/tests/e2e/utils/tools.ts
Line: 64-66

Comment:
**`openSourceManagement` hardcodes `"Configure Connectors"` label — will break when no connectors exist**

The utility always targets `button[aria-label="Configure Connectors"]`, but `ActionLineItem` now conditionally sets the aria-label to either `"Add Connectors"` (when `isSearchToolWithNoConnectors`) or `"Configure Connectors"` (when connectors exist). If called in a test environment where the file connector setup fails (or in a future test that runs before connector creation), the locator will match nothing and the test will fail with an opaque timeout error.

Consider using a combined selector to handle both states, similar to how `toggleToolDisabled` handles the dual-label button:

```suggestion
  await searchOption
    .locator(
      'button[aria-label="Configure Connectors"], button[aria-label="Add Connectors"]'
    )
    .click();
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +259 to +261
const slashButton = searchOption.locator(
'button[aria-label="Disable"], button[aria-label="Enable"]'
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Cleanup step in test body is fragile when preceding assertions fail

The "re-enable the tool for cleanup" step at the end of the test body (commented // Re-enable the tool for cleanup (serial tests follow)) runs only if all previous assertions pass. If any assertion earlier in this test fails, the search tool remains disabled for the remainder of the suite.

Since the suite is in serial mode and all tests share the same browser state, a more reliable pattern is to add an afterEach that always re-enables the tool:

test.afterEach(async ({ page }) => {
  // Ensure search tool is re-enabled between tests
  await loginAs(page, "admin");
  await page.goto("/app");
  await page.waitForLoadState("networkidle");
  // ... re-enable logic
});

Or, scope the disable/re-enable test to its own isolated browser context rather than relying on in-body cleanup.

Prompt To Fix With AI
This is a comment left during a code review.
Path: web/tests/e2e/chat/actions_popover.spec.ts
Line: 259-261

Comment:
**Cleanup step in test body is fragile when preceding assertions fail**

The "re-enable the tool for cleanup" step at the end of the test body (commented `// Re-enable the tool for cleanup (serial tests follow)`) runs only if all previous assertions pass. If any assertion earlier in this test fails, the search tool remains disabled for the remainder of the suite.

Since the suite is in `serial` mode and all tests share the same browser state, a more reliable pattern is to add an `afterEach` that always re-enables the tool:

```typescript
test.afterEach(async ({ page }) => {
  // Ensure search tool is re-enabled between tests
  await loginAs(page, "admin");
  await page.goto("/app");
  await page.waitForLoadState("networkidle");
  // ... re-enable logic
});
```

Or, scope the disable/re-enable test to its own isolated browser context rather than relying on in-body cleanup.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="web/tests/e2e/chat/actions_popover.spec.ts">

<violation number="1" location="web/tests/e2e/chat/actions_popover.spec.ts:146">
P1: Custom agent: **No debugging code**

Remove the direct debug `console.log`/`console.warn` statements from this test file before merge; they are temporary debugging output and violate the no-debugging-code rule.</violation>

<violation number="2" location="web/tests/e2e/chat/actions_popover.spec.ts:223">
P1: Wait for the tool-preference PATCH response before reloading or asserting persisted toggle state; otherwise this test can race the async save and become flaky.

(Based on your team's feedback about pre-creating waitForResponse before trigger clicks in Playwright tests.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

await expect(page.locator(TOOL_IDS.searchOption)).toBeVisible();

// Disable the search tool
await toggleToolDisabled(page, TOOL_IDS.searchOption);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Wait for the tool-preference PATCH response before reloading or asserting persisted toggle state; otherwise this test can race the async save and become flaky.

(Based on your team's feedback about pre-creating waitForResponse before trigger clicks in Playwright tests.)

View Feedback: 1 2

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/tests/e2e/chat/actions_popover.spec.ts, line 223:

<comment>Wait for the tool-preference PATCH response before reloading or asserting persisted toggle state; otherwise this test can race the async save and become flaky.

(Based on your team's feedback about pre-creating waitForResponse before trigger clicks in Playwright tests.) </comment>

<file context>
@@ -0,0 +1,303 @@
+    await expect(page.locator(TOOL_IDS.searchOption)).toBeVisible();
+
+    // Disable the search tool
+    await toggleToolDisabled(page, TOOL_IDS.searchOption);
+
+    // Verify localStorage was written (the fix being tested)
</file context>
Fix with Cubic

.locator(TOOL_IDS.imageGenerationOption)
.isVisible()
.catch(() => false);
console.log(`[tools] web_search=${webVisible}, image_gen=${imgVisible}`);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Custom agent: No debugging code

Remove the direct debug console.log/console.warn statements from this test file before merge; they are temporary debugging output and violate the no-debugging-code rule.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/tests/e2e/chat/actions_popover.spec.ts, line 146:

<comment>Remove the direct debug `console.log`/`console.warn` statements from this test file before merge; they are temporary debugging output and violate the no-debugging-code rule.</comment>

<file context>
@@ -0,0 +1,303 @@
+      .locator(TOOL_IDS.imageGenerationOption)
+      .isVisible()
+      .catch(() => false);
+    console.log(`[tools] web_search=${webVisible}, image_gen=${imgVisible}`);
+  });
+
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants