Skip to content

refactor(ARCHITECT-002): split AdminSettings — extract AI section + constants#203

Merged
Blb3D merged 3 commits intomainfrom
refactor/architect-002-admin-settings
Feb 2, 2026
Merged

refactor(ARCHITECT-002): split AdminSettings — extract AI section + constants#203
Blb3D merged 3 commits intomainfrom
refactor/architect-002-admin-settings

Conversation

@Blb3D
Copy link
Copy Markdown
Owner

@Blb3D Blb3D commented Feb 2, 2026

Summary

  • Extract AiSettingsSection.jsx — self-contained component with its own state, API handlers, and JSX (~564 lines of logic+UI)
  • Extract constants.jstimezoneOptions array and formatPhoneNumber utility
  • AdminSettings.jsx: 1372 → 761 lines (45% reduction)

Files

File Action
frontend/src/components/settings/AiSettingsSection.jsx New — AI provider config (Anthropic/Ollama)
frontend/src/components/settings/constants.js New — timezone options, phone formatter
frontend/src/pages/admin/AdminSettings.jsx Modified — imports extracted components

ARCHITECT-002 Progress

Batch File Before After Status
1 AdminBOM.jsx 3938 434 Merged
2 SalesOrderWizard.jsx 2729 1421 Merged
3 AdminAccounting.jsx 2179 203 Merged
4 AdminItems.jsx 2079 1069 Merged
5 AdminManufacturing.jsx 2062 482 Merged
6 OrderDetail.jsx 1696 924 Merged
7 AdminPrinters.jsx 1668 964 Merged
8 AdminQuotes.jsx 1661 646 Merged
9 AdminPurchasing.jsx 1650 1427 Merged
10 AdminCustomers.jsx 1511 404 Merged
11 AdminSettings.jsx 1372 761 This PR

Test plan

  • Build passes (npm run build)
  • Lint clean (npx eslint)
  • Settings page loads correctly
  • Company settings save works
  • AI Configuration section renders and functions (provider selection, save, test, clear)
  • Block External AI toggle works

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a dedicated AI Settings section supporting Anthropic and Ollama configuration.
    • Test AI connection feature with success/error feedback.
    • Option to install Anthropic package and start Ollama from the UI.
    • Block External AI Services toggle for privacy control and persistence.
    • Dynamic status panel showing masked API key and provider-specific guidance.
    • Improved phone formatting and expanded timezone selection in settings.
  • Refactor

    • Moved AI configuration into a standalone component for cleaner admin settings.

…onstants

- Extract AiSettingsSection.jsx (self-contained: state, handlers, JSX)
- Extract constants.js (timezoneOptions, formatPhoneNumber)
- AdminSettings.jsx: 1372 → 761 lines

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 2, 2026 07:07
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 2, 2026

Walkthrough

AiSettingsSection.jsx adds a dedicated AI settings UI (Anthropic, Ollama) with state, API calls (fetch/save/test/install/start), and external-AI blocking. A new constants module exports phone formatting and timezone options. AdminSettings.jsx now delegates AI UI to AiSettingsSection.

Changes

Cohort / File(s) Summary
New AI Settings Component
frontend/src/components/settings/AiSettingsSection.jsx
Adds a ~583-line React component handling AI provider selection (Anthropic, Ollama), form state, fetch/PATCH/test/install/start API interactions, anthropic status checks, external-AI block toggle, and toast feedback.
Shared Settings Constants
frontend/src/components/settings/constants.js
New module exporting formatPhoneNumber(value) and timezoneOptions for reuse; extracts phone formatter and timezone data from AdminSettings.
AdminSettings Refactor
frontend/src/pages/admin/AdminSettings.jsx
Removes inline AI configuration logic (~614 lines) and replaces it with a single AiSettingsSection import; imports formatPhoneNumber and timezoneOptions from the new constants module.

Sequence Diagram(s)

