docs(sdlc): keep short cells on one line, unify QA/Tester
This commit is contained in:
@@ -354,7 +354,7 @@ async function tableWidthNeededMm(page) {
|
|||||||
* them. Returns the IDs or dates that still stick out of their cell.
|
* them. Returns the IDs or dates that still stick out of their cell.
|
||||||
*/
|
*/
|
||||||
async function applyProportionalWidths(page, textMm) {
|
async function applyProportionalWidths(page, textMm) {
|
||||||
return page.evaluate(({ availMm, SHORT_COLUMN_MM }) => {
|
return page.evaluate(({ availMm, SHORT_COLUMN_MM, SHORT_CELL_CHARS }) => {
|
||||||
const mm = 96 / 25.4;
|
const mm = 96 / 25.4;
|
||||||
const main = document.querySelector('main.delivery-document');
|
const main = document.querySelector('main.delivery-document');
|
||||||
const probe = document.createElement('style');
|
const probe = document.createElement('style');
|
||||||
@@ -373,7 +373,8 @@ async function applyProportionalWidths(page, textMm) {
|
|||||||
const rects = [...range.getClientRects()];
|
const rects = [...range.getClientRects()];
|
||||||
const text = rects.length ? Math.max(...rects.map((r) => r.right)) - Math.min(...rects.map((r) => r.left)) : 0;
|
const text = rects.length ? Math.max(...rects.map((r) => r.right)) - Math.min(...rects.map((r) => r.left)) : 0;
|
||||||
const style = getComputedStyle(cell);
|
const style = getComputedStyle(cell);
|
||||||
return text + parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) + 1;
|
// 1.2mm slack for the cell borders and glyphs that overhang their advance width.
|
||||||
|
return text + parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) + 1.2 * mm;
|
||||||
};
|
};
|
||||||
const measure = (table, mode) => {
|
const measure = (table, mode) => {
|
||||||
const holder = document.createElement('div');
|
const holder = document.createElement('div');
|
||||||
@@ -384,7 +385,7 @@ async function applyProportionalWidths(page, textMm) {
|
|||||||
for (const row of holder.querySelector('table').rows) {
|
for (const row of holder.querySelector('table').rows) {
|
||||||
let index = 0;
|
let index = 0;
|
||||||
for (const cell of row.cells) {
|
for (const cell of row.cells) {
|
||||||
if (cell.colSpan === 1) (columns[index] ??= []).push({ width: contentWidth(cell) / mm, head: cell.tagName === 'TH' });
|
if (cell.colSpan === 1) (columns[index] ??= []).push({ width: contentWidth(cell) / mm, head: cell.tagName === 'TH', short: cell.textContent.trim().length <= SHORT_CELL_CHARS });
|
||||||
index += cell.colSpan;
|
index += cell.colSpan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,7 +402,9 @@ async function applyProportionalWidths(page, textMm) {
|
|||||||
let floor = narrow.map((c, i) => Math.min(Math.max(...c.map((x) => x.width)), longest[i]));
|
let floor = narrow.map((c, i) => Math.min(Math.max(...c.map((x) => x.width)), longest[i]));
|
||||||
// Short columns (IDs, dates, statuses) stay on one line when the page allows;
|
// Short columns (IDs, dates, statuses) stay on one line when the page allows;
|
||||||
// the prose columns then share what is left in proportion to their content.
|
// the prose columns then share what is left in proportion to their content.
|
||||||
const oneLine = floor.map((f, i) => (longest[i] <= SHORT_COLUMN_MM ? longest[i] : f));
|
// So do short entries in any column - a status word, a list of initials.
|
||||||
|
const shortest = line.map((c) => Math.max(0, ...c.filter((x) => x.short && !x.head).map((x) => x.width)));
|
||||||
|
const oneLine = floor.map((f, i) => (longest[i] <= SHORT_COLUMN_MM ? longest[i] : Math.max(f, shortest[i])));
|
||||||
if (oneLine.reduce((a, b) => a + b, 0) < availMm) floor = oneLine;
|
if (oneLine.reduce((a, b) => a + b, 0) < availMm) floor = oneLine;
|
||||||
const weight = line.map((c) => {
|
const weight = line.map((c) => {
|
||||||
const body = c.filter((x) => !x.head);
|
const body = c.filter((x) => !x.head);
|
||||||
@@ -462,7 +465,7 @@ async function applyProportionalWidths(page, textMm) {
|
|||||||
.map((span) => span.textContent);
|
.map((span) => span.textContent);
|
||||||
main.style.width = '';
|
main.style.width = '';
|
||||||
return [...new Set(clipped)];
|
return [...new Set(clipped)];
|
||||||
}, { availMm: textMm, SHORT_COLUMN_MM: 35 });
|
}, { availMm: textMm, SHORT_COLUMN_MM: 35, SHORT_CELL_CHARS: 16 });
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((error) => { console.error(error); process.exit(1); });
|
main().catch((error) => { console.error(error); process.exit(1); });
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function stakeholderRegister() {
|
|||||||
[2, P.ApS.th, P.ApS.id, 'Project Manager', 'วางแผนและควบคุมโครงการ ติดตามความก้าวหน้า บริหารความเสี่ยงและการเปลี่ยนแปลง', 'A (Accountable), R (Responsible)'],
|
[2, P.ApS.th, P.ApS.id, 'Project Manager', 'วางแผนและควบคุมโครงการ ติดตามความก้าวหน้า บริหารความเสี่ยงและการเปลี่ยนแปลง', 'A (Accountable), R (Responsible)'],
|
||||||
[3, P.NoC.th, P.NoC.id, 'System Analyst', 'เก็บและวิเคราะห์ความต้องการ ออกแบบระบบและฐานข้อมูล จัดทำเอกสาร SRS และ Design', 'R (Responsible), C (Consult)'],
|
[3, P.NoC.th, P.NoC.id, 'System Analyst', 'เก็บและวิเคราะห์ความต้องการ ออกแบบระบบและฐานข้อมูล จัดทำเอกสาร SRS และ Design', 'R (Responsible), C (Consult)'],
|
||||||
[4, P.ThS.th, P.ThS.id, 'Developer', 'พัฒนาระบบตามการออกแบบ ดูแลความปลอดภัย การติดตั้ง และการสำรองข้อมูล', 'R (Responsible), C (Consult)'],
|
[4, P.ThS.th, P.ThS.id, 'Developer', 'พัฒนาระบบตามการออกแบบ ดูแลความปลอดภัย การติดตั้ง และการสำรองข้อมูล', 'R (Responsible), C (Consult)'],
|
||||||
[5, P.PaNg.th, P.PaNg.id, 'QA / Tester', 'จัดทำและดำเนินการทดสอบ ตรวจสอบ Work Products และติดตามการแก้ไขข้อบกพร่อง', 'R (Responsible), C (Consult)'],
|
[5, P.PaNg.th, P.PaNg.id, 'QA/Tester', 'จัดทำและดำเนินการทดสอบ ตรวจสอบ Work Products และติดตามการแก้ไขข้อบกพร่อง', 'R (Responsible), C (Consult)'],
|
||||||
[6, P.YaB.th, P.YaB.id, 'Document Control', 'ควบคุมรหัสเอกสาร เวอร์ชัน การอนุมัติ การจัดเก็บ และหลักฐานของโครงการ', 'R (Responsible)'],
|
[6, P.YaB.th, P.YaB.id, 'Document Control', 'ควบคุมรหัสเอกสาร เวอร์ชัน การอนุมัติ การจัดเก็บ และหลักฐานของโครงการ', 'R (Responsible)'],
|
||||||
...OTHER_STAKEHOLDERS.map(([name, role, duty, engagement], i) => [7 + i, name, '—', role, duty, engagement]),
|
...OTHER_STAKEHOLDERS.map(([name, role, duty, engagement], i) => [7 + i, name, '—', role, duty, engagement]),
|
||||||
], ['c', '', 'c', '', '', '']),
|
], ['c', '', 'c', '', '', '']),
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ export function softwareProjectPlan() {
|
|||||||
[1, `Project Manager (${P.ApS.id})`, P.ApS.th, P.ApS.email, 'จัดทำ Project Charter และแผนโครงการ / วางแผน Timeline, Resource, Risk, Quality / จัดประชุมและติดตามความคืบหน้า / ควบคุมการเปลี่ยนแปลงและการปิดโครงการ'],
|
[1, `Project Manager (${P.ApS.id})`, P.ApS.th, P.ApS.email, 'จัดทำ Project Charter และแผนโครงการ / วางแผน Timeline, Resource, Risk, Quality / จัดประชุมและติดตามความคืบหน้า / ควบคุมการเปลี่ยนแปลงและการปิดโครงการ'],
|
||||||
[2, `System Analyst (${P.NoC.id})`, P.NoC.th, P.NoC.email, 'เก็บและวิเคราะห์ความต้องการ / จัดทำ SRS และเอกสารออกแบบระบบ / ออกแบบฐานข้อมูลและความสัมพันธ์ของโมดูล / ตรวจสอบความสอดคล้องของงานพัฒนากับความต้องการ'],
|
[2, `System Analyst (${P.NoC.id})`, P.NoC.th, P.NoC.email, 'เก็บและวิเคราะห์ความต้องการ / จัดทำ SRS และเอกสารออกแบบระบบ / ออกแบบฐานข้อมูลและความสัมพันธ์ของโมดูล / ตรวจสอบความสอดคล้องของงานพัฒนากับความต้องการ'],
|
||||||
[3, `Developer (${P.ThS.id})`, P.ThS.th, P.ThS.email, 'พัฒนาโมดูลและ API ตามการออกแบบ / จัดการฐานข้อมูลและประสิทธิภาพ / ดูแลความปลอดภัยและการติดตั้ง / แก้ไขข้อบกพร่องที่พบจากการทดสอบ'],
|
[3, `Developer (${P.ThS.id})`, P.ThS.th, P.ThS.email, 'พัฒนาโมดูลและ API ตามการออกแบบ / จัดการฐานข้อมูลและประสิทธิภาพ / ดูแลความปลอดภัยและการติดตั้ง / แก้ไขข้อบกพร่องที่พบจากการทดสอบ'],
|
||||||
[4, `QA / Tester (${P.PaNg.id})`, P.PaNg.th, P.PaNg.email, 'จัดทำ Test Case และ Test Procedures / ทดสอบระบบและบันทึกผล / ติดตามการแก้ไขข้อบกพร่องและทดสอบซ้ำ / สนับสนุนผู้ใช้งานช่วง UAT'],
|
[4, `QA/Tester (${P.PaNg.id})`, P.PaNg.th, P.PaNg.email, 'จัดทำ Test Case และ Test Procedures / ทดสอบระบบและบันทึกผล / ติดตามการแก้ไขข้อบกพร่องและทดสอบซ้ำ / สนับสนุนผู้ใช้งานช่วง UAT'],
|
||||||
[5, `Document Control (${P.YaB.id})`, P.YaB.th, P.YaB.email, 'ควบคุมรหัสเอกสารและเวอร์ชัน / จัดเก็บและตรวจสอบความครบถ้วนของเอกสาร / ประสานการทบทวนและอนุมัติ / บันทึกประวัติการเปลี่ยนแปลงเอกสาร'],
|
[5, `Document Control (${P.YaB.id})`, P.YaB.th, P.YaB.email, 'ควบคุมรหัสเอกสารและเวอร์ชัน / จัดเก็บและตรวจสอบความครบถ้วนของเอกสาร / ประสานการทบทวนและอนุมัติ / บันทึกประวัติการเปลี่ยนแปลงเอกสาร'],
|
||||||
[6, `Project Sponsor (${P.SeV.id})`, P.SeV.th, P.SeV.email, 'อนุมัติขอบเขต งบประมาณ และการเปลี่ยนแปลง / ตัดสินใจเชิงกลยุทธ์ / ทดสอบการยอมรับและตรวจรับส่งมอบ / อนุมัติปิดโครงการ'],
|
[6, `Project Sponsor (${P.SeV.id})`, P.SeV.th, P.SeV.email, 'อนุมัติขอบเขต งบประมาณ และการเปลี่ยนแปลง / ตัดสินใจเชิงกลยุทธ์ / ทดสอบการยอมรับและตรวจรับส่งมอบ / อนุมัติปิดโครงการ'],
|
||||||
], ['c']),
|
], ['c']),
|
||||||
@@ -225,7 +225,7 @@ export function softwareProjectPlan() {
|
|||||||
[1, 'Project Manager', 'ควบคุมงาน ประสานงาน ติดตามแผน', 120],
|
[1, 'Project Manager', 'ควบคุมงาน ประสานงาน ติดตามแผน', 120],
|
||||||
[2, 'System Analyst', 'วิเคราะห์ความต้องการ ออกแบบระบบ', 60],
|
[2, 'System Analyst', 'วิเคราะห์ความต้องการ ออกแบบระบบ', 60],
|
||||||
[3, 'Developer', 'พัฒนาระบบและแก้ไขข้อบกพร่อง', 100],
|
[3, 'Developer', 'พัฒนาระบบและแก้ไขข้อบกพร่อง', 100],
|
||||||
[4, 'QA / Tester', 'วางแผนทดสอบ ทดสอบระบบ UAT', 40],
|
[4, 'QA/Tester', 'วางแผนทดสอบ ทดสอบระบบ UAT', 40],
|
||||||
[5, 'Document Control', 'ควบคุมเอกสารและหลักฐานโครงการ', 60],
|
[5, 'Document Control', 'ควบคุมเอกสารและหลักฐานโครงการ', 60],
|
||||||
], ['c', '', '', 'r']),
|
], ['c', '', '', 'r']),
|
||||||
sec(7, 'Project Resources'),
|
sec(7, 'Project Resources'),
|
||||||
|
|||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user