@takagaki/cortex-decisions-viewer 0.12.6 → 0.12.7
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/dist/render.js +143 -4
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -2064,10 +2064,26 @@ a:hover { text-decoration: underline; }
|
|
|
2064
2064
|
.badge.latest { background: #dcfce7; color: #166534; border: 1px solid #86efac; }
|
|
2065
2065
|
.badge.error { background: #fee2e2; color: #b91c1c; border: 1px solid #fca5a5; }
|
|
2066
2066
|
.draft-note {
|
|
2067
|
-
display: flex; gap: 8px; align-items: flex-start;
|
|
2067
|
+
display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start;
|
|
2068
2068
|
background: #fffbeb; border: 1px solid #fcd34d; border-radius: 8px;
|
|
2069
2069
|
padding: 10px 14px; margin: 12px 0 4px; font-size: 13.5px; color: #92400e; line-height: 1.7;
|
|
2070
2070
|
}
|
|
2071
|
+
/* 警告帯に並べる「確認済みにする」。帯と同じ系統の色で、押すものだと分かる濃さにする */
|
|
2072
|
+
.promote-btn {
|
|
2073
|
+
flex: 0 0 auto; align-self: center; margin-left: auto; cursor: pointer; white-space: nowrap;
|
|
2074
|
+
padding: 6px 14px; border-radius: 999px; border: 1px solid #b45309;
|
|
2075
|
+
background: #b45309; color: #fff; font-size: 13px; font-weight: 600;
|
|
2076
|
+
}
|
|
2077
|
+
.promote-btn:hover { background: #92400e; }
|
|
2078
|
+
.promote-btn:disabled { opacity: .6; cursor: default; }
|
|
2079
|
+
/* 何を上げようとしているか(リポジトリ上のパス)。リンクではないので控えめな色にする */
|
|
2080
|
+
.promote-target { font-size: 12.5px; word-break: break-all; color: var(--muted); margin: 0 0 12px; }
|
|
2081
|
+
/* 押したあとの帯。draft(黄・要対応)と入れ替わるので、済んだと分かる緑にする */
|
|
2082
|
+
.promoted-note {
|
|
2083
|
+
display: flex; gap: 8px; align-items: flex-start;
|
|
2084
|
+
background: #ecfdf5; border: 1px solid #a7f3d0; border-radius: 8px;
|
|
2085
|
+
padding: 10px 14px; margin: 12px 0 4px; font-size: 13.5px; color: #047857; line-height: 1.7;
|
|
2086
|
+
}
|
|
2071
2087
|
.adoption-note {
|
|
2072
2088
|
display: flex; gap: 8px; align-items: flex-start;
|
|
2073
2089
|
background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px;
|
|
@@ -2913,13 +2929,136 @@ ${deriveCapTile.toString()}
|
|
|
2913
2929
|
function latestBadge(rec) {
|
|
2914
2930
|
return rec && rec.isLatest ? el("span", { class: "badge latest", text: "最新の生成" }) : null;
|
|
2915
2931
|
}
|
|
2916
|
-
//
|
|
2932
|
+
// 詳細ページの警告。バッジより強く「そのまま信じないでほしい」と伝える。
|
|
2933
|
+
// **確認済みにできる記録には、その場で上げるボタンを並べる**(下の promotableRecordPath)。
|
|
2934
|
+
// ボタンが出せないとき(受け口が未設定・パスが解決できない)は、これまでどおり
|
|
2935
|
+
// 「frontmatter を直してください」の案内に倒す——押せない画面で押す話をしない
|
|
2917
2936
|
function draftNote(rec) {
|
|
2918
2937
|
if (!rec || rec.rstatus !== "draft") return null;
|
|
2919
|
-
|
|
2938
|
+
var path = promotableRecordPath(rec);
|
|
2939
|
+
var note = el("div", { class: "draft-note" }, [
|
|
2920
2940
|
el("span", { text: "⚠️" }),
|
|
2921
|
-
el("span", { text:
|
|
2941
|
+
el("span", { text: path
|
|
2942
|
+
? "この内容はAIが自動生成したものです(人間未確認)。内容を確認し、直すところが無ければ「確認済みにする」を押してください。直したいところがあれば「AIで編集」から修正してください。"
|
|
2943
|
+
: "この内容はAIが自動生成したものです(人間未確認)。必ず内容を確認し、適切な内容に直したうえで frontmatter の status を active に変更してください。" }),
|
|
2922
2944
|
]);
|
|
2945
|
+
if (path) {
|
|
2946
|
+
var btn = el("button", { class: "promote-btn", type: "button", text: "確認済みにする" });
|
|
2947
|
+
btn.addEventListener("click", function () {
|
|
2948
|
+
openPromoteModal(path, function () { markPromoted(rec, note); });
|
|
2949
|
+
});
|
|
2950
|
+
note.appendChild(btn);
|
|
2951
|
+
}
|
|
2952
|
+
return note;
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2955
|
+
// ---------- Gold の確認済み昇格(status: draft → active) ----------
|
|
2956
|
+
//
|
|
2957
|
+
// 内容がそのまま正しいとき、**編集せずに所有権だけ引き取る**ための最短経路。
|
|
2958
|
+
// 直すところがあるなら「AIで編集」が別にあるので、ここは「そのままでよい」専用。
|
|
2959
|
+
|
|
2960
|
+
// 受け口が受け付けるパスの形。**サーバ側にも同じ門がある**(logic.mjs の isPromotablePath)。
|
|
2961
|
+
// ここは「押せないボタンを出さない」ための出し分けで、**守りはサーバ側**
|
|
2962
|
+
var PROMOTABLE_PATH = /^Cortex\\/(Decisions|Glossary|Members|Rules)\\/records\\/[^/]+\\.md$/;
|
|
2963
|
+
function promotableRecordPath(rec) {
|
|
2964
|
+
if (!SITE.intake) return "";
|
|
2965
|
+
var p = repoPathOf(rec);
|
|
2966
|
+
if (!p || !PROMOTABLE_PATH.test(p)) return "";
|
|
2967
|
+
// 区画の規約・雛形はレコードではない(一覧にも出ないが、念のため出し分けでも弾く)
|
|
2968
|
+
var base = p.slice(p.lastIndexOf("/") + 1).toLowerCase();
|
|
2969
|
+
return base === "readme.md" || base === "template.md" ? "" : p;
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
// 確認者名は同じブラウザで覚えておく(**案件別**。同一ブラウザで複数案件を見ても混ざらない)
|
|
2973
|
+
function verifierStoreKey() { return "cortex-verifier-name:" + REPO_SLUG; }
|
|
2974
|
+
function rememberedVerifier() {
|
|
2975
|
+
try { return localStorage.getItem(verifierStoreKey()) || ""; } catch (e) { return ""; }
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
/**
|
|
2979
|
+
* 確認の一手間を挟む。**押した瞬間に上げない。**
|
|
2980
|
+
*
|
|
2981
|
+
* 上げると「人間が確認したもの」としてAIの自動更新の対象から外れる=意味の重い操作で、
|
|
2982
|
+
* 元に戻すにはリポジトリを直接編集するしかない。誤爆の余地を残さない。
|
|
2983
|
+
*/
|
|
2984
|
+
function openPromoteModal(path, onDone) {
|
|
2985
|
+
var mk = makeModal("この記録を確認済みにする", false);
|
|
2986
|
+
var modal = mk.modal;
|
|
2987
|
+
modal.appendChild(el("p", { class: "modal-desc", text: "内容を確認したものとして、この記録を「確認済み」に上げます。以後この記録は人間が持つものとして扱われ、AIによる自動更新の対象から外れます。" }));
|
|
2988
|
+
modal.appendChild(el("div", { class: "promote-target mono", text: path }));
|
|
2989
|
+
var nameInput = el("input", { type: "text", class: "modal-name", placeholder: "確認した人として記録に残ります(省略できます)" });
|
|
2990
|
+
nameInput.value = rememberedVerifier();
|
|
2991
|
+
modal.appendChild(fieldRow("お名前(任意)", nameInput));
|
|
2992
|
+
var status = el("div", { class: "modal-status" });
|
|
2993
|
+
var cancelBtn = el("button", { class: "modal-cancel", type: "button", text: "閉じる" });
|
|
2994
|
+
var okBtn = el("button", { class: "ops-card-btn", type: "button", text: "確認済みにする" });
|
|
2995
|
+
modal.appendChild(status);
|
|
2996
|
+
modal.appendChild(el("div", { class: "modal-actions" }, [cancelBtn, okBtn]));
|
|
2997
|
+
mk.overlay.appendChild(modal);
|
|
2998
|
+
showModal(mk.overlay, modal);
|
|
2999
|
+
cancelBtn.addEventListener("click", function () { mk.close(); });
|
|
3000
|
+
okBtn.addEventListener("click", function () {
|
|
3001
|
+
sendPromote(path, nameInput.value, status, okBtn, function () { mk.close(); onDone(); });
|
|
3002
|
+
});
|
|
3003
|
+
}
|
|
3004
|
+
|
|
3005
|
+
async function sendPromote(path, name, status, btn, onOk) {
|
|
3006
|
+
var intake = SITE.intake;
|
|
3007
|
+
if (!intake) return;
|
|
3008
|
+
function setStatus(msg, isError) {
|
|
3009
|
+
status.className = "modal-status" + (isError ? " modal-status-error" : "");
|
|
3010
|
+
status.textContent = msg;
|
|
3011
|
+
}
|
|
3012
|
+
// 押している間はボタンごと語を差し替える(#222・beginBusy の項)
|
|
3013
|
+
var endBusy = beginBusy(btn, "確認中…");
|
|
3014
|
+
setStatus("", false);
|
|
3015
|
+
var who = String(name || "").trim();
|
|
3016
|
+
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
3017
|
+
var res, j;
|
|
3018
|
+
try {
|
|
3019
|
+
res = await fetch(pfx + "op=promote&t=" + encodeURIComponent(intake.token), {
|
|
3020
|
+
method: "POST",
|
|
3021
|
+
headers: { "content-type": "application/json" },
|
|
3022
|
+
body: JSON.stringify({ projectKey: intake.projectKey, path: path, submitter: who }),
|
|
3023
|
+
});
|
|
3024
|
+
j = await res.json().catch(function () { return {}; });
|
|
3025
|
+
} catch (e) {
|
|
3026
|
+
endBusy();
|
|
3027
|
+
setStatus("✗ サーバーに接続できませんでした。通信環境を確認して、もう一度お試しください。", true);
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3030
|
+
// 🔴 **「既に確認済みです」は成功として扱う。** この画面のデータは静的ビルド時点のもので、
|
|
3031
|
+
// 誰かが先に上げていれば古いまま未確認に見える。押した人が望んだ状態には**なっている**ので、
|
|
3032
|
+
// 失敗として見せると「押しても直らない」堂々巡りになる。
|
|
3033
|
+
// **符号で見る。** 409 を一律に成功にすると、status が draft でない別の状態
|
|
3034
|
+
// (superseded 等)で断られたときまで「確認済みにしました」と嘘をつく
|
|
3035
|
+
if (res.ok || (res.status === 409 && j.code === "ALREADY_ACTIVE")) {
|
|
3036
|
+
if (who) { try { localStorage.setItem(verifierStoreKey(), who); } catch (e2) {} }
|
|
3037
|
+
endBusy();
|
|
3038
|
+
onOk();
|
|
3039
|
+
return;
|
|
3040
|
+
}
|
|
3041
|
+
endBusy();
|
|
3042
|
+
setStatus("✗ " + (j.message || "確認済みにできませんでした。時間をおいて再度お試しください。"), true);
|
|
3043
|
+
}
|
|
3044
|
+
|
|
3045
|
+
/**
|
|
3046
|
+
* 押した結果を画面に映す。
|
|
3047
|
+
*
|
|
3048
|
+
* **次のビルドまで SiteData は古いまま。** 昇格の commit 自体が Amplify の再ビルドを
|
|
3049
|
+
* 誘発するので数分で追いつくが、その間も押した人には済んだものとして見せる。
|
|
3050
|
+
*/
|
|
3051
|
+
function markPromoted(rec, note) {
|
|
3052
|
+
// **元データも直す。** 一覧へ戻って開き直しても未確認に戻らないようにする
|
|
3053
|
+
rec.rstatus = "active";
|
|
3054
|
+
var host = note.parentNode;
|
|
3055
|
+
if (!host) return;
|
|
3056
|
+
var badge = host.querySelector(".detail-meta .badge.draft");
|
|
3057
|
+
if (badge && badge.parentNode) badge.parentNode.removeChild(badge);
|
|
3058
|
+
host.replaceChild(el("div", { class: "promoted-note" }, [
|
|
3059
|
+
el("span", { text: "✅" }),
|
|
3060
|
+
el("span", { text: "この記録を確認済みにしました。一覧などの表示は、数分後に画面が作り直されたときに反映されます。" }),
|
|
3061
|
+
]), note);
|
|
2923
3062
|
}
|
|
2924
3063
|
// 未確認の絞り込み(フィルタのセレクトの選択肢は draft の1つだけ)
|
|
2925
3064
|
function statusLabel(v) { return v === "draft" ? "未確認のみ" : v; }
|
package/package.json
CHANGED