Configure utilities API creds via Settings UI, not .env

Follows the same app_settings/DB pattern already used for the
Forecasting integration: utilities_url and utilities_api_key are now
editable from Reports Settings, with env vars kept only as a fallback.
Avoids needing to SSH in and hand-edit .env to authenticate against
the utilities app's internal API.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-28 14:38:15 +00:00
parent dfd3a506d1
commit 203639af78
4 changed files with 22 additions and 7 deletions

View file

@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'
import { Save } from 'lucide-react'
import { getSettings, saveSettings, type AppSetting } from '../api'
const SETTING_LABELS: Record<string, { label: string; hint: string; secret?: boolean }> = {
const SETTING_LABELS: Record<string, { label: string; hint: string; secret?: boolean; placeholder?: string }> = {
forecasting_api_key: {
label: 'Forecasting API Key',
hint: 'API key for the Forecasting app public API. Create one in Forecasting → Settings → API Keys.',
@ -11,6 +11,17 @@ const SETTING_LABELS: Record<string, { label: string; hint: string; secret?: boo
forecasting_url: {
label: 'Forecasting URL',
hint: 'Internal URL for the Forecasting backend (e.g. http://10.10.10.113:3080). Leave blank to use the default.',
placeholder: 'http://10.10.10.113:3080',
},
utilities_api_key: {
label: 'Utilities API Key',
hint: 'API key for the Utilities app internal API. Must match the key configured in the Utilities app.',
secret: true,
},
utilities_url: {
label: 'Utilities URL',
hint: 'Internal URL for the Utilities backend (e.g. http://10.10.10.127:3080). Leave blank to use the default.',
placeholder: 'http://10.10.10.127:3080',
},
}
@ -72,7 +83,7 @@ export function SettingsPage() {
<input
type={isSecret && !isRevealed ? 'password' : 'text'}
value={values[s.key] ?? ''}
placeholder={isSecret ? 'fk_…' : 'http://10.10.10.113:3080'}
placeholder={isSecret ? 'fk_…' : meta.placeholder ?? 'http://10.10.10.113:3080'}
onChange={e => setValues(v => ({ ...v, [s.key]: e.target.value }))}
className="setting-input"
autoComplete="off"