create-principles-disciple 1.145.34 → 1.145.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_release/product-identity.json +2 -2
- package/console/dist/server/models/ApprovalsConsoleModel.d.ts +22 -2
- package/console/dist/server/models/ApprovalsConsoleModel.js +56 -16
- package/console/dist/server/models/ApprovalsGroupedConsoleModel.d.ts +8 -0
- package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +3 -2
- package/console/dist/server/models/approval-review-material.d.ts +15 -0
- package/console/dist/server/models/approval-review-material.js +32 -0
- package/console/dist/server/routes/approvals.js +32 -7
- package/console/dist/ui/api.d.ts +8 -2
- package/console/dist/ui/api.js +8 -4
- package/console/dist/ui/i18n/en.json +98 -7
- package/console/dist/ui/i18n/zh-CN.json +98 -7
- package/console/dist/ui/pages/focus/ApprovalSubjectReading.d.ts +24 -0
- package/console/dist/ui/pages/focus/ApprovalSubjectReading.js +133 -0
- package/console/dist/ui/pages/focus/FocusPage.d.ts +5 -26
- package/console/dist/ui/pages/focus/FocusPage.js +166 -459
- package/console/dist/ui/pages/focus/OwnerWorkbench.d.ts +19 -0
- package/console/dist/ui/pages/focus/OwnerWorkbench.js +75 -0
- package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.d.ts +4 -1
- package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.js +7 -3
- package/console/dist/ui/pages/focus/focus-validation.js +31 -0
- package/console/dist/ui/pages/principles/PrincipleDetailPage.js +110 -86
- package/console/dist/ui/pages/principles/PrinciplesPage.js +39 -30
- package/console/dist/ui/utils/approval-review.d.ts +30 -0
- package/console/dist/ui/utils/approval-review.js +50 -0
- package/console/dist/ui/utils/reading-layout.d.ts +1 -0
- package/console/dist/ui/utils/reading-layout.js +1 -1
- package/console/dist/ui/utils/validators.d.ts +4 -0
- package/console/dist/ui/utils/validators.js +10 -2
- package/console/dist/web/assets/app.css +119 -11
- package/console/dist/web/assets/app.js +40 -30
- package/core/dist/runtime-v2/activation/activation-types.d.ts +12 -2
- package/core/dist/runtime-v2/activation/activation-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/activation-types.js.map +1 -1
- package/core/dist/runtime-v2/activation/approval-queue.d.ts +3 -2
- package/core/dist/runtime-v2/activation/approval-queue.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/approval-queue.js +6 -4
- package/core/dist/runtime-v2/activation/approval-queue.js.map +1 -1
- package/core/dist/runtime-v2/activation/approval-review-guard.d.ts +26 -0
- package/core/dist/runtime-v2/activation/approval-review-guard.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/approval-review-guard.js +25 -0
- package/core/dist/runtime-v2/activation/approval-review-guard.js.map +1 -0
- package/core/dist/runtime-v2/activation/memory-approval-store.d.ts +6 -2
- package/core/dist/runtime-v2/activation/memory-approval-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/memory-approval-store.js +26 -2
- package/core/dist/runtime-v2/activation/memory-approval-store.js.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-approval-store.d.ts +6 -2
- package/core/dist/runtime-v2/activation/sqlite-approval-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-approval-store.js +59 -2
- package/core/dist/runtime-v2/activation/sqlite-approval-store.js.map +1 -1
- package/core/dist/runtime-v2/diagnostician-association-shadow.d.ts +24 -0
- package/core/dist/runtime-v2/diagnostician-association-shadow.d.ts.map +1 -0
- package/core/dist/runtime-v2/diagnostician-association-shadow.js +84 -0
- package/core/dist/runtime-v2/diagnostician-association-shadow.js.map +1 -0
- package/core/dist/runtime-v2/diagnostician-association-validation.d.ts +18 -0
- package/core/dist/runtime-v2/diagnostician-association-validation.d.ts.map +1 -0
- package/core/dist/runtime-v2/diagnostician-association-validation.js +47 -0
- package/core/dist/runtime-v2/diagnostician-association-validation.js.map +1 -0
- package/core/dist/runtime-v2/diagnostician-output.d.ts +123 -0
- package/core/dist/runtime-v2/diagnostician-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/diagnostician-output.js +41 -0
- package/core/dist/runtime-v2/diagnostician-output.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +2 -0
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +1 -0
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.d.ts +12 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.js +50 -2
- package/core/dist/runtime-v2/internalization/diag-router-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/router-context-evidence.d.ts +45 -0
- package/core/dist/runtime-v2/internalization/router-context-evidence.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/router-context-evidence.js +64 -0
- package/core/dist/runtime-v2/internalization/router-context-evidence.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/types.d.ts +8 -0
- package/core/dist/runtime-v2/signal-collector/types.d.ts.map +1 -1
- package/core/dist/runtime-v2/signal-collector/types.js.map +1 -1
- package/core/package.json +1 -1
- package/package.json +2 -2
- package/pd-cli/dist/commands/config-doctor.js +1 -1
- package/pd-cli/dist/commands/config-doctor.js.map +1 -1
- package/pd-cli/dist/services/config-doctor.d.ts +2 -0
- package/pd-cli/dist/services/config-doctor.d.ts.map +1 -1
- package/pd-cli/dist/services/config-doctor.js +1 -0
- package/pd-cli/dist/services/config-doctor.js.map +1 -1
- package/pd-cli/package.json +1 -1
- package/plugin/dist/bundle.js +462 -462
- package/plugin/dist/core/signal-collector-host.d.ts +9 -0
- package/plugin/dist/core/signal-health.d.ts +6 -0
- package/plugin/dist/core/trajectory.d.ts +8 -0
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/dist/rulehost-evidence.js +6 -6
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/release-manager/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect, useCallback } from "react";
|
|
3
|
-
import {
|
|
2
|
+
import { useState, useEffect, useCallback, useRef } from "react";
|
|
3
|
+
import { Link, useSearchParams } from "react-router-dom";
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
5
|
import { PageShell } from "../../components/layout/page-shell.js";
|
|
6
6
|
import { SectionTitle } from "../../components/layout/section-title.js";
|
|
@@ -9,6 +9,7 @@ import { Skeleton } from "../../components/ui/skeleton.js";
|
|
|
9
9
|
import { ShinyText } from "../../components/ui/shiny-text.js";
|
|
10
10
|
import { fetchPrinciples, fetchApprovalsGrouped, fetchOwnerDecisionLibrary, } from "../../api.js";
|
|
11
11
|
import { enumLabel } from "../../utils/enum-labels.js";
|
|
12
|
+
import { splitReadingTitleBody, truncateByCodePoints } from "../../utils/reading-layout.js";
|
|
12
13
|
import { formatDate } from "../../utils/format-date.js";
|
|
13
14
|
import { PrinciplesViewNav } from "./PrinciplesViewNav.js";
|
|
14
15
|
// ── Map principle status to review status ───────────────────────────────────
|
|
@@ -140,7 +141,6 @@ function validateApprovalsGrouped(data) {
|
|
|
140
141
|
// ── Component ───────────────────────────────────────────────────────────────
|
|
141
142
|
export function PrinciplesPage() {
|
|
142
143
|
const { t, i18n } = useTranslation("pages");
|
|
143
|
-
const navigate = useNavigate();
|
|
144
144
|
const [principles, setPrinciples] = useState([]);
|
|
145
145
|
const [approvalGroups, setApprovalGroups] = useState([]);
|
|
146
146
|
const [loading, setLoading] = useState(true);
|
|
@@ -148,20 +148,29 @@ export function PrinciplesPage() {
|
|
|
148
148
|
// PRI-558: summary powers the metrics bar (already returned by /api/principles)
|
|
149
149
|
const [summary, setSummary] = useState(null);
|
|
150
150
|
// Search / filter / sort
|
|
151
|
-
const [
|
|
152
|
-
const
|
|
153
|
-
const
|
|
151
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
152
|
+
const updateQuery = (key, value) => { const next = new URLSearchParams(searchParams); next.set(key, value); setSearchParams(next, { replace: true, preventScrollReset: true }); };
|
|
153
|
+
const search = searchParams.get('q') ?? '';
|
|
154
|
+
const setSearch = (value) => updateQuery('q', value);
|
|
155
|
+
const statusParam = searchParams.get('status');
|
|
156
|
+
const statusFilter = statusParam === 'pending' || statusParam === 'candidate' || statusParam === 'approved' || statusParam === 'rejected' || statusParam === 'parked' ? statusParam : 'all';
|
|
157
|
+
const setStatusFilter = (value) => updateQuery('status', value);
|
|
158
|
+
const sortBy = searchParams.get('sort') === 'createdAt' ? 'createdAt' : 'updatedAt';
|
|
159
|
+
const setSortBy = (value) => updateQuery('sort', value);
|
|
154
160
|
// PRI-629 (INV-02): 默认展示全部 — candidate 是生命周期而非待办,
|
|
155
161
|
// "只看待决策"不再作为默认视图 (真实决策在治理焦点)。
|
|
156
|
-
const
|
|
162
|
+
const filterMode = searchParams.get('mode') === 'actionable' ? 'actionable' : 'all';
|
|
163
|
+
const setFilterMode = (value) => updateQuery('mode', value);
|
|
157
164
|
const [categories, setCategories] = useState();
|
|
158
165
|
// Owner Decision Experience v1: backend semantic titles + decision states
|
|
159
166
|
// (display-only — the page never re-derives decision qualification).
|
|
160
167
|
const [ownerDecisionLibrary, setOwnerDecisionLibrary] = useState(null);
|
|
161
168
|
// PRI-956 (F15, D3): runtime status cannot be confirmed when set
|
|
162
169
|
const [revocationUnavailable, setRevocationUnavailable] = useState(null);
|
|
170
|
+
const requestEpoch = useRef(0);
|
|
163
171
|
// Fetch data
|
|
164
172
|
const loadData = useCallback(async () => {
|
|
173
|
+
const epoch = ++requestEpoch.current;
|
|
165
174
|
setLoading(true);
|
|
166
175
|
setError(null);
|
|
167
176
|
try {
|
|
@@ -170,6 +179,8 @@ export function PrinciplesPage() {
|
|
|
170
179
|
fetchApprovalsGrouped(),
|
|
171
180
|
fetchOwnerDecisionLibrary(),
|
|
172
181
|
]);
|
|
182
|
+
if (epoch !== requestEpoch.current)
|
|
183
|
+
return;
|
|
173
184
|
setOwnerDecisionLibrary(dResult.success && dResult.data ? dResult.data : null);
|
|
174
185
|
if (!pResult.success) {
|
|
175
186
|
setError(pResult.error ?? "Failed to load principles");
|
|
@@ -191,14 +202,18 @@ export function PrinciplesPage() {
|
|
|
191
202
|
setApprovalGroups(aData?.groups ?? []);
|
|
192
203
|
}
|
|
193
204
|
catch (err) {
|
|
205
|
+
if (epoch !== requestEpoch.current)
|
|
206
|
+
return;
|
|
194
207
|
setError(err instanceof Error ? err.message : "Unknown error");
|
|
195
208
|
}
|
|
196
209
|
finally {
|
|
197
|
-
|
|
210
|
+
if (epoch === requestEpoch.current)
|
|
211
|
+
setLoading(false);
|
|
198
212
|
}
|
|
199
213
|
}, [filterMode]);
|
|
200
214
|
useEffect(() => {
|
|
201
|
-
loadData();
|
|
215
|
+
void loadData();
|
|
216
|
+
return () => { requestEpoch.current++; };
|
|
202
217
|
}, [loadData]);
|
|
203
218
|
// Build approval lookup
|
|
204
219
|
const approvalByPrinciple = new Map();
|
|
@@ -219,7 +234,7 @@ export function PrinciplesPage() {
|
|
|
219
234
|
const decision = ownerDecisionLibrary?.entries[p.id];
|
|
220
235
|
const semanticTitle = decision?.learnedPrinciple.status === 'known' ? decision.learnedPrinciple.text : undefined;
|
|
221
236
|
// PRI-332: Determine display title with bounded fallback for unreadable titles
|
|
222
|
-
const rawTitle = p.triggerPattern || p.text
|
|
237
|
+
const rawTitle = p.triggerPattern || truncateByCodePoints(p.text, 80);
|
|
223
238
|
const detectedLang = p.detectedLanguage ?? 'unknown';
|
|
224
239
|
const readWarningCode = p.readabilityWarningCode;
|
|
225
240
|
let displayTitle = rawTitle;
|
|
@@ -236,7 +251,8 @@ export function PrinciplesPage() {
|
|
|
236
251
|
}
|
|
237
252
|
return {
|
|
238
253
|
principleId: p.id,
|
|
239
|
-
title: displayTitle,
|
|
254
|
+
title: splitReadingTitleBody(displayTitle).title,
|
|
255
|
+
searchText: semanticTitle ?? rawTitle,
|
|
240
256
|
originalTitle: rawTitle,
|
|
241
257
|
titleUsedFallback: usedFallback,
|
|
242
258
|
text: p.text,
|
|
@@ -260,7 +276,7 @@ export function PrinciplesPage() {
|
|
|
260
276
|
return false;
|
|
261
277
|
if (search) {
|
|
262
278
|
const q = search.toLowerCase();
|
|
263
|
-
if (!c.text.toLowerCase().includes(q) && !c.title.toLowerCase().includes(q))
|
|
279
|
+
if (!c.text.toLowerCase().includes(q) && !c.title.toLowerCase().includes(q) && !c.searchText.toLowerCase().includes(q))
|
|
264
280
|
return false;
|
|
265
281
|
}
|
|
266
282
|
return true;
|
|
@@ -287,32 +303,25 @@ export function PrinciplesPage() {
|
|
|
287
303
|
: "bg-surface text-ink-3 border-line hover:border-line-2"), children: [t("principles.filterAll", { defaultValue: "Show All" }), categories ? ` (${Object.values(categories).reduce((a, b) => a + b, 0)})` : ''] })] }), _jsx("input", { type: "text", value: search, onChange: (e) => setSearch(e.target.value), placeholder: t("principles.searchPlaceholder"), className: "flex-1 min-w-[200px] border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", "aria-label": t("principles.searchPlaceholder") }), _jsx("div", { className: "flex gap-1", role: "group", "aria-label": "Status filter", children: statusFilters.map((sf) => (_jsx("button", { onClick: () => setStatusFilter(sf.value), className: "font-mono text-[11px] uppercase tracking-[0.02em] border rounded-[2px] px-2 py-1 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov " +
|
|
288
304
|
(statusFilter === sf.value
|
|
289
305
|
? "bg-gov text-paper border-gov"
|
|
290
|
-
: "bg-surface text-ink-3 border-line hover:border-line-2"), children: sf.label }, sf.value))) }), _jsxs("select", { value: sortBy, onChange: (e) => setSortBy(e.target.value), className: "border border-line rounded-[var(--radius-md)] bg-surface text-ink-3 px-2 py-1 text-[12px] font-mono focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", "aria-label": "Sort order", children: [_jsx("option", { value: "updatedAt", children: t("principles.sortByUpdated") }), _jsx("option", { value: "createdAt", children: t("principles.sortByCreated") })] })] }), !loading && !error && summary && (_jsxs("div", { className: "flex flex-wrap border border-line rounded-[var(--radius-md)] bg-panel overflow-hidden
|
|
306
|
+
: "bg-surface text-ink-3 border-line hover:border-line-2"), children: sf.label }, sf.value))) }), _jsxs("select", { value: sortBy, onChange: (e) => setSortBy(e.target.value), className: "border border-line rounded-[var(--radius-md)] bg-surface text-ink-3 px-2 py-1 text-[12px] font-mono focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", "aria-label": "Sort order", children: [_jsx("option", { value: "updatedAt", children: t("principles.sortByUpdated") }), _jsx("option", { value: "createdAt", children: t("principles.sortByCreated") })] })] }), !loading && !error && summary && (_jsxs("details", { className: "mb-6 text-[12px] text-ink-3", "data-testid": "principle-library-overview", children: [_jsx("summary", { className: "cursor-pointer text-gov", children: t('principles.libraryOverview') }), _jsxs("div", { className: "mt-3 flex flex-wrap border border-line rounded-[var(--radius-md)] bg-panel overflow-hidden", children: [_jsx(Metric, { num: String(summary.total), label: t("principles.metricDeposited") }), _jsx(Metric, { num: String(summary.active), label: t("principles.metricActive") }), _jsx(Metric, { num: latestUpdatedAt ? formatDate(latestUpdatedAt, i18n.language) : "—", label: t("principles.metricLatest") })] })] })), loading && (_jsx("div", { className: "grid gap-3 animate-[pdFadeIn_200ms_ease-out]", role: "status", "aria-live": "polite", "aria-label": t("principles.loading", { defaultValue: "Loading…" }), children: Array.from({ length: 4 }).map((_, i) => (_jsxs("div", { className: "bg-panel border border-line rounded-[var(--radius-md)] p-4 border-l-[3px] border-l-transparent", children: [_jsxs("div", { className: "flex items-start justify-between gap-3 mb-3", children: [_jsx(Skeleton, { className: "h-5 w-[55%] rounded-sm" }), _jsx(Skeleton, { className: "h-5 w-16 rounded-[2px]" })] }), _jsx(Skeleton, { className: "h-4 w-full rounded-sm mb-2" }), _jsx(Skeleton, { className: "h-4 w-[80%] rounded-sm mb-4" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Skeleton, { className: "h-3.5 w-20 rounded-sm" }), _jsx(Skeleton, { className: "h-3.5 w-24 rounded-sm" })] })] }, i))) })), error && (_jsxs("div", { className: "border border-danger/30 rounded-[var(--radius-md)] p-4 mb-4", children: [_jsx("p", { className: "text-danger text-sm", children: error }), _jsx(Button, { variant: "outline", size: "sm", onClick: loadData, className: "mt-2", children: t("principles.retry", { defaultValue: "Retry" }) })] })), !loading && !error && filtered.length === 0 && principles.length === 0 && (_jsxs("div", { className: "text-center py-12", children: [_jsx("h2", { className: "text-ink-2 text-lg font-semibold mb-2", children: t("principles.emptyTitle") }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[480px] mx-auto leading-relaxed", children: filterMode === 'actionable'
|
|
291
307
|
? t("principles.emptyActionable", { defaultValue: "No owner-actionable principles at this time. When PD captures behavior deviation signals, principle candidates will appear here for your review." })
|
|
292
308
|
: t("principles.emptyDescription") }), categories && filterMode === 'actionable' && (_jsx("div", { className: "flex justify-center gap-2 flex-wrap mt-4", children: Object.entries(categories).map(([cat, count]) => (_jsxs("span", { className: "font-mono text-[11px] uppercase tracking-[0.02em] border border-line rounded-[2px] px-2 py-0.5 text-ink-4", children: [cat, ": ", count] }, cat))) }))] })), !loading && !error && filtered.length === 0 && principles.length > 0 && (_jsx("p", { className: "text-ink-3 text-sm", children: t("principles.noResults") })), !loading && !error && filtered.length > 0 && (_jsxs("div", { className: "relative pl-6 grid gap-3 animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("span", { className: "absolute left-[12.5px] top-3 bottom-3 w-px bg-line", "aria-hidden": "true" }), filtered.map((card) => {
|
|
293
309
|
const ag = approvalByPrinciple.get(card.principleId);
|
|
294
310
|
const decision = GOV_DECISION[card.status];
|
|
295
311
|
const decisionRecord = ag?.records?.find((r) => r.status === ag.status) ?? ag?.records?.[0];
|
|
296
312
|
const decisionDate = decisionRecord?.createdAt;
|
|
297
|
-
return (_jsxs("article", {
|
|
313
|
+
return (_jsxs("article", { className: "relative bg-panel border border-line rounded-[var(--radius-md)] p-5 " +
|
|
298
314
|
"border-l-[3px] " +
|
|
299
315
|
STATUS_BORDER[card.status] + " " +
|
|
300
316
|
"transition-[border-color,background,transform] duration-150 " +
|
|
301
|
-
"hover:border-line-2
|
|
302
|
-
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov",
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
" border-current/20", children: t("principles.status" + card.status.charAt(0).toUpperCase() + card.status.slice(1)) }), card.channels.map((ch) => (_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.02em] border border-line rounded-[2px] px-2 py-0.5 text-ink-3", children: enumLabel('channel', ch, t) }, ch))), card.detectedLanguage && card.detectedLanguage !== 'unknown' && (_jsx("span", { className: "font-mono text-[11px] tracking-[0.02em] border border-line rounded-[2px] px-2 py-0.5 text-ink-4", children: card.detectedLanguage === 'zh'
|
|
311
|
-
? t("principles.languageHintZh")
|
|
312
|
-
: t("principles.languageHintEn") })), _jsxs("span", { className: "font-mono text-[11px] text-ink-4", children: [t("principles.evaluabilityLabel", { defaultValue: "可评价性" }), ": ", enumLabel('evaluability', card.evaluability, t)] }), card.decisionState !== undefined && (_jsx("span", { className: "font-mono text-[11px] tracking-[0.02em] border border-line rounded-[2px] px-2 py-0.5 text-ink-4", children: t(`principles.ownerDecision.state.${card.decisionState}`, { defaultValue: card.decisionState }) }))] }), card.readabilityWarningCode && (_jsx("div", { className: "mb-2 px-3 py-1.5 bg-amber/5 border border-amber/20 rounded-[3px] text-ink-3 text-[12px] leading-snug", children: t("principles.readabilityWarning." + card.readabilityWarningCode, { defaultValue: t("principles.readabilityFallbackTitle") }) })), card.detectedLanguage && card.detectedLanguage !== 'unknown' && i18n.language && !i18n.language.startsWith(card.detectedLanguage) && (_jsx("div", { className: "mb-2 px-3 py-1.5 bg-surface/60 border-l-2 border-line rounded-[3px] text-ink-4 text-[12px] leading-snug", children: t("principles.languageMismatchHint", { lang: card.detectedLanguage === 'en' ? 'English' : '中文' }) })), _jsx("h3", { className: "font-semibold text-ink mb-1", children: card.title }), card.titleUsedFallback && card.originalTitle && (_jsxs("details", { className: "mb-1", children: [_jsx("summary", { className: "text-ink-4 text-[11px] font-mono cursor-pointer hover:underline", children: t("principles.readabilityOriginalLabel") }), _jsx("div", { className: "text-ink-4 text-[12px] leading-snug mt-1 font-mono bg-surface/40 px-2 py-1 rounded-[3px] break-all", children: card.originalTitle })] })), _jsx("p", { className: "text-ink-3 text-[13px] line-clamp-3 leading-relaxed", children: card.text }), _jsxs("p", { className: "font-mono text-[11px] text-ink-4 mt-2", children: [t("principles.updatedAt"), ": ", formatDate(card.updatedAt, i18n.language)] }), _jsx(EvolutionBlock, { label: t("principles.blockBasis"), children: t("principles.blockBasisFallback") }), _jsx(EvolutionBlock, { label: t("principles.blockImpact"), children: card.decisionState !== undefined
|
|
313
|
-
? t("principles.blockImpactSeeDecisionView", { defaultValue: "以详情页「当前实际执行」为准(本卡片不据此判断影响)。" })
|
|
314
|
-
: t(BLOCK_IMPACT_KEY[card.status]) }), _jsx(EvolutionBlock, { label: t("principles.blockBehavior"), children: card.action ? card.action : t("principles.blockBehaviorFallback") }), _jsx("div", { className: "mt-3 pt-3 border-t border-line/60", children: _jsxs("div", { className: "flex items-center justify-between gap-3 bg-gov/5 border border-line rounded-[3px] px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.02em] text-ink-4", children: t("principles.govDecision") }), _jsxs("span", { className: "font-mono text-[11px] uppercase tracking-[0.02em] border rounded-[2px] px-2 py-0.5 " +
|
|
315
|
-
STATUS_TEXT[card.status] +
|
|
316
|
-
" border-current/20", children: [decision.glyph, " ", t(decision.labelKey)] }), card.runtimeDeactivated === true && (_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.02em] border rounded-[2px] px-2 py-0.5 border-amber-300 text-amber-700 bg-amber-50", children: t("principles.runtimeDeactivated") }))] }), decisionDate && (_jsx("span", { className: "font-mono text-[11px] text-ink-4 whitespace-nowrap", children: formatDate(decisionDate, i18n.language) }))] }) })] }, card.principleId));
|
|
317
|
+
"hover:border-line-2 " +
|
|
318
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", children: [_jsx("span", { className: "absolute -left-[19px] top-4 h-2.5 w-2.5 rounded-full border-2 border-paper " +
|
|
319
|
+
STATUS_DOT_BG[card.status], "aria-hidden": "true" }), _jsxs("div", { className: "mb-2 flex flex-wrap items-start justify-between gap-3", children: [_jsx("h3", { className: "min-w-0 flex-1 text-[15px] font-semibold leading-relaxed text-ink", children: _jsx(Link, { className: "rounded-sm hover:text-gov focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", to: `/principles/${card.principleId}`, state: { returnTo: `/principles?${searchParams}` }, children: card.title }) }), _jsx("span", { className: `rounded-[2px] border px-2 py-1 text-[11px] ${STATUS_TEXT[card.status]}`, children: card.decisionState !== undefined ? t(`principles.ownerDecision.state.${card.decisionState}`, { defaultValue: card.decisionState }) : t(decision.labelKey) })] }), card.readabilityWarningCode && (_jsx("div", { className: "mb-2 px-3 py-1.5 bg-amber/5 border border-amber/20 rounded-[3px] text-ink-3 text-[12px] leading-snug", children: t("principles.readabilityWarning." + card.readabilityWarningCode, { defaultValue: t("principles.readabilityFallbackTitle") }) })), card.text.trim() !== card.title.trim() && _jsx("p", { className: "text-ink-3 text-[13px] line-clamp-2 leading-relaxed", children: card.text }), card.runtimeDeactivated === true && _jsx("p", { className: "mt-3 text-[12px] text-amber", role: "status", children: t('principles.runtimeDeactivated') }), _jsxs("details", { className: "mt-4 border-t border-line/60 pt-3", "data-testid": "principle-context-disclosure", children: [_jsx("summary", { className: "cursor-pointer text-[12px] text-gov", children: t('principles.contextDisclosure') }), _jsxs("div", { className: "mt-4 space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2 mb-2 flex-wrap", children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.02em] border rounded-[2px] px-2 py-0.5 " +
|
|
320
|
+
STATUS_TEXT[card.status] +
|
|
321
|
+
" border-current/20", children: t("principles.status" + card.status.charAt(0).toUpperCase() + card.status.slice(1)) }), card.channels.map((ch) => (_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.02em] border border-line rounded-[2px] px-2 py-0.5 text-ink-3", children: enumLabel('channel', ch, t) }, ch))), card.detectedLanguage && card.detectedLanguage !== 'unknown' && (_jsx("span", { className: "font-mono text-[11px] tracking-[0.02em] border border-line rounded-[2px] px-2 py-0.5 text-ink-4", children: card.detectedLanguage === 'zh'
|
|
322
|
+
? t("principles.languageHintZh")
|
|
323
|
+
: t("principles.languageHintEn") })), _jsxs("span", { className: "font-mono text-[11px] text-ink-4", children: [t("principles.evaluabilityLabel", { defaultValue: "可评价性" }), ": ", enumLabel('evaluability', card.evaluability, t)] }), card.decisionState !== undefined && (_jsx("span", { className: "font-mono text-[11px] tracking-[0.02em] border border-line rounded-[2px] px-2 py-0.5 text-ink-4", children: t(`principles.ownerDecision.state.${card.decisionState}`, { defaultValue: card.decisionState }) }))] }), card.detectedLanguage && card.detectedLanguage !== 'unknown' && i18n.language && !i18n.language.startsWith(card.detectedLanguage) && (_jsx("div", { className: "mb-2 px-3 py-1.5 bg-surface/60 border-l-2 border-line rounded-[3px] text-ink-4 text-[12px] leading-snug", children: t("principles.languageMismatchHint", { lang: card.detectedLanguage === 'en' ? 'English' : '中文' }) })), card.titleUsedFallback && card.originalTitle && (_jsxs("details", { className: "mb-1", children: [_jsx("summary", { className: "text-ink-4 text-[11px] font-mono cursor-pointer hover:underline", children: t("principles.readabilityOriginalLabel") }), _jsx("div", { className: "text-ink-4 text-[12px] leading-snug mt-1 font-mono bg-surface/40 px-2 py-1 rounded-[3px] break-all", children: card.originalTitle })] })), _jsxs("p", { className: "font-mono text-[11px] text-ink-4 mt-2", children: [t("principles.updatedAt"), ": ", formatDate(card.updatedAt, i18n.language)] }), _jsx(EvolutionBlock, { label: t("principles.blockBasis"), children: t("principles.blockBasisFallback") }), _jsx(EvolutionBlock, { label: t("principles.blockImpact"), children: card.decisionState !== undefined
|
|
324
|
+
? t("principles.blockImpactSeeDecisionView", { defaultValue: "以详情页「当前实际执行」为准(本卡片不据此判断影响)。" })
|
|
325
|
+
: t(BLOCK_IMPACT_KEY[card.status]) }), _jsx(EvolutionBlock, { label: t("principles.blockBehavior"), children: card.action ? card.action : t("principles.blockBehaviorFallback") }), decisionDate && _jsxs("p", { className: "text-[11px] text-ink-4", children: [t('principles.govDecision'), ": ", formatDate(decisionDate, i18n.language)] })] })] }), _jsx(Link, { className: "mt-3 inline-block text-[12px] text-gov underline underline-offset-4", to: `/principles/${card.principleId}`, state: { returnTo: `/principles?${searchParams}` }, children: t('principles.openDetails') })] }, card.principleId));
|
|
317
326
|
})] }))] }));
|
|
318
327
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ApprovalRecordData } from './validators.js';
|
|
2
|
+
export type ApprovalReviewGuard = {
|
|
3
|
+
schemaVersion: 'approval-review-v1';
|
|
4
|
+
approvalId: string;
|
|
5
|
+
artifactId: string;
|
|
6
|
+
channel: 'prompt' | 'code_tool_hook' | 'defer_archive';
|
|
7
|
+
} & ({
|
|
8
|
+
artifactState: 'present';
|
|
9
|
+
artifactDigest: string;
|
|
10
|
+
} | {
|
|
11
|
+
artifactState: 'missing';
|
|
12
|
+
});
|
|
13
|
+
export interface ApprovalReviewData {
|
|
14
|
+
approval: ApprovalRecordData;
|
|
15
|
+
expectedReview: ApprovalReviewGuard;
|
|
16
|
+
material: {
|
|
17
|
+
availability: 'available' | 'missing' | 'unreadable';
|
|
18
|
+
artifactId: string;
|
|
19
|
+
statement: string | null;
|
|
20
|
+
rationale: string | null;
|
|
21
|
+
targetBehavior: string | null;
|
|
22
|
+
scope: string[];
|
|
23
|
+
risks: string[] | null;
|
|
24
|
+
exactBody: {
|
|
25
|
+
kind: 'principle' | 'rule_code';
|
|
26
|
+
text: string;
|
|
27
|
+
} | null;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare function validateApprovalReview(value: unknown): ApprovalReviewData | null;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { validateApprovalRecordDirect } from './validators.js';
|
|
2
|
+
function record(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }
|
|
3
|
+
export function validateApprovalReview(value) {
|
|
4
|
+
if (!record(value) || value.writeGuardVersion !== 'approval-review-v1' || !record(value.review))
|
|
5
|
+
return null;
|
|
6
|
+
const approval = validateApprovalRecordDirect(value);
|
|
7
|
+
const guard = value.review.expectedReview;
|
|
8
|
+
const { material } = value.review;
|
|
9
|
+
if (!approval || !record(guard) || guard.schemaVersion !== 'approval-review-v1' || guard.approvalId !== approval.approvalId
|
|
10
|
+
|| guard.artifactId !== approval.artifactId || guard.channel !== approval.channel
|
|
11
|
+
|| !['prompt', 'code_tool_hook', 'defer_archive'].includes(String(guard.channel))
|
|
12
|
+
|| (guard.artifactState !== 'present' && guard.artifactState !== 'missing')
|
|
13
|
+
|| (guard.artifactState === 'present' && (typeof guard.artifactDigest !== 'string' || !/^sha256:[a-f0-9]{64}$/.test(guard.artifactDigest)))
|
|
14
|
+
|| !record(material) || material.artifactId !== approval.artifactId
|
|
15
|
+
|| !['available', 'missing', 'unreadable'].includes(String(material.availability))
|
|
16
|
+
|| (material.statement !== null && typeof material.statement !== 'string')
|
|
17
|
+
|| (material.rationale !== null && typeof material.rationale !== 'string')
|
|
18
|
+
|| (material.targetBehavior !== null && typeof material.targetBehavior !== 'string')
|
|
19
|
+
|| !Array.isArray(material.scope) || !material.scope.every(item => typeof item === 'string')
|
|
20
|
+
|| (material.risks !== null && (!Array.isArray(material.risks) || !material.risks.every(item => typeof item === 'string'))))
|
|
21
|
+
return null;
|
|
22
|
+
if (guard.artifactState === 'missing' && (material.availability !== 'missing' || material.exactBody !== null || material.statement !== null || Object.hasOwn(guard, 'artifactDigest')))
|
|
23
|
+
return null;
|
|
24
|
+
if (guard.artifactState === 'present' && material.availability === 'missing')
|
|
25
|
+
return null;
|
|
26
|
+
const body = material.exactBody;
|
|
27
|
+
let exactBody = null;
|
|
28
|
+
if (body !== null) {
|
|
29
|
+
if (!record(body) || (body.kind !== 'principle' && body.kind !== 'rule_code') || typeof body.text !== 'string')
|
|
30
|
+
return null;
|
|
31
|
+
exactBody = { kind: body.kind, text: body.text };
|
|
32
|
+
}
|
|
33
|
+
const { channel } = guard;
|
|
34
|
+
if (channel !== 'prompt' && channel !== 'code_tool_hook' && channel !== 'defer_archive')
|
|
35
|
+
return null;
|
|
36
|
+
// The reader treats a material body as present exactly when availability says so;
|
|
37
|
+
// a payload that disagrees must fail loud rather than render the wrong preview.
|
|
38
|
+
if ((material.availability === 'available') !== (exactBody !== null))
|
|
39
|
+
return null;
|
|
40
|
+
if (exactBody !== null && (channel === 'code_tool_hook') !== (exactBody.kind === 'rule_code'))
|
|
41
|
+
return null;
|
|
42
|
+
const expectedReview = guard.artifactState === 'present' && typeof guard.artifactDigest === 'string'
|
|
43
|
+
? { schemaVersion: 'approval-review-v1', approvalId: approval.approvalId, artifactId: approval.artifactId, channel, artifactState: 'present', artifactDigest: guard.artifactDigest }
|
|
44
|
+
: { schemaVersion: 'approval-review-v1', approvalId: approval.approvalId, artifactId: approval.artifactId, channel, artifactState: 'missing' };
|
|
45
|
+
const { availability } = material;
|
|
46
|
+
if (availability !== 'available' && availability !== 'missing' && availability !== 'unreadable')
|
|
47
|
+
return null;
|
|
48
|
+
return { approval, expectedReview, material: { availability, artifactId: approval.artifactId, statement: material.statement,
|
|
49
|
+
rationale: material.rationale, targetBehavior: material.targetBehavior, scope: material.scope, risks: material.risks, exactBody } };
|
|
50
|
+
}
|
|
@@ -16,4 +16,5 @@ export interface ReadingLayout {
|
|
|
16
16
|
/** 逐字全文。null 表示原文即短标题、已由 title 完整承载(不重复渲染)。 */
|
|
17
17
|
body: string | null;
|
|
18
18
|
}
|
|
19
|
+
export declare function truncateByCodePoints(text: string, max: number): string;
|
|
19
20
|
export declare function splitReadingTitleBody(text: string | null | undefined): ReadingLayout;
|
|
@@ -637,6 +637,8 @@ export interface ApprovalGroupRecordData {
|
|
|
637
637
|
channel: string;
|
|
638
638
|
createdAt: string;
|
|
639
639
|
status: string;
|
|
640
|
+
/** This record's own revision review is incomplete; absent = no such defect. */
|
|
641
|
+
revisionReviewUnavailable?: boolean;
|
|
640
642
|
}
|
|
641
643
|
export interface ApprovalGroupData {
|
|
642
644
|
principleId: string;
|
|
@@ -650,6 +652,8 @@ export interface ApprovalGroupData {
|
|
|
650
652
|
*/
|
|
651
653
|
revisionReviewUnavailable?: boolean;
|
|
652
654
|
revisionReview?: {
|
|
655
|
+
artifactId?: string;
|
|
656
|
+
artifactDigest?: string;
|
|
653
657
|
oldStatement: string;
|
|
654
658
|
newStatement: string;
|
|
655
659
|
intentFields: Record<string, string>;
|
|
@@ -1740,7 +1740,13 @@ function validateApprovalGroupRecord(v) {
|
|
|
1740
1740
|
return null;
|
|
1741
1741
|
if (!Object.hasOwn(v, 'status') || !isString(v.status))
|
|
1742
1742
|
return null;
|
|
1743
|
-
|
|
1743
|
+
const record = { id: v.id, artifactId: v.artifactId, channel: v.channel, createdAt: v.createdAt, status: v.status };
|
|
1744
|
+
if (Object.hasOwn(v, 'revisionReviewUnavailable')) {
|
|
1745
|
+
if (typeof v.revisionReviewUnavailable !== 'boolean')
|
|
1746
|
+
return null;
|
|
1747
|
+
record.revisionReviewUnavailable = v.revisionReviewUnavailable;
|
|
1748
|
+
}
|
|
1749
|
+
return record;
|
|
1744
1750
|
}
|
|
1745
1751
|
function validateApprovalGroup(v) {
|
|
1746
1752
|
if (!isObject(v))
|
|
@@ -1774,7 +1780,9 @@ function validateApprovalGroup(v) {
|
|
|
1774
1780
|
if (typeof value === 'string')
|
|
1775
1781
|
intentFields[key] = value;
|
|
1776
1782
|
}
|
|
1777
|
-
result.revisionReview = { oldStatement: review.oldStatement, newStatement: review.newStatement, intentFields
|
|
1783
|
+
result.revisionReview = { oldStatement: review.oldStatement, newStatement: review.newStatement, intentFields,
|
|
1784
|
+
...(typeof review.artifactId === 'string' ? { artifactId: review.artifactId } : {}),
|
|
1785
|
+
...(typeof review.artifactDigest === 'string' && /^sha256:[a-f0-9]{64}$/.test(review.artifactDigest) ? { artifactDigest: review.artifactDigest } : {}) };
|
|
1778
1786
|
}
|
|
1779
1787
|
// Wave 7: optional candidateDescription from artifact contentJson
|
|
1780
1788
|
if (Object.hasOwn(v, 'candidateDescription') && isString(v.candidateDescription) && v.candidateDescription.length > 0) {
|
|
@@ -434,6 +434,9 @@
|
|
|
434
434
|
.mt-6 {
|
|
435
435
|
margin-top: calc(var(--spacing) * 6);
|
|
436
436
|
}
|
|
437
|
+
.mt-7 {
|
|
438
|
+
margin-top: calc(var(--spacing) * 7);
|
|
439
|
+
}
|
|
437
440
|
.mt-8 {
|
|
438
441
|
margin-top: calc(var(--spacing) * 8);
|
|
439
442
|
}
|
|
@@ -530,11 +533,11 @@
|
|
|
530
533
|
.ml-auto {
|
|
531
534
|
margin-left: auto;
|
|
532
535
|
}
|
|
533
|
-
.line-clamp-
|
|
536
|
+
.line-clamp-2 {
|
|
534
537
|
overflow: hidden;
|
|
535
538
|
display: -webkit-box;
|
|
536
539
|
-webkit-box-orient: vertical;
|
|
537
|
-
-webkit-line-clamp:
|
|
540
|
+
-webkit-line-clamp: 2;
|
|
538
541
|
}
|
|
539
542
|
.block {
|
|
540
543
|
display: block;
|
|
@@ -644,9 +647,6 @@
|
|
|
644
647
|
.h-screen {
|
|
645
648
|
height: 100vh;
|
|
646
649
|
}
|
|
647
|
-
.max-h-32 {
|
|
648
|
-
max-height: calc(var(--spacing) * 32);
|
|
649
|
-
}
|
|
650
650
|
.max-h-40 {
|
|
651
651
|
max-height: calc(var(--spacing) * 40);
|
|
652
652
|
}
|
|
@@ -801,6 +801,9 @@
|
|
|
801
801
|
.max-w-\[400px\] {
|
|
802
802
|
max-width: 400px;
|
|
803
803
|
}
|
|
804
|
+
.max-w-\[440px\] {
|
|
805
|
+
max-width: 440px;
|
|
806
|
+
}
|
|
804
807
|
.max-w-\[480px\] {
|
|
805
808
|
max-width: 480px;
|
|
806
809
|
}
|
|
@@ -816,6 +819,12 @@
|
|
|
816
819
|
.max-w-\[760px\] {
|
|
817
820
|
max-width: 760px;
|
|
818
821
|
}
|
|
822
|
+
.max-w-\[1120px\] {
|
|
823
|
+
max-width: 1120px;
|
|
824
|
+
}
|
|
825
|
+
.max-w-full {
|
|
826
|
+
max-width: 100%;
|
|
827
|
+
}
|
|
819
828
|
.max-w-lg {
|
|
820
829
|
max-width: var(--container-lg);
|
|
821
830
|
}
|
|
@@ -1079,6 +1088,11 @@
|
|
|
1079
1088
|
margin-block-start: calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));
|
|
1080
1089
|
margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)));
|
|
1081
1090
|
}
|
|
1091
|
+
:where(.space-y-7 > :not(:last-child)) {
|
|
1092
|
+
--tw-space-y-reverse: 0;
|
|
1093
|
+
margin-block-start: calc(calc(var(--spacing) * 7) * var(--tw-space-y-reverse));
|
|
1094
|
+
margin-block-end: calc(calc(var(--spacing) * 7) * calc(1 - var(--tw-space-y-reverse)));
|
|
1095
|
+
}
|
|
1082
1096
|
:where(.space-y-8 > :not(:last-child)) {
|
|
1083
1097
|
--tw-space-y-reverse: 0;
|
|
1084
1098
|
margin-block-start: calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));
|
|
@@ -1396,6 +1410,12 @@
|
|
|
1396
1410
|
border-color: color-mix(in oklab, var(--color-green) 40%, transparent);
|
|
1397
1411
|
}
|
|
1398
1412
|
}
|
|
1413
|
+
.border-ink-3\/30 {
|
|
1414
|
+
border-color: color-mix(in srgb, #525966 30%, transparent);
|
|
1415
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1416
|
+
border-color: color-mix(in oklab, var(--color-ink-3) 30%, transparent);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1399
1419
|
.border-ink-4 {
|
|
1400
1420
|
border-color: var(--color-ink-4);
|
|
1401
1421
|
}
|
|
@@ -1576,6 +1596,12 @@
|
|
|
1576
1596
|
.bg-ink-3 {
|
|
1577
1597
|
background-color: var(--color-ink-3);
|
|
1578
1598
|
}
|
|
1599
|
+
.bg-ink-3\/10 {
|
|
1600
|
+
background-color: color-mix(in srgb, #525966 10%, transparent);
|
|
1601
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1602
|
+
background-color: color-mix(in oklab, var(--color-ink-3) 10%, transparent);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1579
1605
|
.bg-ink-4 {
|
|
1580
1606
|
background-color: var(--color-ink-4);
|
|
1581
1607
|
}
|
|
@@ -1798,6 +1824,9 @@
|
|
|
1798
1824
|
.py-8 {
|
|
1799
1825
|
padding-block: calc(var(--spacing) * 8);
|
|
1800
1826
|
}
|
|
1827
|
+
.py-10 {
|
|
1828
|
+
padding-block: calc(var(--spacing) * 10);
|
|
1829
|
+
}
|
|
1801
1830
|
.py-12 {
|
|
1802
1831
|
padding-block: calc(var(--spacing) * 12);
|
|
1803
1832
|
}
|
|
@@ -2033,6 +2062,10 @@
|
|
|
2033
2062
|
--tw-leading: 1.62;
|
|
2034
2063
|
line-height: 1.62;
|
|
2035
2064
|
}
|
|
2065
|
+
.leading-\[1\.85\] {
|
|
2066
|
+
--tw-leading: 1.85;
|
|
2067
|
+
line-height: 1.85;
|
|
2068
|
+
}
|
|
2036
2069
|
.leading-none {
|
|
2037
2070
|
--tw-leading: 1;
|
|
2038
2071
|
line-height: 1;
|
|
@@ -2254,9 +2287,6 @@
|
|
|
2254
2287
|
.opacity-72 {
|
|
2255
2288
|
opacity: 72%;
|
|
2256
2289
|
}
|
|
2257
|
-
.opacity-80 {
|
|
2258
|
-
opacity: 80%;
|
|
2259
|
-
}
|
|
2260
2290
|
.opacity-100 {
|
|
2261
2291
|
opacity: 100%;
|
|
2262
2292
|
}
|
|
@@ -2499,9 +2529,6 @@
|
|
|
2499
2529
|
--tw-content: '';
|
|
2500
2530
|
content: var(--tw-content);
|
|
2501
2531
|
}
|
|
2502
|
-
.last\:mb-0:last-child {
|
|
2503
|
-
margin-bottom: 0px;
|
|
2504
|
-
}
|
|
2505
2532
|
.last\:border-r-0:last-child {
|
|
2506
2533
|
border-right-style: var(--tw-border-style);
|
|
2507
2534
|
border-right-width: 0px;
|
|
@@ -2529,6 +2556,14 @@
|
|
|
2529
2556
|
.hover\:border-gov:hover {
|
|
2530
2557
|
border-color: var(--color-gov);
|
|
2531
2558
|
}
|
|
2559
|
+
.hover\:border-gov\/50:hover {
|
|
2560
|
+
border-color: color-mix(in srgb, #1e3a5f 50%, transparent);
|
|
2561
|
+
}
|
|
2562
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
2563
|
+
.hover\:border-gov\/50:hover {
|
|
2564
|
+
border-color: color-mix(in oklab, var(--color-gov) 50%, transparent);
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2532
2567
|
.hover\:border-line:hover {
|
|
2533
2568
|
border-color: var(--color-line);
|
|
2534
2569
|
}
|
|
@@ -3301,6 +3336,79 @@
|
|
|
3301
3336
|
}
|
|
3302
3337
|
color: var(--color-amber);
|
|
3303
3338
|
}
|
|
3339
|
+
.owner-workbench-container {
|
|
3340
|
+
container-type: inline-size;
|
|
3341
|
+
}
|
|
3342
|
+
.owner-workbench {
|
|
3343
|
+
display: grid;
|
|
3344
|
+
gap: 28px;
|
|
3345
|
+
}
|
|
3346
|
+
.owner-work-reading {
|
|
3347
|
+
border-top: 1px solid var(--color-line);
|
|
3348
|
+
padding-top: 24px;
|
|
3349
|
+
scroll-margin-top: 80px;
|
|
3350
|
+
}
|
|
3351
|
+
.owner-workbench:has(.owner-work-list-selected) .owner-work-list {
|
|
3352
|
+
display: none;
|
|
3353
|
+
}
|
|
3354
|
+
.owner-work-list {
|
|
3355
|
+
max-height: 52dvh;
|
|
3356
|
+
overflow-y: auto;
|
|
3357
|
+
padding-right: 8px;
|
|
3358
|
+
scrollbar-gutter: stable;
|
|
3359
|
+
scrollbar-width: thin;
|
|
3360
|
+
scrollbar-color: var(--color-ink-4) transparent;
|
|
3361
|
+
}
|
|
3362
|
+
@supports selector(::-webkit-scrollbar) {
|
|
3363
|
+
.owner-work-list {
|
|
3364
|
+
scrollbar-width: auto;
|
|
3365
|
+
scrollbar-color: auto;
|
|
3366
|
+
}
|
|
3367
|
+
.owner-work-list::-webkit-scrollbar {
|
|
3368
|
+
width: 6px;
|
|
3369
|
+
}
|
|
3370
|
+
.owner-work-list::-webkit-scrollbar-track {
|
|
3371
|
+
background: transparent;
|
|
3372
|
+
}
|
|
3373
|
+
.owner-work-list::-webkit-scrollbar-thumb {
|
|
3374
|
+
background: var(--color-ink-4);
|
|
3375
|
+
border-radius: 999px;
|
|
3376
|
+
}
|
|
3377
|
+
.owner-work-list:hover::-webkit-scrollbar-thumb {
|
|
3378
|
+
background: var(--color-ink-3);
|
|
3379
|
+
}
|
|
3380
|
+
.owner-work-list::-webkit-scrollbar-button {
|
|
3381
|
+
display: none;
|
|
3382
|
+
width: 0;
|
|
3383
|
+
height: 0;
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
@media (forced-colors: active) {
|
|
3387
|
+
.owner-work-list {
|
|
3388
|
+
scrollbar-color: auto;
|
|
3389
|
+
}
|
|
3390
|
+
.owner-work-list::-webkit-scrollbar-thumb {
|
|
3391
|
+
background: ButtonText;
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3394
|
+
@container (min-width: 900px) {
|
|
3395
|
+
.owner-workbench {
|
|
3396
|
+
grid-template-columns: 272px minmax(0, 1fr);
|
|
3397
|
+
align-items: start;
|
|
3398
|
+
}
|
|
3399
|
+
.owner-workbench:has(.owner-work-list-selected) .owner-work-list {
|
|
3400
|
+
display: block;
|
|
3401
|
+
}
|
|
3402
|
+
.owner-work-list {
|
|
3403
|
+
max-height: 72dvh;
|
|
3404
|
+
}
|
|
3405
|
+
.owner-work-reading {
|
|
3406
|
+
border-top: 0;
|
|
3407
|
+
border-left: 1px solid var(--color-line);
|
|
3408
|
+
padding-top: 0;
|
|
3409
|
+
padding-left: 28px;
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3304
3412
|
@property --tw-translate-x {
|
|
3305
3413
|
syntax: "*";
|
|
3306
3414
|
inherits: false;
|