feat: harden auth for public deploy + gantt, duration units, docker packaging
Security (fail-secure for production): - Refuse to start without PPM_PASSWORD/PPM_PASSWORD_HASH unless PPM_ALLOW_NO_AUTH=1 (local dev only) - Add login rate limiting (5 failures / 60s per client), enforced inside SessionManager.login so it cannot be bypassed at the endpoint layer - compose defaults PPM_COOKIE_SECURE=true for HTTPS behind reverse proxy - Add .dockerignore to keep runtime data/out of the image Features: - Task timeline gantt on home page (week/month zoom, horizontal scroll, infinite-arrow for open-ended dates, CSS Grid layout) - Duration metrics gain a second/minute/hour unit for input & display (canonical storage stays integer seconds) - Per-metric progress bars on home page (no more merged average) - Backfill historical records via date picker in the today-record card - Admin panel: stats overview, JSON import/restore, full task list mgmt Fixes: - Nullable task startDate; summarize handles missing start date - Task dialog cancel/close no longer submits the form - Import validates whole backup first, rejects path traversal, rebuilds archives, and replaces stale files Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,14 +26,14 @@
|
||||
</div>
|
||||
|
||||
<dialog id="taskDialog" class="dialog task-dialog">
|
||||
<form id="taskForm" method="dialog">
|
||||
<form id="taskForm">
|
||||
<div class="dialog-heading">
|
||||
<div><p class="eyebrow">任务定义</p><h2 id="taskDialogTitle">新建任务</h2></div>
|
||||
<button class="icon-button" value="cancel" formmethod="dialog" title="关闭" aria-label="关闭">×</button>
|
||||
<button class="icon-button" id="closeTaskButton" type="button" title="关闭" aria-label="关闭">×</button>
|
||||
</div>
|
||||
<div class="form-grid">
|
||||
<label class="wide">任务名称<input name="name" required maxlength="120"></label>
|
||||
<label>开始日期<input name="startDate" type="date" required></label>
|
||||
<label>开始日期<input name="startDate" type="date"></label>
|
||||
<label>结束日期<input name="endDate" type="date"></label>
|
||||
<label>优先级<select name="priority"><option value="1">1 · 紧急</option><option value="2">2 · 高</option><option value="3" selected>3 · 正常</option><option value="4">4 · 低</option><option value="5">5 · 挂起候选</option></select></label>
|
||||
<label>状态<select name="state"><option value="active">进行中</option><option value="paused">已挂起</option></select></label>
|
||||
@@ -41,13 +41,16 @@
|
||||
</div>
|
||||
<div class="metric-heading"><div><p class="eyebrow">衡量标准</p><h3>多个指标可同时记录</h3></div><button class="button subtle" id="addMetricButton" type="button">+ 添加指标</button></div>
|
||||
<div id="metricEditor" class="metric-editor"></div>
|
||||
<div class="dialog-actions"><button class="button" value="cancel" formmethod="dialog">取消</button><button class="button primary" id="saveTaskButton" type="submit">保存任务</button></div>
|
||||
<div class="dialog-actions"><button class="button" id="cancelTaskButton" type="button">取消</button><button class="button primary" id="saveTaskButton" type="submit">保存任务</button></div>
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<dialog id="adminDialog" class="dialog admin-dialog">
|
||||
<div class="dialog-heading"><div><p class="eyebrow">后台</p><h2>数据管理</h2></div><button class="icon-button" id="closeAdminButton" title="关闭" aria-label="关闭">×</button></div>
|
||||
<div class="admin-actions"><button class="button" id="exportButton">导出 JSON</button><button class="button" id="archiveButton">执行补归档</button><button class="button" id="logoutButton">退出登录</button></div>
|
||||
<div class="admin-actions"><button class="button" id="exportButton">导出 JSON</button><button class="button" id="importButton">导入还原</button><input type="file" id="importFile" accept="application/json,.json" hidden><button class="button" id="archiveButton">执行补归档</button><button class="button" id="logoutButton">退出登录</button></div>
|
||||
<div class="admin-stats" id="adminStats"></div>
|
||||
<h3>全部任务</h3>
|
||||
<div id="taskAdminList" class="trash-list"></div>
|
||||
<h3>回收站</h3>
|
||||
<div id="trashList" class="trash-list"></div>
|
||||
</dialog>
|
||||
|
||||
Reference in New Issue
Block a user