sync: update from private repo (63a6e76)
CI / build-and-test (push) Has been cancelled

This commit is contained in:
oss-sync
2026-06-09 03:17:43 +00:00
parent d6d8e83867
commit 3848b5efd7
20 changed files with 386 additions and 29 deletions
+116
View File
@@ -0,0 +1,116 @@
import { HelpText } from './HelpText';
import { FieldLabel, FieldInput } from './formUtils';
import { StringArrayEditor } from './StringArrayEditor';
import type { SectionFormProps } from './types';
/**
* Authentication config (`auth.*`): session policy, admin allowlist, and the
* Google / Gitea OAuth providers. Secrets (session secret, client secrets) are
* server-masked (config-manager SENSITIVE_PATHS) — they render as ******** and
* saving without re-entering keeps the stored value.
*
* Leaving the whole `auth` block empty (no providers) keeps the app in no-auth
* mode — every visitor is treated as a local admin.
*/
export function AuthForm({ config, onChange }: SectionFormProps) {
const auth = config.auth ?? {};
const providers = auth.providers ?? {};
const google = providers.google ?? {};
const gitea = providers.gitea ?? {};
return (
<div className="space-y-5">
<h2 className="text-base font-semibold text-slate-800">Authentication</h2>
<p className="text-[13px] text-slate-500">
providers <strong> admin</strong>
</p>
<div>
<FieldLabel>Primary Provider</FieldLabel>
<select
value={auth.primaryProvider ?? ''}
onChange={e => onChange('auth.primaryProvider', e.target.value)}
className="w-full h-8 px-2 text-[13px] border border-hairline rounded-md bg-canvas focus:ring-2 focus:ring-accent-ring focus:border-accent outline-none transition-shadow"
>
<option value=""></option>
<option value="google">google </option>
<option value="gitea">gitea </option>
</select>
<HelpText></HelpText>
</div>
<div>
<FieldLabel>Admin Emails</FieldLabel>
<StringArrayEditor
value={auth.adminEmails ?? []}
onChange={v => onChange('auth.adminEmails', v)}
placeholder="[email protected]"
/>
<HelpText>admin </HelpText>
</div>
<div>
<label className="flex items-center gap-2 text-sm text-slate-700">
<input type="checkbox" checked={auth.secureCookie === true}
onChange={e => onChange('auth.secureCookie', e.target.checked)} className="rounded" />
Secure CookieHTTPS Cookie
</label>
<HelpText>HTTPSHTTP </HelpText>
</div>
<div>
<FieldLabel>Session Max Age (ms)</FieldLabel>
<FieldInput type="number" value={auth.sessionMaxAge ?? ''}
onChange={v => onChange('auth.sessionMaxAge', v ? Number(v) : undefined)} />
<HelpText></HelpText>
</div>
<div>
<FieldLabel>Session Secret</FieldLabel>
<FieldInput type="password" value={auth.sessionSecret ?? ''}
onChange={v => onChange('auth.sessionSecret', v)} />
<HelpText></HelpText>
</div>
<h3 className="text-sm font-medium text-slate-600 mt-4 pt-3 border-t border-slate-200">Google OAuth</h3>
<div>
<FieldLabel>Client ID</FieldLabel>
<FieldInput value={google.clientId ?? ''}
onChange={v => onChange('auth.providers.google.clientId', v)} />
</div>
<div>
<FieldLabel>Client Secret</FieldLabel>
<FieldInput type="password" value={google.clientSecret ?? ''}
onChange={v => onChange('auth.providers.google.clientSecret', v)} />
</div>
<div>
<FieldLabel>Callback URL</FieldLabel>
<FieldInput value={google.callbackUrl ?? ''} placeholder="https://example.com/auth/google/callback"
onChange={v => onChange('auth.providers.google.callbackUrl', v)} />
</div>
<h3 className="text-sm font-medium text-slate-600 mt-4 pt-3 border-t border-slate-200">Gitea OAuth</h3>
<div>
<FieldLabel>Base URL</FieldLabel>
<FieldInput value={gitea.baseUrl ?? ''} placeholder="https://gitea.example.com"
onChange={v => onChange('auth.providers.gitea.baseUrl', v)} />
</div>
<div>
<FieldLabel>Client ID</FieldLabel>
<FieldInput value={gitea.clientId ?? ''}
onChange={v => onChange('auth.providers.gitea.clientId', v)} />
</div>
<div>
<FieldLabel>Client Secret</FieldLabel>
<FieldInput type="password" value={gitea.clientSecret ?? ''}
onChange={v => onChange('auth.providers.gitea.clientSecret', v)} />
</div>
<div>
<FieldLabel>Callback URL</FieldLabel>
<FieldInput value={gitea.callbackUrl ?? ''} placeholder="https://example.com/auth/gitea/callback"
onChange={v => onChange('auth.providers.gitea.callbackUrl', v)} />
</div>
</div>
);
}
@@ -91,6 +91,13 @@ export function BrowserSettingsForm({ config, onChange }: SectionFormProps) {
onChange={v => onChange('browser.maxSessions', Number(v))} />
<HelpText>デフォルト: 3</HelpText>
</div>
<div>
<FieldLabel>Task Session Idle TTL ()</FieldLabel>
<FieldInput type="number" value={browser.taskSessionIdleTtl ?? ''}
onChange={v => onChange('browser.taskSessionIdleTtl', v ? Number(v) : undefined)} />
<HelpText> CDP GCデフォルト: 300</HelpText>
</div>
</div>
);
}
@@ -28,6 +28,7 @@ import { SshForm } from './SshForm';
import { GatewayServerForm } from './GatewayServerForm';
import { NotesForm } from './NotesForm';
import { PushNotificationsForm } from './PushNotificationsForm';
import { AuthForm } from './AuthForm';
import { useAuthState } from '../../App';
@@ -189,6 +190,7 @@ function ConfigFormInner({ section }: ConfigFormProps) {
case 'reflection': return <ReflectionForm {...formProps} />;
case 'notes': return <NotesForm {...formProps} />;
case 'push-notifications': return <PushNotificationsForm {...formProps} />;
case 'auth': return <AuthForm {...formProps} />;
// ── Tools sub-sections — Step 9 split the legacy grab-bag
// ToolsForm into focused per-category forms. Each binds to the
@@ -34,6 +34,7 @@ const CONFIG_GROUPS = [
{ id: 'branding', label: 'Branding' },
{ id: 'paths-storage', label: 'Paths & Storage' },
{ id: 'execution', label: 'Execution' },
{ id: 'auth', label: 'Authentication' },
{ id: 'push-notifications', label: 'Web Push (Server)' },
],
},
@@ -68,6 +69,7 @@ const CONFIG_GROUPS = [
{ id: 'tools-browser', label: 'Browser Runtime' },
{ id: 'tools-media', label: 'Media & Documents' },
{ id: 'tools-external', label: 'External Services' },
{ id: 'search-filter', label: 'Search Filter' },
{ id: 'tools-legacy-knowledge', label: 'Legacy Knowledge' },
],
},
@@ -102,7 +104,6 @@ export const LEGACY_SECTION_REDIRECT: Record<string, string> = {
workspace: 'paths-storage',
tools: 'tools-web',
'browser-settings': 'tools-browser',
'search-filter': 'tools-web',
// browser-sessions never had a Settings page in the new layout —
// it lives in User Folder. Keep mapping so an old URL still goes
// somewhere sensible.
@@ -63,6 +63,39 @@ export function ToolsExternalForm({ config, onChange }: SectionFormProps) {
placeholder="/path/to/chrome/profile" />
<HelpText>Cookie Chrome </HelpText>
</div>
<div>
<FieldLabel>X Media Download</FieldLabel>
<select value={tools.xDownloadMedia ?? 'auto'}
onChange={e => onChange('tools.xDownloadMedia', e.target.value)}
className="w-full h-8 px-2 text-[13px] border border-hairline rounded-md bg-canvas focus:ring-2 focus:ring-accent-ring focus:border-accent outline-none transition-shadow">
<option value="auto">auto/</option>
<option value="never">never</option>
</select>
<HelpText>X 稿デフォルト: auto</HelpText>
</div>
<div>
<FieldLabel>X Video Download</FieldLabel>
<select value={tools.xDownloadVideo ?? 'thumbnail'}
onChange={e => onChange('tools.xDownloadVideo', e.target.value)}
className="w-full h-8 px-2 text-[13px] border border-hairline rounded-md bg-canvas focus:ring-2 focus:ring-accent-ring focus:border-accent outline-none transition-shadow">
<option value="thumbnail">thumbnail</option>
<option value="full">full</option>
<option value="never">never</option>
</select>
<HelpText>X 稿デフォルト: thumbnail</HelpText>
</div>
<div>
<FieldLabel>X Media Max (MB)</FieldLabel>
<FieldInput type="number" value={tools.xMediaMaxMb ?? ''}
onChange={v => onChange('tools.xMediaMaxMb', v ? Number(v) : undefined)} />
<HelpText>1 MB</HelpText>
</div>
<div>
<FieldLabel>X Media Fetch Timeout ()</FieldLabel>
<FieldInput type="number" value={tools.xMediaFetchTimeoutSeconds ?? ''}
onChange={v => onChange('tools.xMediaFetchTimeoutSeconds', v ? Number(v) : undefined)} />
<HelpText></HelpText>
</div>
</section>
<section className="space-y-5 pt-2 border-t border-hairline">
@@ -74,6 +107,12 @@ export function ToolsExternalForm({ config, onChange }: SectionFormProps) {
<FieldInput type="password" value={tools.googleMapsApiKey ?? ''} onChange={v => onChange('tools.googleMapsApiKey', v)} />
<HelpText>Google Maps Places / Directions API Nominatim / OSRM使</HelpText>
</div>
<div>
<FieldLabel>Maps Timeout ()</FieldLabel>
<FieldInput type="number" value={tools.mapsTimeout ?? ''}
onChange={v => onChange('tools.mapsTimeout', v ? Number(v) : undefined)} />
<HelpText>Maps / Nominatim / OSRM デフォルト: 30</HelpText>
</div>
</section>
<section className="space-y-5 pt-2 border-t border-hairline">