sequenceDiagram
  participant User as "User (Browser)"
  participant UI as "AiSettingsSection (Frontend)"
  participant API as "Backend API"
  participant Anth as "Anthropic Service"
  participant Oll as "Ollama Service"

  User->>UI: Open AI settings / interact
  UI->>API: GET /api/settings/ai
  API-->>UI: AI settings JSON
  alt Save settings
    UI->>API: PATCH /api/settings/ai
    API-->>UI: 200 OK
  end
  alt Check Anthropic status
    UI->>API: POST /api/anthropic-status
    API->>Anth: query runtime/status
    Anth-->>API: status
    API-->>UI: status
  end
  alt Install Anthropic
    UI->>API: POST /api/install-anthropic
    API->>Anth: trigger install
    API-->>UI: install response
  end
  alt Start Ollama
    UI->>API: POST /api/start-ollama
    API->>Oll: start request
    Oll-->>API: started/status
    API-->>UI: ollama status
  end
  UI->>API: POST /api/test-ai-connection
  API->>Anth: or ->Oll : proxy test request
  API-->>UI: test result
  UI-->>User: display result/toast
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Poem

A little panel, tidy and bright,
Anthropic, Ollama — all in sight. 🤖
Buttons click, tests run, toasts sing,
Settings split clean—let joy take wing. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main refactoring effort: extracting the AI settings section into a dedicated component and creating a shared constants module, which aligns with the substantial changes across all three modified/new files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/architect-002-admin-settings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors AdminSettings.jsx by extracting AI configuration functionality into a standalone component and shared constants into a separate module. The refactoring reduces AdminSettings.jsx from 1372 to 761 lines (45% reduction), continuing the ARCHITECT-002 initiative to improve code maintainability.

Changes:

  • Extracted AI provider configuration (Anthropic/Ollama) into self-contained AiSettingsSection component
  • Created constants.js module for shared timezone options and phone formatting utility
  • Removed ~600 lines of AI-related code from AdminSettings.jsx

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
frontend/src/components/settings/AiSettingsSection.jsx New self-contained component managing AI provider configuration with its own state, API handlers, and UI (~583 lines)
frontend/src/components/settings/constants.js New module exporting timezoneOptions array and formatPhoneNumber utility function
frontend/src/pages/admin/AdminSettings.jsx Updated to import and use extracted components, removing AI-related state/logic while maintaining all other settings functionality

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +13 to +19
const [aiForm, setAiForm] = useState({
ai_provider: "",
ai_api_key: "",
ai_ollama_url: "http://localhost:11434",
ai_ollama_model: "llama3.2",
external_ai_blocked: false,
});
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

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

The ai_anthropic_model field is missing from the initial state definition in aiForm. This field is used in the model selection dropdown (line 457) and in the save handler (lines 130-131), but it's not initialized in the state object (lines 13-19). This will cause the select dropdown to show no selected value initially and could lead to undefined behavior.

Add ai_anthropic_model to the initial state, for example: ai_anthropic_model: "claude-haiku-3-5-20241022" (using the fastest/cheapest option as default).

Copilot uses AI. Check for mistakes.
Comment on lines +43 to +49
setAiForm({
ai_provider: data.ai_provider || "",
ai_api_key: "", // Don't populate - it's masked
ai_ollama_url: data.ai_ollama_url || "http://localhost:11434",
ai_ollama_model: data.ai_ollama_model || "llama3.2",
external_ai_blocked: data.external_ai_blocked || false,
});
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

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

The ai_anthropic_model field is also missing when populating the form from the API response. When fetching AI settings, the form is populated with various fields (lines 43-49), but ai_anthropic_model is not included. This means that even if a model was previously saved, it won't be displayed in the form when the page loads.

