|
104 | 104 | </div> |
105 | 105 | </header> |
106 | 106 |
|
| 107 | + <section class="admin-command-strip" aria-label="Admin command summary"> |
| 108 | + <div class="admin-command-copy"> |
| 109 | + <span class="eyebrow">CONTROL ROOM</span> |
| 110 | + <h2>{{ adminCommandTitle }}</h2> |
| 111 | + <p>{{ adminCommandBody }}</p> |
| 112 | + </div> |
| 113 | + <div class="admin-command-metrics"> |
| 114 | + <article v-for="metric in adminCommandMetrics" :key="metric.label"> |
| 115 | + <span :class="['metric-icon', metric.tone]"> |
| 116 | + <component :is="metric.icon" :size="18" /> |
| 117 | + </span> |
| 118 | + <div> |
| 119 | + <strong>{{ metric.value }}</strong> |
| 120 | + <small>{{ metric.label }}</small> |
| 121 | + </div> |
| 122 | + </article> |
| 123 | + </div> |
| 124 | + </section> |
| 125 | + |
107 | 126 | <p v-if="errorMessage" class="workspace-error">{{ errorMessage }}</p> |
108 | 127 |
|
109 | 128 | <section v-if="activeView === 'builder'" class="builder-workspace"> |
@@ -966,6 +985,40 @@ const filteredUsers = computed(() => { |
966 | 985 | if (!query.value) return users.value; |
967 | 986 | return users.value.filter((row) => haystack(row).includes(query.value)); |
968 | 987 | }); |
| 988 | +const adminCommandTitle = computed(() => activeNav.value?.title || 'Admin workspace'); |
| 989 | +const adminCommandBody = computed(() => { |
| 990 | + if (activeView.value === 'tasks') return 'Review GitHub issues, inspect PRs, assign bounty credit, and keep payout proof aligned with the ledger.'; |
| 991 | + if (activeView.value === 'ledger') return 'Credit MRG, audit verified records, and switch between public references and hash evidence.'; |
| 992 | + if (activeView.value === 'users') return 'Inspect account activity, update roles, and keep admin access controlled from one panel.'; |
| 993 | + if (activeView.value === 'setting') return 'Tune review models, provider tokens, quotas, and webhook health for the automation layer.'; |
| 994 | + return 'Monitor funded work, task queues, SSL health, user activity, and payout records from one operations surface.'; |
| 995 | +}); |
| 996 | +const adminCommandMetrics = computed(() => [ |
| 997 | + { |
| 998 | + label: 'Visible tasks', |
| 999 | + value: number(filteredTasks.value.length), |
| 1000 | + icon: ListChecks, |
| 1001 | + tone: 'amber', |
| 1002 | + }, |
| 1003 | + { |
| 1004 | + label: 'Funded projects', |
| 1005 | + value: number(filteredProjects.value.length), |
| 1006 | + icon: FolderKanban, |
| 1007 | + tone: 'green', |
| 1008 | + }, |
| 1009 | + { |
| 1010 | + label: 'Ledger rows', |
| 1011 | + value: number(ledgerEntries.value.length), |
| 1012 | + icon: Activity, |
| 1013 | + tone: 'blue', |
| 1014 | + }, |
| 1015 | + { |
| 1016 | + label: 'SSL attention', |
| 1017 | + value: number(sslAttentionCount.value), |
| 1018 | + icon: ShieldCheck, |
| 1019 | + tone: sslAttentionCount.value ? 'amber' : 'green', |
| 1020 | + }, |
| 1021 | +]); |
969 | 1022 |
|
970 | 1023 | const TableHeader = defineComponent({ |
971 | 1024 | props: { |
|
0 commit comments