updated apps
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
/** localStorage keys for panel UI preferences — single source of truth.
|
||||
*
|
||||
* The VALUES are a compatibility contract: they are what users' browsers
|
||||
* already have stored, so they must never change (the mixed msp-/full-name
|
||||
* prefixes are historical and stay). Centralizing the names just makes a typo
|
||||
* in one call site impossible — a DRY audit (2026-07-10) found every key
|
||||
* duplicated inline at its get/set pair.
|
||||
*/
|
||||
|
||||
export const LS_KEYS = {
|
||||
overviewTab: "msp-overview-tab",
|
||||
collapsedSections: "msp-collapsed-sections",
|
||||
chartRange: "msp-chart-range",
|
||||
chartHideOutliers: "msp-chart-hide-outliers",
|
||||
taskSort: "maintenance_supporter_sort",
|
||||
objectSort: "maintenance_supporter_object_sort",
|
||||
groupBy: "maintenance_supporter_groupby",
|
||||
objectView: "maintenance_supporter_object_view",
|
||||
} as const;
|
||||
@@ -0,0 +1,11 @@
|
||||
/** Shared URL-safety guard for rendering user-supplied links.
|
||||
*
|
||||
* A user-entered URL (object/task documentation, spare-part shopping link,
|
||||
* document weblink) must only ever be linkified when it is an absolute http(s)
|
||||
* URL — never `javascript:`/`data:`/protocol-relative — else it is a stored-XSS
|
||||
* vector. The `X && /^https?:\/\//i.test(X)` idiom was inlined at ~8 render
|
||||
* sites; one forgotten copy is a hole, so it lives here once.
|
||||
*/
|
||||
export function isSafeHttpUrl(url: string | null | undefined): url is string {
|
||||
return !!url && /^https?:\/\//i.test(url);
|
||||
}
|
||||
@@ -25,6 +25,7 @@ export interface WorksheetLabels {
|
||||
priority: string;
|
||||
checklist: string;
|
||||
notes: string;
|
||||
parts: string; // "Required parts"
|
||||
scanView: string; // "Scan to open the task"
|
||||
scanComplete: string; // "Scan to complete"
|
||||
manualExcerpt: string; // "Manual excerpt"
|
||||
@@ -59,6 +60,7 @@ export function buildTaskWorksheetHtml(
|
||||
qrCompleteDataUri: string | null,
|
||||
excerpt: WorksheetExcerpt | null,
|
||||
nowIso: string,
|
||||
partsLines: string[] = [],
|
||||
): string {
|
||||
const meta: Array<[string, string]> = [
|
||||
[L.object, esc(objectName)],
|
||||
@@ -127,6 +129,7 @@ export function buildTaskWorksheetHtml(
|
||||
${meta.map(([k, v]) => `<tr><td>${esc(k)}</td><td>${v}</td></tr>`).join("")}
|
||||
</table>
|
||||
${checklist ? `<h2>${esc(L.checklist)}</h2><ul class="check">${checklist}</ul>` : ""}
|
||||
${partsLines.length ? `<h2>${esc(L.parts)}</h2><ul class="check">${partsLines.map((line) => `<li><span class="box"></span>${esc(line)}</li>`).join("")}</ul>` : ""}
|
||||
${task.notes ? `<h2>${esc(L.notes)}</h2><div class="notes">${esc(task.notes)}</div>` : ""}
|
||||
${excerpt ? `<h2>${esc(L.manualExcerpt)}</h2>
|
||||
<div class="excerpt">${esc(excerpt.title)} — ${esc(L.pages)} ${excerpt.startPage}–${excerpt.endPage}:
|
||||
|
||||
Reference in New Issue
Block a user