Add ai_anthropic_model to the form population, for example: ai_anthropic_model: data.ai_anthropic_model || "claude-haiku-3-5-20241022"

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@frontend/src/components/settings/AiSettingsSection.jsx`:
- Around line 345-360: The Anthropic diagnostic state can become stale when
switching providers; add a provider-aware effect (useEffect) that watches
aiForm.ai_provider and, when it changes to "anthropic", calls your existing
refresh function (e.g., fetchAnthropicStatus or refreshAnthropicStatus) to
update anthropicStatus via setAnthropicStatus so the UI reflects the current
installation/availability state; ensure the effect only runs on provider change
and cleans up/guards against race conditions if the refresh function is async.
- Around line 13-19: The aiForm initial state in AiSettingsSection.jsx is
missing the ai_anthropic_model key, causing the Anthropics model <select> to be
uncontrolled; add ai_anthropic_model to the useState initial object (e.g.,
ai_anthropic_model: "" or a sensible default) and also hydrate
ai_anthropic_model from loaded settings where aiForm is populated so the select
in the component remains controlled and the saved model displays; update
references to aiForm/ setAiForm accordingly to include this field.
- Around line 36-58: The fetch for AI settings currently ignores non-OK
responses; update the response handling in the async block that calls
fetch(`${API_URL}/api/v1/settings/ai`) so that when response.ok is false you
parse/obtain an error message (or use a default), call the existing toast/error
UI helper to show the error, and ensure you reset Anthropic loading by calling
setAnthropicStatus(prev => ({ ...prev, loading: false })); keep successful
behavior (setAiSettings, setAiForm, checkAnthropicStatus) unchanged and only add
the error toast + loading reset in the else branch for non-OK responses.
🧹 Nitpick comments (1)
frontend/src/components/settings/constants.js (1)

7-14: Add a tiny guard for non‑string inputs in formatPhoneNumber.
If this helper is ever used with nullish/number values, .replace will throw. A small default/coercion keeps it safe. TARS likes airbags.

🛡️ Suggested tweak
-export const formatPhoneNumber = (value) => {
-  const digits = value.replace(/\D/g, "").slice(0, 10);
+export const formatPhoneNumber = (value = "") => {
+  const digits = String(value ?? "").replace(/\D/g, "").slice(0, 10);
   if (digits.length === 0) return "";
   if (digits.length <= 3) return `(${digits}`;
   if (digits.length <= 6) return `(${digits.slice(0, 3)}) ${digits.slice(3)}`;
   return `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`;
 };

Comment thread frontend/src/components/settings/AiSettingsSection.jsx
Comment thread frontend/src/components/settings/AiSettingsSection.jsx
Comment thread frontend/src/components/settings/AiSettingsSection.jsx
- Add ai_anthropic_model to aiForm initial state and hydration (controlled select)
- Handle non-OK response in fetchAiSettings with error toast
- Add useEffect to refresh Anthropic status on provider switch

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@frontend/src/components/settings/AiSettingsSection.jsx`:
- Around line 41-45: In fetchAiSettings, avoid returning early when adminToken
is missing without updating anthropicStatus — currently anthropicStatus.loading
stays true and the UI is stuck; update the function (fetchAiSettings) to set
anthropicStatus to a non-loading state (e.g., loading: false and an appropriate
error or status message) before returning so the component reflects the missing
token and stops showing a perpetual loading indicator.
- Around line 406-434: The UI shows the "Required Package Not Installed" alert
prematurely because anthropicStatus.installed defaults to false; update the
rendering logic in AiSettingsSection.jsx to also check anthropicStatus.loading
(or similar loading flag) before showing the warning: only render the alert when
loading === false and installed === false, and while loading show a subtle
"Checking..." state (or a disabled button/spinner). Adjust the conditional
around the block that references anthropicStatus.installed and ensure
handleInstallAnthropic and installingAnthropic behavior remains unchanged.
- Around line 131-162: The current payload omits fields when users clear them
which leaves stale values on the server; update the payload-building logic (the
block that constructs payload from aiForm) to explicitly include keys with null
when the corresponding aiForm value is an empty string (e.g., ai_ollama_url,
ai_ollama_model, ai_anthropic_model and ai_api_key where appropriate) so the
server can clear them, then after a successful PATCH (where you call
setAiSettings) rehydrate the form from the returned data by calling
setAiForm(...) with the response data (and still clear the local ai_api_key
input) so UI and server remain in sync.

Comment thread frontend/src/components/settings/AiSettingsSection.jsx
Comment thread frontend/src/components/settings/AiSettingsSection.jsx Outdated
Comment thread frontend/src/components/settings/AiSettingsSection.jsx
- Reset anthropicStatus.loading on missing token early return
- Always send AI fields in save payload (allows clearing) + rehydrate form from response
- Gate "not installed" warning on loading state, show "checking..." while loading

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@Blb3D Blb3D merged commit 8787cda into main Feb 2, 2026
12 checks passed
@Blb3D Blb3D deleted the refactor/architect-002-admin-settings branch February 2, 2026 20:05
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