feat: 全站 PageShell 设计系统与专业 UI 统一
- 新增 PageShell/PageTabs/ContentPanel/PageLoading/PageEmpty 页面骨架 - index.css 设计令牌文档化,布局令牌与纯色主按钮(去除渐变粉彩) - 全站路由页接入 PageShell,云账单三 Tab 为标杆 - 主题体系:跟随系统 + 主流/开发者分组,新增 Dracula/Tokyo Night,One Dark 暖灰差异化 - 登录页/侧栏/顶栏去渐变光球,企业克制风 - 修复 AIAlertAnalyzer JSX 与构建依赖导入问题
This commit is contained in:
1 parent
1acb0c49af
commit
e363ded445
213 files changed
+7148
-6818
No files matched your search
@@ -50,47 +50,47 @@ export function DnsHostSection({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card className="bg-slate-900 border-slate-800">
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-slate-200 flex items-center gap-2">
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Globe className="h-4 w-4 text-indigo-400" />DNS 配置 (dnsConfig)
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0 space-y-3">
|
||||
<p className="text-[11px] text-slate-500">
|
||||
提示:dnsConfig 通常与 <code className="text-slate-400">dnsPolicy: None</code> 搭配使用。每行一个值。
|
||||
<p className="text-[11px] dg-text-muted">
|
||||
提示:dnsConfig 通常与 <code className="dg-text-secondary">dnsPolicy: None</code> 搭配使用。每行一个值。
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<Label className="text-slate-500 text-xs">nameservers(每行一个 IP)</Label>
|
||||
<Label className="dg-text-muted text-xs">nameservers(每行一个 IP)</Label>
|
||||
<textarea
|
||||
value={dnsNameservers}
|
||||
onChange={e => onDnsNameserversChange(e.target.value)}
|
||||
placeholder={'8.8.8.8\n114.114.114.114'}
|
||||
rows={3}
|
||||
className="w-full mt-1 bg-slate-800 border border-slate-700 rounded text-xs text-slate-300 font-mono p-2 resize-y"
|
||||
className="w-full mt-1 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] font-mono p-2 resize-y"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-slate-500 text-xs">searches(搜索域,每行一个)</Label>
|
||||
<Label className="dg-text-muted text-xs">searches(搜索域,每行一个)</Label>
|
||||
<textarea
|
||||
value={dnsSearches}
|
||||
onChange={e => onDnsSearchesChange(e.target.value)}
|
||||
placeholder={'svc.cluster.local\ncluster.local'}
|
||||
rows={3}
|
||||
className="w-full mt-1 bg-slate-800 border border-slate-700 rounded text-xs text-slate-300 font-mono p-2 resize-y"
|
||||
className="w-full mt-1 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] font-mono p-2 resize-y"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<Label className="text-slate-400 text-xs">options(DNS 选项)</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs text-slate-400" onClick={addDnsOption}>
|
||||
<Label className="dg-text-secondary text-xs">options(DNS 选项)</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-secondary" onClick={addDnsOption}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加
|
||||
</Button>
|
||||
</div>
|
||||
{dnsOptions.length === 0 ? (
|
||||
<p className="text-xs text-slate-600 italic">未配置</p>
|
||||
<p className="text-xs dg-text-muted italic">未配置</p>
|
||||
) : (
|
||||
dnsOptions.map((o, i) => (
|
||||
<div key={i} className="flex items-center gap-2 mb-1.5">
|
||||
@@ -98,16 +98,16 @@ export function DnsHostSection({
|
||||
value={o.name}
|
||||
onChange={e => updateDnsOption(i, { name: e.target.value })}
|
||||
placeholder="ndots"
|
||||
className="flex-1 h-7 bg-slate-800 border-slate-700 text-slate-300 text-xs font-mono"
|
||||
className="flex-1 h-7 dg-input text-[var(--dg-text-secondary)] text-xs font-mono"
|
||||
/>
|
||||
<span className="text-slate-600">:</span>
|
||||
<span className="dg-text-muted">:</span>
|
||||
<Input
|
||||
value={o.value}
|
||||
onChange={e => updateDnsOption(i, { value: e.target.value })}
|
||||
placeholder="5(可留空)"
|
||||
className="flex-1 h-7 bg-slate-800 border-slate-700 text-slate-300 text-xs font-mono"
|
||||
className="flex-1 h-7 dg-input text-[var(--dg-text-secondary)] text-xs font-mono"
|
||||
/>
|
||||
<Button size="icon" variant="ghost" className="h-6 w-6 text-red-400" onClick={() => removeDnsOption(i)}>
|
||||
<Button size="icon" variant="ghost" className="h-6 w-6 dg-text-red" onClick={() => removeDnsOption(i)}>
|
||||
<Trash2 className="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
@@ -117,21 +117,21 @@ export function DnsHostSection({
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-slate-900 border-slate-800">
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-slate-200 flex items-center gap-2">
|
||||
<MapPin className="h-4 w-4 text-amber-400" />主机别名 (hostAliases)
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<MapPin className="h-4 w-4 dg-text-yellow" />主机别名 (hostAliases)
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0 space-y-2">
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<Label className="text-slate-400 text-xs">IP → 主机名映射(注入 Pod 的 /etc/hosts)</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs text-slate-400" onClick={addHostAlias}>
|
||||
<Label className="dg-text-secondary text-xs">IP → 主机名映射(注入 Pod 的 /etc/hosts)</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-secondary" onClick={addHostAlias}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加
|
||||
</Button>
|
||||
</div>
|
||||
{hostAliases.length === 0 ? (
|
||||
<p className="text-xs text-slate-600 italic">未配置</p>
|
||||
<p className="text-xs dg-text-muted italic">未配置</p>
|
||||
) : (
|
||||
hostAliases.map((a, i) => (
|
||||
<div key={i} className="flex items-center gap-2">
|
||||
@@ -139,16 +139,16 @@ export function DnsHostSection({
|
||||
value={a.ip}
|
||||
onChange={e => updateHostAlias(i, { ip: e.target.value })}
|
||||
placeholder="10.10.10.72"
|
||||
className="w-40 h-7 bg-slate-800 border-slate-700 text-slate-300 text-xs font-mono"
|
||||
className="w-40 h-7 dg-input text-[var(--dg-text-secondary)] text-xs font-mono"
|
||||
/>
|
||||
<span className="text-slate-600">→</span>
|
||||
<span className="dg-text-muted">→</span>
|
||||
<Input
|
||||
value={a.hostnames}
|
||||
onChange={e => updateHostAlias(i, { hostnames: e.target.value })}
|
||||
placeholder="gitlab.local, registry.local"
|
||||
className="flex-1 h-7 bg-slate-800 border-slate-700 text-slate-300 text-xs font-mono"
|
||||
className="flex-1 h-7 dg-input text-[var(--dg-text-secondary)] text-xs font-mono"
|
||||
/>
|
||||
<Button size="icon" variant="ghost" className="h-6 w-6 text-red-400" onClick={() => removeHostAlias(i)}>
|
||||
<Button size="icon" variant="ghost" className="h-6 w-6 dg-text-red" onClick={() => removeHostAlias(i)}>
|
||||
<Trash2 className="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -51,21 +51,21 @@ export function SchedulingSection({
|
||||
nodeLabels,
|
||||
}: SchedulingSectionProps) {
|
||||
return (
|
||||
<Card className="bg-slate-900 border-slate-800">
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-sm text-slate-200 flex items-center gap-2">
|
||||
<Server className="h-4 w-4 text-emerald-400" />调度 (Scheduling)
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Server className="h-4 w-4 dg-text-green" />调度 (Scheduling)
|
||||
</CardTitle>
|
||||
<div className="flex items-center gap-1 bg-slate-800 rounded-lg p-0.5 border border-slate-700">
|
||||
<div className="flex items-center gap-1 bg-[var(--dg-bg-tertiary)] rounded-lg p-0.5 border border-[var(--dg-border)]">
|
||||
{SCHEDULE_MODES.map(m => (
|
||||
<button
|
||||
key={m.key}
|
||||
onClick={() => onScheduleModeChange(m.key)}
|
||||
className={`px-2.5 py-1 rounded text-[10px] font-medium transition-all ${
|
||||
scheduleMode === m.key
|
||||
? 'bg-emerald-500/20 text-emerald-300 shadow-sm'
|
||||
: 'text-slate-400 hover:text-slate-300'
|
||||
? 'bg-emerald-500/20 dg-text-green shadow-sm'
|
||||
: 'dg-text-secondary hover:text-[var(--dg-text-secondary)]'
|
||||
}`}
|
||||
>
|
||||
{m.label}
|
||||
@@ -73,7 +73,7 @@ export function SchedulingSection({
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 mt-1">
|
||||
<p className="text-xs dg-text-muted mt-1">
|
||||
{scheduleMode === 'nodeName' && 'Pod 将直接调度到指定节点'}
|
||||
{scheduleMode === 'nodeSelector' && 'Pod 将调度到匹配标签的节点'}
|
||||
{scheduleMode === 'nodeAffinity' && '通过亲和性规则控制 Pod 调度到指定节点'}
|
||||
@@ -82,16 +82,16 @@ export function SchedulingSection({
|
||||
<CardContent className="pt-0">
|
||||
{scheduleMode === 'nodeName' && (
|
||||
<div className="space-y-2">
|
||||
<Label className="text-slate-400 text-xs">请选择节点</Label>
|
||||
<Label className="dg-text-secondary text-xs">请选择节点</Label>
|
||||
{nodesLoading ? (
|
||||
<div className="flex items-center gap-1 text-slate-500 text-xs">
|
||||
<div className="flex items-center gap-1 dg-text-muted text-xs">
|
||||
<Loader2 className="h-3 w-3 animate-spin" />加载节点列表...
|
||||
</div>
|
||||
) : (
|
||||
<select
|
||||
value={nodeName}
|
||||
onChange={e => onNodeNameChange(e.target.value)}
|
||||
className="h-8 w-full bg-slate-800 border border-slate-700 rounded text-xs text-slate-300 px-2"
|
||||
className="h-8 w-full bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-2"
|
||||
>
|
||||
<option value="">(不指定)</option>
|
||||
{availableNodes.map(n => (
|
||||
@@ -102,8 +102,8 @@ export function SchedulingSection({
|
||||
</select>
|
||||
)}
|
||||
{nodeName && (
|
||||
<div className="text-[10px] text-slate-500">
|
||||
已选择: <code className="bg-slate-800 px-1 py-0.5 rounded text-emerald-400">{nodeName}</code>
|
||||
<div className="text-[10px] dg-text-muted">
|
||||
已选择: <code className="bg-[var(--dg-bg-tertiary)] px-1 py-0.5 rounded dg-text-green">{nodeName}</code>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -112,20 +112,20 @@ export function SchedulingSection({
|
||||
{scheduleMode === 'nodeSelector' && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-slate-400 text-xs">请选择标签</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs text-slate-400" onClick={onAddLabelSelector}>
|
||||
<Label className="dg-text-secondary text-xs">请选择标签</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-secondary" onClick={onAddLabelSelector}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加
|
||||
</Button>
|
||||
</div>
|
||||
{labelSelectorKv.length === 0 ? (
|
||||
<p className="text-xs text-slate-600 italic">未配置标签选择器</p>
|
||||
<p className="text-xs dg-text-muted italic">未配置标签选择器</p>
|
||||
) : (
|
||||
labelSelectorKv.map((n, i) => (
|
||||
<div key={i} className="flex items-center gap-2">
|
||||
<select
|
||||
value={n.key}
|
||||
onChange={e => onUpdateLabelSelector(i, { key: e.target.value, value: '' })}
|
||||
className="flex-1 h-7 bg-slate-800 border border-slate-700 rounded text-xs text-slate-300 px-1.5"
|
||||
className="flex-1 h-7 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-1.5"
|
||||
>
|
||||
<option value="">选择标签</option>
|
||||
{Object.entries(nodeLabels).map(([k, vals]) => (
|
||||
@@ -135,7 +135,7 @@ export function SchedulingSection({
|
||||
<select
|
||||
value={n.value}
|
||||
onChange={e => onUpdateLabelSelector(i, { value: e.target.value })}
|
||||
className="flex-1 h-7 bg-slate-800 border border-slate-700 rounded text-xs text-slate-300 px-1.5"
|
||||
className="flex-1 h-7 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-1.5"
|
||||
disabled={!n.key}
|
||||
>
|
||||
<option value="">选择值</option>
|
||||
@@ -146,7 +146,7 @@ export function SchedulingSection({
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="h-6 w-6 text-red-400"
|
||||
className="h-6 w-6 dg-text-red"
|
||||
onClick={() => onRemoveLabelSelector(i)}
|
||||
>
|
||||
<Trash2 className="h-3 w-3" />
|
||||
@@ -160,22 +160,22 @@ export function SchedulingSection({
|
||||
{scheduleMode === 'nodeAffinity' && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-slate-400 text-xs">
|
||||
请选择标签 <span className="text-slate-600">(生成 requiredDuringScheduling 规则)</span>
|
||||
<Label className="dg-text-secondary text-xs">
|
||||
请选择标签 <span className="dg-text-muted">(生成 requiredDuringScheduling 规则)</span>
|
||||
</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs text-slate-400" onClick={onAddLabelSelector}>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-secondary" onClick={onAddLabelSelector}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加
|
||||
</Button>
|
||||
</div>
|
||||
{labelSelectorKv.length === 0 ? (
|
||||
<p className="text-xs text-slate-600 italic">未配置亲和性规则</p>
|
||||
<p className="text-xs dg-text-muted italic">未配置亲和性规则</p>
|
||||
) : (
|
||||
labelSelectorKv.map((n, i) => (
|
||||
<div key={i} className="flex items-center gap-2">
|
||||
<select
|
||||
value={n.key}
|
||||
onChange={e => onUpdateLabelSelector(i, { key: e.target.value, value: '' })}
|
||||
className="flex-1 h-7 bg-slate-800 border border-slate-700 rounded text-xs text-slate-300 px-1.5"
|
||||
className="flex-1 h-7 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-1.5"
|
||||
>
|
||||
<option value="">选择标签</option>
|
||||
{Object.entries(nodeLabels).map(([k, vals]) => (
|
||||
@@ -185,7 +185,7 @@ export function SchedulingSection({
|
||||
<select
|
||||
value={n.value}
|
||||
onChange={e => onUpdateLabelSelector(i, { value: e.target.value })}
|
||||
className="flex-1 h-7 bg-slate-800 border border-slate-700 rounded text-xs text-slate-300 px-1.5"
|
||||
className="flex-1 h-7 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-1.5"
|
||||
disabled={!n.key}
|
||||
>
|
||||
<option value="">选择值</option>
|
||||
@@ -196,7 +196,7 @@ export function SchedulingSection({
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="h-6 w-6 text-red-400"
|
||||
className="h-6 w-6 dg-text-red"
|
||||
onClick={() => onRemoveLabelSelector(i)}
|
||||
>
|
||||
<Trash2 className="h-3 w-3" />
|
||||
|
||||
Reference in new issue
Block a user