Redmine へチケットを起票するボタンを追加
chktime のタスクと git 履歴から下書きを作り、まとめて Redmine へ登録できる ようにした。外部通信はこの機能を使ったときだけで、使わなければ従来どおり ローカルの jsonl を読むだけ。 - Redmine の REST API を叩く最小クライアント (標準ライブラリのみ) - 下書きは「タスクから」(1タスク=1チケット) と「git 履歴から」 (日ごと / 日 x 種別 / 期間一括) の 2 系統 - 起票は件数 x 間隔ぶん時間がかかるのでジョブにし、進捗だけ見に行く - 作成時の status_id は Redmine 側で無視されるため、作成後に付け直す - 連続アクセスに 403 を返すサーバがあるので 1 件ごとに間隔をあける (既定 7 秒) - 自己署名証明書が普通なので、既定は証明書の検証なし - API キーは redmine.json に置き、git 管理外にする Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -297,6 +297,98 @@ table { width: 100%; border-collapse: collapse; }
|
||||
.gantt svg rect.g-hit { fill: transparent; cursor: pointer; }
|
||||
.gantt svg rect.g-hit:hover { fill: #ffffff; opacity: .07; }
|
||||
|
||||
/* Redmine 起票ダイアログ */
|
||||
.hidden { display: none !important; }
|
||||
.modal-back {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, .55);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
}
|
||||
.modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: min(880px, 94vw);
|
||||
height: min(760px, 92vh);
|
||||
background: var(--pane);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.modal-head, .modal-foot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 14px;
|
||||
background: var(--pane2);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.modal-foot { border-bottom: none; border-top: 1px solid var(--line); }
|
||||
.modal-head .spacer, .modal-foot .spacer { flex: 1; }
|
||||
.modal-body { flex: 1; overflow: auto; padding: 12px 14px 20px; }
|
||||
.modal .note { color: var(--dim); font-size: 11px; }
|
||||
.modal .err-inline { color: #f7768e; font-size: 11px; }
|
||||
.modal .go { border-color: var(--work); color: var(--work); }
|
||||
.modal .go:disabled { border-color: var(--line); color: var(--dim); cursor: default; }
|
||||
|
||||
.rm-sec { margin-bottom: 14px; }
|
||||
.rm-sec > h4 {
|
||||
margin: 0 0 6px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
letter-spacing: .08em;
|
||||
color: var(--dim);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.rm-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
|
||||
.rm-row label { color: var(--dim); font-size: 11px; }
|
||||
.modal input[type="text"], .modal input[type="password"], .modal input[type="date"], .modal select {
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 5px;
|
||||
color: var(--fg);
|
||||
padding: 3px 8px;
|
||||
font: inherit;
|
||||
font-size: 12px;
|
||||
color-scheme: dark;
|
||||
}
|
||||
.modal input[type="text"], .modal input[type="password"] { flex: 1 1 220px; min-width: 140px; }
|
||||
.modal input:focus, .modal select:focus { outline: none; border-color: var(--accent); }
|
||||
|
||||
.rm-list { border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
|
||||
.rm-item { border-bottom: 1px solid var(--line); }
|
||||
.rm-item:last-child { border-bottom: none; }
|
||||
.rm-item > .h { display: flex; align-items: flex-start; gap: 8px; padding: 6px 10px; cursor: pointer; }
|
||||
.rm-item > .h:hover { background: var(--pane2); }
|
||||
.rm-item .t { flex: 1; min-width: 0; }
|
||||
.rm-item .subject { font-size: 12.5px; word-break: break-word; }
|
||||
.rm-item .meta { color: var(--dim); font-size: 11px; margin-top: 2px; }
|
||||
.rm-item .body {
|
||||
display: none;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
font-size: 11px;
|
||||
color: var(--dim);
|
||||
background: var(--bg);
|
||||
border-top: 1px solid var(--line);
|
||||
padding: 8px 10px;
|
||||
max-height: 260px;
|
||||
overflow: auto;
|
||||
}
|
||||
.rm-item.open .body { display: block; }
|
||||
.rm-item.off .subject, .rm-item.off .meta { opacity: .45; text-decoration: line-through; }
|
||||
|
||||
.rm-res { display: flex; gap: 8px; padding: 4px 10px; border-bottom: 1px solid var(--line); font-size: 12px; }
|
||||
.rm-res:last-child { border-bottom: none; }
|
||||
.rm-res .id { color: var(--work); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
||||
.rm-res .id.ng { color: #f7768e; }
|
||||
.rm-res .s { flex: 1; min-width: 0; word-break: break-word; }
|
||||
.rm-prog { height: 6px; background: var(--bg); border: 1px solid var(--line); border-radius: 4px; overflow: hidden; margin: 8px 0; }
|
||||
.rm-prog i { display: block; height: 100%; background: var(--work); transition: width .2s; }
|
||||
|
||||
/* ガント (ターン単位) */
|
||||
.gantt .g-no { color: var(--dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
||||
.gantt svg rect.t-wait { fill: var(--user); }
|
||||
|
||||
Reference in New Issue
Block a user