GitHub(nextgroup2706/ken_nogi)は今後使わず自社Gitea運用に切替え。 NodeSrvは旧リポジトリの履歴を破棄しファイルのみ統合(Dokploy用サービスアカウントは 別途mygit-admin/NodeSrv.gitに履歴あり)。notepmエクスポート(12GB)とPleasanter インストーラzip(208MB)はサイズが大きいため.gitignoreで除外。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
189 lines
7.6 KiB
JavaScript
189 lines
7.6 KiB
JavaScript
/**
|
||
* add-tateuri-link-columns.js
|
||
* ------------------------------------------------------------
|
||
* 116503「★リードタイム算定」・203147「★工期計算表」に、488755「【開発中】★建売マスターシート」
|
||
* への参照カラムを新規追加する。
|
||
*
|
||
* 経緯: 488755編集画面の要望「リンクは『リードタイム算定』と『工期計算』のみ必要」に対応するため、
|
||
* 488755側のEditorColumnHash(_Links-116503 / _Links-203147)自体は複製元189112から既に
|
||
* 引き継がれているが、Pleasanterの双方向リンクは「子サイト側(116503/203147)が親サイトを
|
||
* 参照するColumn」の存在が必須で、これが488755分だけ欠落しているため画面に何も表示されていなかった
|
||
* (実機Selenium検証、2026-08-31で確認)。
|
||
*
|
||
* 1カラムにつき参照できるサイトは1つまで(ユーザー確認済みルール)のため、既存の189112用カラム
|
||
* (116503側=ClassA、203147側=ClassA)を流用せず、488755専用の新規カラムを追加する。
|
||
*
|
||
* 使い方:
|
||
* node add-tateuri-link-columns.js --project="★マスターシート" --env=staging
|
||
* … 差分表示のみ(送信なし)
|
||
* node add-tateuri-link-columns.js --project="★マスターシート" --env=staging --execute
|
||
* … 上記に加えて実際に送信する
|
||
* ------------------------------------------------------------
|
||
*/
|
||
const path = require("path");
|
||
const fs = require("fs");
|
||
const { resolveProjectRoot, loadServerConfig } = require("../../resolve-project");
|
||
const { findSiteDir, newModifyDir } = require("../../site-paths");
|
||
|
||
const { baseDir, env } = resolveProjectRoot();
|
||
const execute = process.argv.includes("--execute");
|
||
|
||
const TARGETS = [
|
||
{
|
||
siteId: 116503,
|
||
newColumnName: "Class001",
|
||
labelText: "建売マスターシート",
|
||
messageWhenDuplicated: "建売マスターシートに付随できるレコードは1つだけです",
|
||
insertAfter: "ClassA",
|
||
},
|
||
{
|
||
siteId: 203147,
|
||
newColumnName: "Class011",
|
||
labelText: "建売マスターシート",
|
||
messageWhenDuplicated: "建売マスターシートに付随できるレコードは1つだけです",
|
||
insertAfter: "ClassA",
|
||
},
|
||
];
|
||
const TARGET_SITE_ID_FOR_LINK = 488755;
|
||
|
||
function maskApiKey(key) {
|
||
if (!key) return key;
|
||
return key.length > 8 ? key.slice(0, 4) + "****" + key.slice(-4) : "****";
|
||
}
|
||
|
||
async function processSite(target, config) {
|
||
const { siteId, newColumnName, labelText, messageWhenDuplicated, insertAfter } = target;
|
||
console.log(`\n---- SiteId ${siteId} ----`);
|
||
|
||
const getUrl = `${config.BaseUrl.replace(/\/+$/, "")}/api/items/${siteId}/getsite`;
|
||
const getRes = await fetch(getUrl, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ ApiVersion: config.ApiVersion || "1.1", ApiKey: config.ApiKey }),
|
||
});
|
||
const getJson = await getRes.json();
|
||
if (getJson.StatusCode !== 200) {
|
||
console.error("[エラー] getsiteに失敗しました:", JSON.stringify(getJson).slice(0, 500));
|
||
process.exit(1);
|
||
}
|
||
const data = getJson.Response.Data;
|
||
const siteSettings = data.SiteSettings;
|
||
console.log(`[OK] 取得しました(現在のVer: ${data.Ver}, UpdatedTime: ${data.UpdatedTime})`);
|
||
|
||
let changed = false;
|
||
|
||
// --- Columns ---
|
||
console.log("\n--- Columns ---");
|
||
const existingCol = siteSettings.Columns.find((c) => c.ColumnName === newColumnName);
|
||
if (existingCol) {
|
||
if (existingCol.ChoicesText === `[[${TARGET_SITE_ID_FOR_LINK}]]`) {
|
||
console.log(` ${newColumnName}: 既に488755参照カラムとして存在(変更なし)`);
|
||
} else {
|
||
console.error(`[エラー] ${newColumnName} は既に別用途で使用中です:`, JSON.stringify(existingCol));
|
||
process.exit(1);
|
||
}
|
||
} else {
|
||
const newColumn = {
|
||
ColumnName: newColumnName,
|
||
LabelText: labelText,
|
||
ChoicesText: `[[${TARGET_SITE_ID_FOR_LINK}]]`,
|
||
Hide: true,
|
||
NoDuplication: true,
|
||
MessageWhenDuplicated: messageWhenDuplicated,
|
||
FieldCss: "field-wide",
|
||
Link: true,
|
||
SearchType: "PartialMatch",
|
||
};
|
||
siteSettings.Columns.push(newColumn);
|
||
console.log(` ${newColumnName}: Columns末尾に追加 ->`, JSON.stringify(newColumn));
|
||
changed = true;
|
||
}
|
||
|
||
// --- Links ---
|
||
console.log("\n--- Links ---");
|
||
const hasLink = siteSettings.Links.some(
|
||
(l) => l.ColumnName === newColumnName && String(l.SiteId) === String(TARGET_SITE_ID_FOR_LINK)
|
||
);
|
||
if (hasLink) {
|
||
console.log(` 488755参照: 既にLinks設定あり(変更なし)`);
|
||
} else {
|
||
siteSettings.Links.push({ ColumnName: newColumnName, SiteId: TARGET_SITE_ID_FOR_LINK });
|
||
console.log(` 488755参照: Links末尾に追加 -> { ColumnName: "${newColumnName}", SiteId: ${TARGET_SITE_ID_FOR_LINK} }`);
|
||
changed = true;
|
||
}
|
||
|
||
// --- EditorColumnHash.General ---
|
||
console.log("\n--- EditorColumnHash.General ---");
|
||
const general = siteSettings.EditorColumnHash.General;
|
||
if (general.includes(newColumnName)) {
|
||
console.log(` ${newColumnName}: 既に配置あり(変更なし)`);
|
||
} else {
|
||
const idx = general.indexOf(insertAfter);
|
||
if (idx === -1) {
|
||
console.error(`[エラー] 挿入位置の基準(${insertAfter})が見つかりません`);
|
||
process.exit(1);
|
||
}
|
||
general.splice(idx + 1, 0, newColumnName);
|
||
console.log(` ${newColumnName}: ${insertAfter}の直後に挿入 ->`, JSON.stringify(general));
|
||
changed = true;
|
||
}
|
||
|
||
if (!changed) {
|
||
console.log("\n変更なし。既に対応済みです。");
|
||
return { siteId, changed: false };
|
||
}
|
||
|
||
console.log("\n他のSiteSettings(他Columns/Processes/GridColumns等)・Permissions・Title等は一切変更しません。");
|
||
|
||
const body = {
|
||
ApiVersion: config.ApiVersion || "1.1",
|
||
ApiKey: config.ApiKey,
|
||
SiteId: siteId,
|
||
Title: data.Title,
|
||
ReferenceType: data.ReferenceType,
|
||
ParentId: data.ParentId,
|
||
InheritPermission: data.InheritPermission,
|
||
Permissions: data.Permissions,
|
||
SiteSettings: siteSettings,
|
||
};
|
||
|
||
const configsDir = path.join(baseDir, "configs", env);
|
||
const siteDir = findSiteDir(configsDir, siteId);
|
||
const maskedBody = { ...body, ApiKey: maskApiKey(body.ApiKey) };
|
||
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
||
if (siteDir) {
|
||
const modifyDir = newModifyDir(siteDir, "add-tateuri-link-column");
|
||
const previewPath = path.join(modifyDir, `site-${siteId}_preview_${ts}.json`);
|
||
fs.writeFileSync(previewPath, JSON.stringify(maskedBody, null, 2), "utf-8");
|
||
console.log(`\n[OK] 送信予定内容を保存しました: ${previewPath}`);
|
||
}
|
||
|
||
if (!execute) {
|
||
console.log("\n[注意] --execute が指定されていないため、送信は行っていません。");
|
||
return { siteId, changed: true, sent: false };
|
||
}
|
||
|
||
console.log("\n実際に送信します(updatesite)...");
|
||
const url = `${config.BaseUrl.replace(/\/+$/, "")}/api/items/${siteId}/updatesite`;
|
||
const res = await fetch(url, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(body),
|
||
});
|
||
const text = await res.text();
|
||
console.log(`HTTP ${res.status} ${res.statusText}`);
|
||
console.log(text);
|
||
return { siteId, changed: true, sent: true };
|
||
}
|
||
|
||
(async () => {
|
||
const config = loadServerConfig(env);
|
||
console.log("========================================");
|
||
console.log(` 488755参照カラム追加(116503/203147, ${env})${execute ? "(実行)" : "(プレビューのみ)"}`);
|
||
console.log("========================================");
|
||
|
||
for (const target of TARGETS) {
|
||
await processSite(target, config);
|
||
}
|
||
})();
|