This commit is contained in:
@@ -124,7 +124,7 @@ function AssetUploader({
|
||||
type="button"
|
||||
onClick={() => void handleClear()}
|
||||
disabled={busy}
|
||||
className="px-2.5 h-7 text-2xs font-medium text-red-700 border border-red-200 bg-canvas hover:bg-red-50 rounded-md disabled:opacity-50 transition-colors"
|
||||
className="px-2.5 h-7 text-2xs font-medium text-red-700 dark:text-red-300 border border-red-200 bg-canvas hover:bg-red-50 dark:hover:bg-red-500/15 rounded-md disabled:opacity-50 transition-colors"
|
||||
>
|
||||
削除
|
||||
</button>
|
||||
|
||||
@@ -242,16 +242,16 @@ function ConfigFormInner({ section }: ConfigFormProps) {
|
||||
<div
|
||||
className={`sticky bottom-0 px-3 py-2.5 mt-6 border rounded-md flex items-center justify-end gap-2 transition-colors ${
|
||||
dirty
|
||||
? 'bg-amber-50 border-amber-300 shadow-[0_2px_8px_rgba(180,83,9,0.08)]'
|
||||
? 'bg-amber-50 dark:bg-amber-500/15 border-amber-300 dark:border-amber-500/30 shadow-[0_2px_8px_rgba(180,83,9,0.08)]'
|
||||
: 'bg-canvas border-hairline'
|
||||
}`}
|
||||
>
|
||||
{toast ? (
|
||||
<span className={`text-2xs mr-auto ${toast.startsWith('エラー') ? 'text-red-600' : 'text-emerald-700'}`}>
|
||||
<span className={`text-2xs mr-auto ${toast.startsWith('エラー') ? 'text-red-600' : 'text-emerald-700 dark:text-emerald-300'}`}>
|
||||
{toast}
|
||||
</span>
|
||||
) : dirty ? (
|
||||
<span className="text-xs mr-auto text-amber-800 flex items-center gap-1.5 font-medium min-w-0">
|
||||
<span className="text-xs mr-auto text-amber-800 dark:text-amber-300 flex items-center gap-1.5 font-medium min-w-0">
|
||||
<span className="inline-block w-1.5 h-1.5 rounded-full bg-amber-500 animate-pulse flex-shrink-0" aria-hidden />
|
||||
<span className="truncate">
|
||||
<span className="hidden sm:inline">未保存: {dirtyCount} 項目 — 「Save & Apply」を押すまで反映されません</span>
|
||||
|
||||
@@ -106,9 +106,9 @@ export function GatewayKeyRawKeyDialog({ rawKey, team, reason, onClose }: Props)
|
||||
</h3>
|
||||
<p className="text-xs text-slate-500 mb-4">team: {team}</p>
|
||||
|
||||
<div className="rounded border border-red-300 bg-red-50 p-3 mb-3">
|
||||
<p className="text-sm text-red-800 font-medium">⚠️ このキーは今後二度と表示されません</p>
|
||||
<p className="text-xs text-red-700 mt-1">
|
||||
<div className="rounded border border-red-300 dark:border-red-500/30 bg-red-50 dark:bg-red-500/15 p-3 mb-3">
|
||||
<p className="text-sm text-red-800 dark:text-red-300 font-medium">⚠️ このキーは今後二度と表示されません</p>
|
||||
<p className="text-xs text-red-700 dark:text-red-300 mt-1">
|
||||
必ずパスワードマネージャや LLM クライアントの設定にコピー・保存してから閉じてください。
|
||||
紛失した場合は Rotate で再発行する必要があります。
|
||||
</p>
|
||||
|
||||
@@ -282,9 +282,9 @@ export function GatewayKeysSection({ showToast }: Props) {
|
||||
</td>
|
||||
<td className="p-2 text-xs">
|
||||
{isRevoked ? (
|
||||
<span className="px-1.5 py-0.5 bg-red-50 text-red-700 rounded">revoked</span>
|
||||
<span className="px-1.5 py-0.5 bg-red-50 dark:bg-red-500/15 text-red-700 dark:text-red-300 rounded">revoked</span>
|
||||
) : (
|
||||
<span className="px-1.5 py-0.5 bg-green-50 text-green-700 rounded">active</span>
|
||||
<span className="px-1.5 py-0.5 bg-green-50 dark:bg-green-500/15 text-green-700 dark:text-green-300 rounded">active</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="p-2 text-right">
|
||||
@@ -308,7 +308,7 @@ export function GatewayKeysSection({ showToast }: Props) {
|
||||
type="button"
|
||||
disabled={isRevoked}
|
||||
onClick={() => handleRevoke(row)}
|
||||
className="px-2 py-0.5 text-xs rounded border border-red-300 text-red-700 hover:bg-red-50 disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
className="px-2 py-0.5 text-xs rounded border border-red-300 text-red-700 dark:text-red-300 hover:bg-red-50 dark:hover:bg-red-500/15 disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
>
|
||||
Revoke
|
||||
</button>
|
||||
|
||||
@@ -87,21 +87,21 @@ function StatusBadge({ status }: { status: GatewayServerStatus | undefined }) {
|
||||
}
|
||||
if (status.state === 'running') {
|
||||
return (
|
||||
<span className="text-xs px-2 py-0.5 rounded bg-emerald-50 text-emerald-700 border border-emerald-200">
|
||||
<span className="text-xs px-2 py-0.5 rounded bg-emerald-50 dark:bg-emerald-500/15 text-emerald-700 dark:text-emerald-300 border border-emerald-200 dark:border-emerald-500/30">
|
||||
running (mounted at /v1, port {status.sharedPort})
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (status.state === 'misconfigured') {
|
||||
return (
|
||||
<span className="text-xs px-2 py-0.5 rounded bg-red-50 text-red-700 border border-red-200">
|
||||
<span className="text-xs px-2 py-0.5 rounded bg-red-50 dark:bg-red-500/15 text-red-700 dark:text-red-300 border border-red-200 dark:border-red-500/30">
|
||||
misconfigured ({status.errors.length} error{status.errors.length === 1 ? '' : 's'})
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (status.state === 'starting' || status.state === 'stopping') {
|
||||
return (
|
||||
<span className="text-xs px-2 py-0.5 rounded bg-amber-50 text-amber-700 border border-amber-200">
|
||||
<span className="text-xs px-2 py-0.5 rounded bg-amber-50 dark:bg-amber-500/15 text-amber-700 dark:text-amber-300 border border-amber-200 dark:border-amber-500/30">
|
||||
{status.state}…
|
||||
</span>
|
||||
);
|
||||
@@ -206,7 +206,7 @@ export function GatewayServerForm({ config, onChange }: SectionFormProps) {
|
||||
<StatusBadge status={statusQuery.data} />
|
||||
</div>
|
||||
{statusQuery.data?.errors && statusQuery.data.errors.length > 0 && (
|
||||
<ul className="mt-2 text-xs text-red-700 bg-red-50 border border-red-200 rounded p-2 space-y-0.5">
|
||||
<ul className="mt-2 text-xs text-red-700 dark:text-red-300 bg-red-50 dark:bg-red-500/15 border border-red-200 dark:border-red-500/30 rounded p-2 space-y-0.5">
|
||||
{statusQuery.data.errors.map((e, i) => (
|
||||
<li key={i}>• {e}</li>
|
||||
))}
|
||||
@@ -260,7 +260,7 @@ export function GatewayServerForm({ config, onChange }: SectionFormProps) {
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className={`border rounded-md p-3 space-y-2 relative ${errs.length > 0 ? 'border-red-200 bg-red-50/30' : 'border-slate-200'}`}
|
||||
className={`border rounded-md p-3 space-y-2 relative ${errs.length > 0 ? 'border-red-200 dark:border-red-500/30 bg-red-50/30 dark:bg-red-500/10' : 'border-slate-200'}`}
|
||||
>
|
||||
<button
|
||||
onClick={() => removeBackend(i)}
|
||||
@@ -306,7 +306,7 @@ export function GatewayServerForm({ config, onChange }: SectionFormProps) {
|
||||
reference into a literal "${VAR}" string and
|
||||
the env var indirection is lost. */}
|
||||
{typeof b.apiKey === 'string' && b.apiKey.trimStart().startsWith('${') && (
|
||||
<p className="text-2xs text-amber-700 bg-amber-50 border border-amber-200 rounded px-2 py-1 mt-1">
|
||||
<p className="text-2xs text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-500/15 border border-amber-200 dark:border-amber-500/30 rounded px-2 py-1 mt-1">
|
||||
env var reference detected: 保存すると <code>{b.apiKey}</code> がそのまま config.yaml に書き込まれ、起動時の env 置換は効かなくなります。env 経由で渡すなら config.yaml を直接編集してください。
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -24,7 +24,7 @@ export function KnowledgeNamespacesForm({ config, onChange }: SectionFormProps)
|
||||
<div className="flex items-center gap-2">
|
||||
<h2 className="text-base font-semibold text-slate-800">Knowledge (DKS)</h2>
|
||||
<span
|
||||
className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold uppercase tracking-wide bg-amber-100 text-amber-800 border border-amber-300"
|
||||
className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold uppercase tracking-wide bg-amber-100 dark:bg-amber-500/15 text-amber-800 dark:text-amber-300 border border-amber-300 dark:border-amber-500/30"
|
||||
title="この機能は legacy です。新規の知識検索統合は MCP server 経由を推奨"
|
||||
>
|
||||
LEGACY
|
||||
@@ -33,14 +33,14 @@ export function KnowledgeNamespacesForm({ config, onChange }: SectionFormProps)
|
||||
|
||||
<div
|
||||
role="note"
|
||||
className="rounded border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-900"
|
||||
className="rounded border border-amber-300 dark:border-amber-500/30 bg-amber-50 dark:bg-amber-500/15 px-3 py-2 text-xs text-amber-900 dark:text-amber-300"
|
||||
>
|
||||
DKS 機能は <strong>legacy</strong> 化されており、新規の知識検索統合は{' '}
|
||||
<strong>MCP server 経由</strong> を推奨します。既存の namespace 設定は引き続き動作しますが、
|
||||
新規 namespace の追加はできません。{' '}
|
||||
<a
|
||||
href="/help"
|
||||
className="underline text-amber-900 hover:text-amber-700"
|
||||
className="underline text-amber-900 dark:text-amber-300 hover:text-amber-700 dark:hover:text-amber-300"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -237,7 +237,7 @@ export function LlmWorkersForm({ config, onChange, overriddenByEnv }: SectionFor
|
||||
/>
|
||||
{endpointOverridden && <EnvOverrideWarning />}
|
||||
{showSelfLoop && (
|
||||
<p className="text-2xs text-amber-700 bg-amber-50 border border-amber-200 rounded px-2 py-1 mt-1">
|
||||
<p className="text-2xs text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-500/15 border border-amber-200 dark:border-amber-500/30 rounded px-2 py-1 mt-1">
|
||||
endpoint は自インスタンスを指しているように見えます (self-loop)。
|
||||
リバースプロキシ越しの場合はこの警告は無視できます。
|
||||
</p>
|
||||
|
||||
@@ -144,11 +144,11 @@ async function fetchMetrics(days: number = 30): Promise<ReflectionMetrics> {
|
||||
// ── Shared UI primitives ──────────────────────────────────────────────────────
|
||||
|
||||
const OUTCOME_LABELS: Record<string, { label: string; cls: string }> = {
|
||||
applied: { label: '適用済み', cls: 'bg-emerald-100 text-emerald-800' },
|
||||
partial: { label: '一部適用', cls: 'bg-yellow-100 text-yellow-800' },
|
||||
applied: { label: '適用済み', cls: 'bg-emerald-100 dark:bg-emerald-500/15 text-emerald-800 dark:text-emerald-300' },
|
||||
partial: { label: '一部適用', cls: 'bg-yellow-100 dark:bg-yellow-500/15 text-yellow-800 dark:text-yellow-300' },
|
||||
abstained: { label: '学習なし', cls: 'bg-slate-100 text-slate-600' },
|
||||
rejected: { label: '却下', cls: 'bg-red-100 text-red-700' },
|
||||
failed: { label: '失敗', cls: 'bg-red-200 text-red-900' },
|
||||
rejected: { label: '却下', cls: 'bg-red-100 dark:bg-red-500/15 text-red-700 dark:text-red-300' },
|
||||
failed: { label: '失敗', cls: 'bg-red-200 dark:bg-red-500/20 text-red-900 dark:text-red-300' },
|
||||
};
|
||||
|
||||
function OutcomeBadge({ outcome }: { outcome: string }) {
|
||||
@@ -307,7 +307,7 @@ function MemoryEntryModal({
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="text-xs text-red-600 bg-red-50 border border-red-200 px-3 py-2 rounded-md">
|
||||
<div className="text-xs text-red-600 dark:text-red-300 bg-red-50 dark:bg-red-500/15 border border-red-200 dark:border-red-500/30 px-3 py-2 rounded-md">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
@@ -411,7 +411,7 @@ function MemoryEntriesPanel() {
|
||||
)}
|
||||
|
||||
{deleteError && (
|
||||
<div className="px-4 py-2 text-xs text-red-600 bg-red-50">
|
||||
<div className="px-4 py-2 text-xs text-red-600 dark:text-red-300 bg-red-50 dark:bg-red-500/15">
|
||||
{deleteError}
|
||||
</div>
|
||||
)}
|
||||
@@ -456,7 +456,7 @@ function MemoryEntriesPanel() {
|
||||
<button
|
||||
onClick={() => void handleDelete(entry.name)}
|
||||
disabled={deleting === entry.name}
|
||||
className="px-2 h-6 text-2xs text-red-700 border border-red-200 bg-canvas hover:bg-red-50 rounded transition-colors disabled:opacity-50"
|
||||
className="px-2 h-6 text-2xs text-red-700 dark:text-red-300 border border-red-200 bg-canvas hover:bg-red-50 dark:hover:bg-red-500/15 rounded transition-colors disabled:opacity-50"
|
||||
>
|
||||
{deleting === entry.name ? '…' : '削除'}
|
||||
</button>
|
||||
@@ -517,12 +517,12 @@ function SnapshotCard({ item, onReverted }: { item: SnapshotIndexEntry; onRevert
|
||||
</span>
|
||||
<span className="flex-shrink-0 flex items-center gap-1.5">
|
||||
{item.memoryChanges > 0 && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 bg-blue-50 text-blue-700 rounded">
|
||||
<span className="text-[10px] px-1.5 py-0.5 bg-blue-50 dark:bg-blue-500/15 text-blue-700 dark:text-blue-300 rounded">
|
||||
{item.memoryChanges} mem
|
||||
</span>
|
||||
)}
|
||||
{item.pieceEdited && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 bg-purple-50 text-purple-700 rounded">
|
||||
<span className="text-[10px] px-1.5 py-0.5 bg-purple-50 dark:bg-purple-500/15 text-purple-700 dark:text-purple-300 rounded">
|
||||
piece
|
||||
</span>
|
||||
)}
|
||||
@@ -579,7 +579,7 @@ function SnapshotCard({ item, onReverted }: { item: SnapshotIndexEntry; onRevert
|
||||
</div>
|
||||
<ul className="space-y-0.5">
|
||||
{d.rejections.map((r, i) => (
|
||||
<li key={i} className="text-2xs text-red-700">
|
||||
<li key={i} className="text-2xs text-red-700 dark:text-red-300">
|
||||
<span className="font-mono">{r.code}</span>
|
||||
{r.name && <span className="text-slate-500 ml-1">({r.name})</span>}
|
||||
</li>
|
||||
@@ -631,7 +631,7 @@ function SnapshotCard({ item, onReverted }: { item: SnapshotIndexEntry; onRevert
|
||||
{!item.reverted && (
|
||||
<div className="pt-1">
|
||||
{revertDone === true && (
|
||||
<span className="text-xs text-emerald-700">正常に revert しました。</span>
|
||||
<span className="text-xs text-emerald-700 dark:text-emerald-300">正常に revert しました。</span>
|
||||
)}
|
||||
{revertDone === false && (
|
||||
<span className="text-xs text-slate-500">すでに revert 済みです。</span>
|
||||
@@ -640,14 +640,14 @@ function SnapshotCard({ item, onReverted }: { item: SnapshotIndexEntry; onRevert
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setConfirmRevert(true)}
|
||||
className="px-2.5 h-7 text-2xs text-amber-800 border border-amber-300 bg-amber-50 hover:bg-amber-100 rounded transition-colors"
|
||||
className="px-2.5 h-7 text-2xs text-amber-800 dark:text-amber-300 border border-amber-300 dark:border-amber-500/30 bg-amber-50 dark:bg-amber-500/15 hover:bg-amber-100 dark:hover:bg-amber-500/15 rounded transition-colors"
|
||||
>
|
||||
このスナップショットを revert…
|
||||
</button>
|
||||
)}
|
||||
{revertDone === null && confirmRevert && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-amber-800">
|
||||
<span className="text-xs text-amber-800 dark:text-amber-300">
|
||||
このスナップショットの変更前の状態に戻しますか?
|
||||
</span>
|
||||
<button
|
||||
@@ -729,12 +729,12 @@ function BeforeAfterDiff({
|
||||
</div>
|
||||
)}
|
||||
{isAdded && (
|
||||
<div className="text-2xs text-emerald-700 bg-emerald-50 border border-emerald-200 rounded px-2 py-1 mb-1">
|
||||
<div className="text-2xs text-emerald-700 dark:text-emerald-300 bg-emerald-50 dark:bg-emerald-500/15 border border-emerald-200 dark:border-emerald-500/30 rounded px-2 py-1 mb-1">
|
||||
追加
|
||||
</div>
|
||||
)}
|
||||
{isRemoved && (
|
||||
<div className="text-2xs text-red-700 bg-red-50 border border-red-200 rounded px-2 py-1 mb-1">
|
||||
<div className="text-2xs text-red-700 dark:text-red-300 bg-red-50 dark:bg-red-500/15 border border-red-200 dark:border-red-500/30 rounded px-2 py-1 mb-1">
|
||||
削除
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -146,7 +146,7 @@ export function ModelSelect({ value, onChange, endpoint, apiKeyRaw }: ModelSelec
|
||||
className="w-full h-8 px-2.5 text-[13px] border border-hairline rounded-md focus:ring-2 focus:ring-accent-ring focus:border-accent outline-none bg-canvas"
|
||||
/>
|
||||
{error && (
|
||||
<p className="text-2xs text-amber-700 bg-amber-50 border border-amber-100 px-2 py-1 rounded mt-1">
|
||||
<p className="text-2xs text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-500/15 border border-amber-100 dark:border-amber-500/30 px-2 py-1 rounded mt-1">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -37,11 +37,11 @@ export function MovementAccordion({ movements, onChange, onAdd, onRemove, onMove
|
||||
<span className="text-xs text-slate-400 mr-1">{isExpanded ? '\u25BC' : '\u25B6'}</span>
|
||||
<span className="text-sm font-medium text-slate-800">{movement.name || '(unnamed)'}</span>
|
||||
{movement.persona && (
|
||||
<span className="bg-blue-100 text-blue-700 text-xs px-2 py-0.5 rounded">
|
||||
<span className="bg-blue-100 dark:bg-blue-500/15 text-blue-700 dark:text-blue-300 text-xs px-2 py-0.5 rounded">
|
||||
{movement.persona}
|
||||
</span>
|
||||
)}
|
||||
<span className={`text-xs px-2 py-0.5 rounded ${movement.edit ? 'bg-green-100 text-green-700' : 'bg-purple-100 text-purple-700'}`}>
|
||||
<span className={`text-xs px-2 py-0.5 rounded ${movement.edit ? 'bg-green-100 dark:bg-green-500/15 text-green-700 dark:text-green-300' : 'bg-purple-100 dark:bg-purple-500/15 text-purple-700 dark:text-purple-300'}`}>
|
||||
edit: {movement.edit ? 'on' : 'off'}
|
||||
</span>
|
||||
<span className="text-xs text-slate-400">{toolCount} tools</span>
|
||||
@@ -108,7 +108,7 @@ export function MovementAccordion({ movements, onChange, onAdd, onRemove, onMove
|
||||
<button
|
||||
type="button"
|
||||
onClick={onAdd}
|
||||
className="mt-3 text-sm text-blue-600 hover:text-blue-700"
|
||||
className="mt-3 text-sm text-blue-600 hover:text-blue-700 dark:hover:text-blue-300"
|
||||
>
|
||||
+ Add Movement
|
||||
</button>
|
||||
|
||||
@@ -379,7 +379,7 @@ export function NotificationsForm() {
|
||||
<button
|
||||
onClick={() => handleDeleteRemote(s.id)}
|
||||
disabled={busy}
|
||||
className="ml-2 px-2 py-1 text-[11px] text-red-700 hover:bg-red-50 rounded"
|
||||
className="ml-2 px-2 py-1 text-[11px] text-red-700 dark:text-red-300 hover:bg-red-50 dark:hover:bg-red-500/15 rounded"
|
||||
>
|
||||
解除
|
||||
</button>
|
||||
@@ -403,7 +403,7 @@ export function NotificationsForm() {
|
||||
)}
|
||||
|
||||
{pushFatal && (
|
||||
<p className="text-[12px] text-red-700">エラー: {pushFatal}</p>
|
||||
<p className="text-[12px] text-red-700 dark:text-red-300">エラー: {pushFatal}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -224,7 +224,7 @@ export function PieceEditor({ name, isAdmin = true, source }: PieceEditorProps)
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDelete}
|
||||
className="px-3 py-1.5 text-xs text-red-600 hover:bg-red-50 rounded-lg border border-red-200"
|
||||
className="px-3 py-1.5 text-xs text-red-600 hover:bg-red-50 dark:hover:bg-red-500/15 rounded-lg border border-red-200"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
@@ -288,7 +288,7 @@ export function PieceEditor({ name, isAdmin = true, source }: PieceEditorProps)
|
||||
/* YAML editor */
|
||||
<div className="mb-6">
|
||||
{yamlError && (
|
||||
<div className="mb-2 px-3 py-2 bg-red-50 border border-red-200 rounded-lg text-xs text-red-600">
|
||||
<div className="mb-2 px-3 py-2 bg-red-50 dark:bg-red-500/15 border border-red-200 dark:border-red-500/30 rounded-lg text-xs text-red-600 dark:text-red-300">
|
||||
{yamlError}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -53,7 +53,7 @@ export function ReflectionForm({ config, onChange }: SectionFormProps) {
|
||||
</div>
|
||||
|
||||
{enabled && !hasReflectionWorker && (
|
||||
<div className="rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-900">
|
||||
<div className="rounded-md border border-amber-300 dark:border-amber-500/30 bg-amber-50 dark:bg-amber-500/15 px-3 py-2 text-xs text-amber-900 dark:text-amber-300">
|
||||
<div className="font-semibold mb-1">⚠ Reflection worker が未設定です</div>
|
||||
<div>
|
||||
Reflection を有効化しても、<code className="font-mono">roles</code> に
|
||||
|
||||
@@ -83,7 +83,7 @@ export function RulesTable({ rules, movementNames, onChange, disabled = false }:
|
||||
<button
|
||||
type="button"
|
||||
onClick={addRule}
|
||||
className="text-xs text-blue-600 hover:text-blue-700"
|
||||
className="text-xs text-blue-600 hover:text-blue-700 dark:hover:text-blue-300"
|
||||
>
|
||||
+ Add Rule
|
||||
</button>
|
||||
|
||||
@@ -140,7 +140,7 @@ export function SecretInput({ rawValue, onChange, placeholder }: SecretInputProp
|
||||
readOnly
|
||||
className="flex-1 h-8 px-2.5 text-[13px] border border-hairline rounded-md bg-slate-50 text-slate-400 italic"
|
||||
/>
|
||||
<span className="inline-flex items-center px-2 h-6 text-2xs rounded bg-amber-50 text-amber-700 border border-amber-200">
|
||||
<span className="inline-flex items-center px-2 h-6 text-2xs rounded bg-amber-50 dark:bg-amber-500/15 text-amber-700 dark:text-amber-300 border border-amber-200 dark:border-amber-500/30">
|
||||
will be cleared
|
||||
</span>
|
||||
</div>
|
||||
@@ -180,7 +180,7 @@ export function SecretInput({ rawValue, onChange, placeholder }: SecretInputProp
|
||||
<button
|
||||
type="button"
|
||||
onClick={setClearedMode}
|
||||
className="px-2 py-0.5 rounded border border-amber-200 text-amber-700 hover:bg-amber-50"
|
||||
className="px-2 py-0.5 rounded border border-amber-200 text-amber-700 dark:text-amber-300 hover:bg-amber-50 dark:hover:bg-amber-500/15"
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
|
||||
@@ -29,7 +29,7 @@ function SourceBadge({ source }: { source: 'system' | 'user' }) {
|
||||
<span aria-label="locked">🔒</span> system
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-semibold bg-blue-50 text-blue-700">
|
||||
<span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-semibold bg-blue-50 dark:bg-blue-500/15 text-blue-700 dark:text-blue-300">
|
||||
user
|
||||
</span>
|
||||
);
|
||||
@@ -37,10 +37,10 @@ function SourceBadge({ source }: { source: 'system' | 'user' }) {
|
||||
|
||||
function SeverityBadge({ severity }: { severity: string }) {
|
||||
if (severity === 'high') {
|
||||
return <span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-semibold bg-red-100 text-red-700">HIGH</span>;
|
||||
return <span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-semibold bg-red-100 dark:bg-red-500/15 text-red-700 dark:text-red-300">HIGH</span>;
|
||||
}
|
||||
if (severity === 'medium') {
|
||||
return <span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-semibold bg-yellow-100 text-yellow-800">MEDIUM</span>;
|
||||
return <span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-semibold bg-yellow-100 dark:bg-yellow-500/15 text-yellow-800 dark:text-yellow-300">MEDIUM</span>;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -178,7 +178,7 @@ export function SkillsForm() {
|
||||
</p>
|
||||
|
||||
{error && (
|
||||
<div className="mb-3 px-3 py-2 rounded bg-red-50 border border-red-200 text-xs text-red-700">
|
||||
<div className="mb-3 px-3 py-2 rounded bg-red-50 dark:bg-red-500/15 border border-red-200 dark:border-red-500/30 text-xs text-red-700 dark:text-red-300">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
@@ -331,10 +331,10 @@ export function SkillsForm() {
|
||||
|
||||
{/* Findings */}
|
||||
{detailQuery.data.findings.length > 0 && (
|
||||
<div className="border border-yellow-200 bg-yellow-50 rounded p-2 flex flex-col gap-1">
|
||||
<div className="text-xs font-semibold text-yellow-800">Security Findings</div>
|
||||
<div className="border border-yellow-200 dark:border-yellow-500/30 bg-yellow-50 dark:bg-yellow-500/15 rounded p-2 flex flex-col gap-1">
|
||||
<div className="text-xs font-semibold text-yellow-800 dark:text-yellow-300">Security Findings</div>
|
||||
{detailQuery.data.findings.map((f, i) => (
|
||||
<div key={i} className="text-[10px] text-yellow-700 font-mono">
|
||||
<div key={i} className="text-[10px] text-yellow-700 dark:text-yellow-300 font-mono">
|
||||
<SeverityBadge severity={f.severity} />{' '}
|
||||
L{f.line}: {f.pattern} — <code>{f.match}</code>
|
||||
{f.file && <span className="text-slate-500"> ({f.file})</span>}
|
||||
@@ -396,7 +396,7 @@ export function SkillsForm() {
|
||||
<button
|
||||
onClick={handleDelete}
|
||||
disabled={deleteMut.isPending}
|
||||
className="px-3 py-1.5 text-xs font-semibold text-red-600 border border-red-200 rounded hover:bg-red-50 disabled:opacity-50 transition-colors"
|
||||
className="px-3 py-1.5 text-xs font-semibold text-red-600 border border-red-200 rounded hover:bg-red-50 dark:hover:bg-red-500/15 disabled:opacity-50 transition-colors"
|
||||
>
|
||||
{deleteMut.isPending ? 'Deleting...' : 'Delete'}
|
||||
</button>
|
||||
|
||||
@@ -174,9 +174,9 @@ export function SshAuditLog() {
|
||||
function OutcomeBadge({ outcome }: { outcome: string }) {
|
||||
const colorMap: Record<string, string> = {
|
||||
pending: 'bg-slate-100 text-slate-600',
|
||||
success: 'bg-emerald-50 text-emerald-700',
|
||||
failed: 'bg-red-50 text-red-700',
|
||||
denied: 'bg-amber-50 text-amber-700',
|
||||
success: 'bg-emerald-50 dark:bg-emerald-500/15 text-emerald-700 dark:text-emerald-300',
|
||||
failed: 'bg-red-50 dark:bg-red-500/15 text-red-700 dark:text-red-300',
|
||||
denied: 'bg-amber-50 dark:bg-amber-500/15 text-amber-700 dark:text-amber-300',
|
||||
aborted: 'bg-slate-100 text-slate-500',
|
||||
};
|
||||
const cls = colorMap[outcome] ?? 'bg-slate-100 text-slate-600';
|
||||
|
||||
@@ -258,7 +258,7 @@ export function SshGlobalConnectionsForm({ showToast, onChange }: Props) {
|
||||
)}
|
||||
</div>
|
||||
{c.disabledByAdminReason && (
|
||||
<div className="text-2xs text-red-700 mt-0.5">理由: {c.disabledByAdminReason}</div>
|
||||
<div className="text-2xs text-red-700 dark:text-red-300 mt-0.5">理由: {c.disabledByAdminReason}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1 flex-shrink-0 flex-wrap justify-end max-w-[280px]">
|
||||
@@ -371,8 +371,8 @@ function ReasonModal({ title, warning, onCancel, onSubmit }: ReasonModalProps) {
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
|
||||
<div className="w-full max-w-md bg-surface rounded-md shadow-lg border border-hairline overflow-hidden">
|
||||
<div className={`px-4 py-3 border-b border-hairline ${warning ? 'bg-red-50' : ''}`}>
|
||||
<h3 className={`text-sm font-semibold ${warning ? 'text-red-800' : 'text-slate-900'}`}>{title}</h3>
|
||||
<div className={`px-4 py-3 border-b border-hairline ${warning ? 'bg-red-50 dark:bg-red-500/15' : ''}`}>
|
||||
<h3 className={`text-sm font-semibold ${warning ? 'text-red-800 dark:text-red-300' : 'text-slate-900'}`}>{title}</h3>
|
||||
</div>
|
||||
<div className="px-4 py-3 space-y-2">
|
||||
<label className="block text-2xs font-semibold text-slate-500 uppercase tracking-wide">
|
||||
@@ -404,7 +404,7 @@ function ReasonModal({ title, warning, onCancel, onSubmit }: ReasonModalProps) {
|
||||
}
|
||||
|
||||
const btnCls = 'px-2 h-7 text-2xs text-slate-700 border border-hairline rounded hover:bg-surface disabled:opacity-50';
|
||||
const btnDangerCls = 'px-2 h-7 text-2xs text-red-600 border border-hairline rounded hover:bg-red-50 disabled:opacity-50';
|
||||
const btnDangerCls = 'px-2 h-7 text-2xs text-red-600 border border-hairline rounded hover:bg-red-50 dark:hover:bg-red-500/15 disabled:opacity-50';
|
||||
|
||||
/**
|
||||
* Click-to-copy connection UUID. Same UX as the user folder panel — agents
|
||||
@@ -436,10 +436,10 @@ function CopyableUuid({ value }: { value: string }) {
|
||||
function Badge({ color, children }: { color: 'slate' | 'blue' | 'emerald' | 'amber' | 'red'; children: React.ReactNode }) {
|
||||
const cls: Record<typeof color, string> = {
|
||||
slate: 'bg-slate-100 text-slate-600',
|
||||
blue: 'bg-blue-50 text-blue-600',
|
||||
emerald: 'bg-emerald-50 text-emerald-700',
|
||||
amber: 'bg-amber-50 text-amber-700',
|
||||
red: 'bg-red-50 text-red-700',
|
||||
blue: 'bg-blue-50 dark:bg-blue-500/15 text-blue-600 dark:text-blue-300',
|
||||
emerald: 'bg-emerald-50 dark:bg-emerald-500/15 text-emerald-700 dark:text-emerald-300',
|
||||
amber: 'bg-amber-50 dark:bg-amber-500/15 text-amber-700 dark:text-amber-300',
|
||||
red: 'bg-red-50 dark:bg-red-500/15 text-red-700 dark:text-red-300',
|
||||
};
|
||||
return (
|
||||
<span className={`inline-block px-1.5 py-0.5 rounded text-[10px] font-medium leading-none ${cls[color]}`}>
|
||||
|
||||
@@ -105,7 +105,7 @@ export function SshGrantsForm({ showToast }: Props) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-sm font-semibold text-slate-900">アクセス権 (grants)</h3>
|
||||
<div className="border border-amber-200 rounded-md bg-amber-50 p-4 text-xs text-amber-900">
|
||||
<div className="border border-amber-200 dark:border-amber-500/30 rounded-md bg-amber-50 dark:bg-amber-500/15 p-4 text-xs text-amber-900 dark:text-amber-300">
|
||||
<div className="font-semibold mb-1">SSH サブシステムが無効です</div>
|
||||
<div>
|
||||
<code className="font-mono">config.yaml</code> で <code className="font-mono">ssh.enabled: true</code> を設定し、
|
||||
@@ -169,7 +169,7 @@ export function SshGrantsForm({ showToast }: Props) {
|
||||
<div className="text-2xs">
|
||||
<span className="font-mono font-semibold">{g.subjectType}:{g.subjectId}</span>
|
||||
{g.appliesToAllPieces ? (
|
||||
<span className="ml-2 inline-block px-1.5 py-0.5 rounded text-[10px] font-medium bg-amber-50 text-amber-700">
|
||||
<span className="ml-2 inline-block px-1.5 py-0.5 rounded text-[10px] font-medium bg-amber-50 dark:bg-amber-500/15 text-amber-700 dark:text-amber-300">
|
||||
all pieces
|
||||
</span>
|
||||
) : (
|
||||
@@ -183,7 +183,7 @@ export function SshGrantsForm({ showToast }: Props) {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setReasonForDelete(g)}
|
||||
className="px-2 h-6 text-2xs text-red-600 border border-hairline rounded hover:bg-red-50"
|
||||
className="px-2 h-6 text-2xs text-red-600 border border-hairline rounded hover:bg-red-50 dark:hover:bg-red-500/15"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
@@ -303,7 +303,7 @@ function CreateGrantForm({ connections, pieces, onSubmit, onCancel }: CreateGran
|
||||
/>
|
||||
<span>
|
||||
<span className="font-semibold">すべてのピースで利用可能 (applies_to_all_pieces)</span>
|
||||
<span className="block text-2xs text-amber-700">
|
||||
<span className="block text-2xs text-amber-700 dark:text-amber-300">
|
||||
⚠️ この grant は任意の piece からこの接続を使えるようにします。本当に必要なときのみ。
|
||||
</span>
|
||||
</span>
|
||||
@@ -386,8 +386,8 @@ function ReasonModal({ title, warning, onCancel, onSubmit }: ReasonModalProps) {
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
|
||||
<div className="w-full max-w-md bg-surface rounded-md shadow-lg border border-hairline overflow-hidden">
|
||||
<div className={`px-4 py-3 border-b border-hairline ${warning ? 'bg-red-50' : ''}`}>
|
||||
<h3 className={`text-sm font-semibold ${warning ? 'text-red-800' : 'text-slate-900'}`}>{title}</h3>
|
||||
<div className={`px-4 py-3 border-b border-hairline ${warning ? 'bg-red-50 dark:bg-red-500/15' : ''}`}>
|
||||
<h3 className={`text-sm font-semibold ${warning ? 'text-red-800 dark:text-red-300' : 'text-slate-900'}`}>{title}</h3>
|
||||
</div>
|
||||
<div className="px-4 py-3 space-y-2">
|
||||
<label className="block text-2xs font-semibold text-slate-500 uppercase tracking-wide">Reason (≥ 8 chars)</label>
|
||||
|
||||
@@ -99,13 +99,13 @@ export function SshMasterKeyRotationForm({ showToast }: Props) {
|
||||
{activeJobId === null && <span>idle (rotation 未実行)</span>}
|
||||
{activeJobId !== null && statusQuery.isLoading && <span className="text-slate-400">確認中…</span>}
|
||||
{activeJobId !== null && status === null && (
|
||||
<span className="text-emerald-700">job {activeJobId} は完了またはクリア済み</span>
|
||||
<span className="text-emerald-700 dark:text-emerald-300">job {activeJobId} は完了またはクリア済み</span>
|
||||
)}
|
||||
{status && (
|
||||
<>
|
||||
<span className="font-mono">{status.status}</span>
|
||||
{status.notImplemented && (
|
||||
<span className="ml-2 inline-block px-1.5 py-0.5 rounded text-[10px] font-medium bg-amber-50 text-amber-700">
|
||||
<span className="ml-2 inline-block px-1.5 py-0.5 rounded text-[10px] font-medium bg-amber-50 dark:bg-amber-500/15 text-amber-700 dark:text-amber-300">
|
||||
stub (v1)
|
||||
</span>
|
||||
)}
|
||||
@@ -169,8 +169,8 @@ function ConfirmDialog({
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
|
||||
<div className="w-full max-w-lg bg-surface rounded-md shadow-lg border border-amber-300 overflow-hidden">
|
||||
<div className="px-4 py-3 border-b border-amber-200 bg-amber-50">
|
||||
<h3 className="text-sm font-semibold text-amber-900">⚠️ Master Key Rotation を開始</h3>
|
||||
<div className="px-4 py-3 border-b border-amber-200 dark:border-amber-500/30 bg-amber-50 dark:bg-amber-500/15">
|
||||
<h3 className="text-sm font-semibold text-amber-900 dark:text-amber-300">⚠️ Master Key Rotation を開始</h3>
|
||||
</div>
|
||||
<div className="px-4 py-3 space-y-3">
|
||||
<p className="text-xs text-slate-700 leading-relaxed">
|
||||
|
||||
@@ -221,7 +221,7 @@ function SelectedToolChip({
|
||||
// - unknown (not in catalog at all) → amber chip + "unknown" badge
|
||||
const tone =
|
||||
isUnknown || isUnavailable
|
||||
? 'bg-amber-50 text-amber-800 border border-amber-200'
|
||||
? 'bg-amber-50 dark:bg-amber-500/15 text-amber-800 dark:text-amber-300 border border-amber-200 dark:border-amber-500/30'
|
||||
: 'bg-slate-100 text-slate-700';
|
||||
const tip = isUnknown
|
||||
? 'このツールは現在のカタログに存在しません。明示削除するまで保持されます。'
|
||||
@@ -272,10 +272,10 @@ function Badge({
|
||||
}) {
|
||||
const cls: Record<typeof color, string> = {
|
||||
slate: 'bg-slate-100 text-slate-600',
|
||||
blue: 'bg-blue-50 text-blue-700',
|
||||
emerald: 'bg-emerald-50 text-emerald-700',
|
||||
amber: 'bg-amber-50 text-amber-700',
|
||||
red: 'bg-red-50 text-red-700',
|
||||
blue: 'bg-blue-50 dark:bg-blue-500/15 text-blue-700 dark:text-blue-300',
|
||||
emerald: 'bg-emerald-50 dark:bg-emerald-500/15 text-emerald-700 dark:text-emerald-300',
|
||||
amber: 'bg-amber-50 dark:bg-amber-500/15 text-amber-700 dark:text-amber-300',
|
||||
red: 'bg-red-50 dark:bg-red-500/15 text-red-700 dark:text-red-300',
|
||||
};
|
||||
return (
|
||||
<span
|
||||
|
||||
@@ -218,7 +218,7 @@ export function ToolsForm({ config, onChange, visibleTabs }: ToolsFormProps) {
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="text-sm font-semibold text-slate-800">Knowledge (DKS)</h3>
|
||||
<span
|
||||
className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold uppercase tracking-wide bg-amber-100 text-amber-800 border border-amber-300"
|
||||
className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold uppercase tracking-wide bg-amber-100 dark:bg-amber-500/15 text-amber-800 dark:text-amber-300 border border-amber-300 dark:border-amber-500/30"
|
||||
title="この機能は legacy です。新規の知識検索統合は MCP server 経由を推奨"
|
||||
>
|
||||
LEGACY
|
||||
@@ -226,14 +226,14 @@ export function ToolsForm({ config, onChange, visibleTabs }: ToolsFormProps) {
|
||||
</div>
|
||||
<div
|
||||
role="note"
|
||||
className="rounded border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-900"
|
||||
className="rounded border border-amber-300 dark:border-amber-500/30 bg-amber-50 dark:bg-amber-500/15 px-3 py-2 text-xs text-amber-900 dark:text-amber-300"
|
||||
>
|
||||
DKS 機能は <strong>legacy</strong> 化されており、新規の知識検索統合は{' '}
|
||||
<strong>MCP server 経由</strong> を推奨します。既存の namespace 設定は引き続き動作しますが、
|
||||
新規 namespace の追加はできません。{' '}
|
||||
<a
|
||||
href="/help"
|
||||
className="underline text-amber-900 hover:text-amber-700"
|
||||
className="underline text-amber-900 dark:text-amber-300 hover:text-amber-700 dark:hover:text-amber-300"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export function EnvOverrideWarning() {
|
||||
return (
|
||||
<div className="text-2xs text-amber-700 bg-amber-50 border border-amber-100 px-2 py-1 rounded mt-1">
|
||||
<div className="text-2xs text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-500/15 border border-amber-100 dark:border-amber-500/30 px-2 py-1 rounded mt-1">
|
||||
環境変数で上書きされています(保存しても反映されません)
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user