@1mancompany/onemancompany 0.7.23 → 0.7.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/frontend/app.js +325 -0
- package/frontend/style.css +285 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/onemancompany/agents/product_tools.py +147 -1
- package/src/onemancompany/api/routes.py +182 -0
- package/src/onemancompany/core/config.py +2 -0
- package/src/onemancompany/core/models.py +9 -0
- package/src/onemancompany/core/product.py +379 -3
- package/src/onemancompany/core/product_triggers.py +132 -1
package/frontend/app.js
CHANGED
|
@@ -7528,6 +7528,9 @@ class AppController {
|
|
|
7528
7528
|
const tabDefs = [
|
|
7529
7529
|
{ id: 'overview', label: 'Overview' },
|
|
7530
7530
|
{ id: 'issues', label: `Issues (${issues.length})` },
|
|
7531
|
+
{ id: 'kanban', label: 'Kanban' },
|
|
7532
|
+
{ id: 'roadmap', label: 'Roadmap' },
|
|
7533
|
+
{ id: 'activity', label: 'Activity' },
|
|
7531
7534
|
{ id: 'projects', label: `Projects (${projects.length})` },
|
|
7532
7535
|
];
|
|
7533
7536
|
const tabContent = document.createElement('div');
|
|
@@ -7559,6 +7562,12 @@ class AppController {
|
|
|
7559
7562
|
this._renderProductOverview(product, versions, slug, container);
|
|
7560
7563
|
} else if (tabId === 'issues') {
|
|
7561
7564
|
this._renderProductIssues(issues, slug, container, data);
|
|
7565
|
+
} else if (tabId === 'kanban') {
|
|
7566
|
+
this._renderProductKanban(slug, container, data);
|
|
7567
|
+
} else if (tabId === 'roadmap') {
|
|
7568
|
+
this._renderProductRoadmap(slug, container);
|
|
7569
|
+
} else if (tabId === 'activity') {
|
|
7570
|
+
this._renderProductActivity(slug, container);
|
|
7562
7571
|
} else if (tabId === 'projects') {
|
|
7563
7572
|
this._renderProductProjects(projects, container);
|
|
7564
7573
|
}
|
|
@@ -8246,6 +8255,322 @@ class AppController {
|
|
|
8246
8255
|
}
|
|
8247
8256
|
}
|
|
8248
8257
|
|
|
8258
|
+
// ---------------------------------------------------------------------------
|
|
8259
|
+
// Kanban Board Tab
|
|
8260
|
+
// ---------------------------------------------------------------------------
|
|
8261
|
+
|
|
8262
|
+
_renderProductKanban(slug, container, fullData) {
|
|
8263
|
+
container.innerHTML = '<div class="loading-text">Loading kanban...</div>';
|
|
8264
|
+
fetch(`/api/product/${encodeURIComponent(slug)}/kanban`)
|
|
8265
|
+
.then(r => r.json())
|
|
8266
|
+
.then(data => {
|
|
8267
|
+
container.innerHTML = '';
|
|
8268
|
+
const board = document.createElement('div');
|
|
8269
|
+
board.className = 'kanban-board';
|
|
8270
|
+
|
|
8271
|
+
const statusLabels = {
|
|
8272
|
+
backlog: 'Backlog',
|
|
8273
|
+
planned: 'Planned',
|
|
8274
|
+
in_progress: 'In Progress',
|
|
8275
|
+
in_review: 'In Review',
|
|
8276
|
+
done: 'Done',
|
|
8277
|
+
released: 'Released',
|
|
8278
|
+
};
|
|
8279
|
+
const blockedSet = new Set(data.blocked_ids || []);
|
|
8280
|
+
|
|
8281
|
+
for (const [status, label] of Object.entries(statusLabels)) {
|
|
8282
|
+
const col = document.createElement('div');
|
|
8283
|
+
col.className = 'kanban-column';
|
|
8284
|
+
col.dataset.status = status;
|
|
8285
|
+
|
|
8286
|
+
const colHeader = document.createElement('div');
|
|
8287
|
+
colHeader.className = 'kanban-column-header';
|
|
8288
|
+
const items = data.columns[status] || [];
|
|
8289
|
+
colHeader.textContent = `${label} (${items.length})`;
|
|
8290
|
+
col.appendChild(colHeader);
|
|
8291
|
+
|
|
8292
|
+
const cardList = document.createElement('div');
|
|
8293
|
+
cardList.className = 'kanban-card-list';
|
|
8294
|
+
|
|
8295
|
+
// Drag-drop: allow dropping on column
|
|
8296
|
+
cardList.addEventListener('dragover', (e) => { e.preventDefault(); cardList.classList.add('kanban-drop-target'); });
|
|
8297
|
+
cardList.addEventListener('dragleave', () => cardList.classList.remove('kanban-drop-target'));
|
|
8298
|
+
cardList.addEventListener('drop', (e) => {
|
|
8299
|
+
e.preventDefault();
|
|
8300
|
+
cardList.classList.remove('kanban-drop-target');
|
|
8301
|
+
const issueId = e.dataTransfer.getData('text/plain');
|
|
8302
|
+
if (issueId) {
|
|
8303
|
+
fetch(`/api/product/${encodeURIComponent(slug)}/issue/${encodeURIComponent(issueId)}`, {
|
|
8304
|
+
method: 'PUT',
|
|
8305
|
+
headers: { 'Content-Type': 'application/json' },
|
|
8306
|
+
body: JSON.stringify({ status }),
|
|
8307
|
+
}).then(() => this._renderProductKanban(slug, container, fullData));
|
|
8308
|
+
}
|
|
8309
|
+
});
|
|
8310
|
+
|
|
8311
|
+
for (const issue of items) {
|
|
8312
|
+
const card = document.createElement('div');
|
|
8313
|
+
card.className = `kanban-card priority-${(issue.priority || 'p2').toLowerCase()}`;
|
|
8314
|
+
card.draggable = true;
|
|
8315
|
+
card.dataset.issueId = issue.id;
|
|
8316
|
+
if (blockedSet.has(issue.id)) card.classList.add('kanban-blocked');
|
|
8317
|
+
|
|
8318
|
+
card.addEventListener('dragstart', (e) => {
|
|
8319
|
+
e.dataTransfer.setData('text/plain', issue.id);
|
|
8320
|
+
card.classList.add('dragging');
|
|
8321
|
+
});
|
|
8322
|
+
card.addEventListener('dragend', () => card.classList.remove('dragging'));
|
|
8323
|
+
|
|
8324
|
+
const priTag = document.createElement('span');
|
|
8325
|
+
priTag.className = `kanban-priority priority-${(issue.priority || 'p2').toLowerCase()}`;
|
|
8326
|
+
priTag.textContent = issue.priority || 'P2';
|
|
8327
|
+
|
|
8328
|
+
const title = document.createElement('span');
|
|
8329
|
+
title.className = 'kanban-card-title';
|
|
8330
|
+
title.textContent = issue.title;
|
|
8331
|
+
|
|
8332
|
+
const meta = document.createElement('div');
|
|
8333
|
+
meta.className = 'kanban-card-meta';
|
|
8334
|
+
if (issue.assignee_id) {
|
|
8335
|
+
meta.textContent = issue.assignee_id;
|
|
8336
|
+
}
|
|
8337
|
+
if (issue.story_points) {
|
|
8338
|
+
const sp = document.createElement('span');
|
|
8339
|
+
sp.className = 'kanban-sp';
|
|
8340
|
+
sp.textContent = `${issue.story_points}sp`;
|
|
8341
|
+
meta.appendChild(sp);
|
|
8342
|
+
}
|
|
8343
|
+
if (blockedSet.has(issue.id)) {
|
|
8344
|
+
const lock = document.createElement('span');
|
|
8345
|
+
lock.className = 'kanban-blocked-icon';
|
|
8346
|
+
lock.textContent = '🔒';
|
|
8347
|
+
lock.title = 'Blocked by dependency';
|
|
8348
|
+
meta.appendChild(lock);
|
|
8349
|
+
}
|
|
8350
|
+
|
|
8351
|
+
card.appendChild(priTag);
|
|
8352
|
+
card.appendChild(title);
|
|
8353
|
+
card.appendChild(meta);
|
|
8354
|
+
cardList.appendChild(card);
|
|
8355
|
+
}
|
|
8356
|
+
|
|
8357
|
+
col.appendChild(cardList);
|
|
8358
|
+
board.appendChild(col);
|
|
8359
|
+
}
|
|
8360
|
+
|
|
8361
|
+
container.appendChild(board);
|
|
8362
|
+
})
|
|
8363
|
+
.catch(err => { container.innerHTML = `<div class="error-text">Failed to load kanban: ${err.message}</div>`; });
|
|
8364
|
+
}
|
|
8365
|
+
|
|
8366
|
+
// ---------------------------------------------------------------------------
|
|
8367
|
+
// Roadmap Timeline Tab
|
|
8368
|
+
// ---------------------------------------------------------------------------
|
|
8369
|
+
|
|
8370
|
+
_renderProductRoadmap(slug, container) {
|
|
8371
|
+
container.innerHTML = '<div class="loading-text">Loading roadmap...</div>';
|
|
8372
|
+
fetch(`/api/product/${encodeURIComponent(slug)}/roadmap`)
|
|
8373
|
+
.then(r => r.json())
|
|
8374
|
+
.then(data => {
|
|
8375
|
+
container.innerHTML = '';
|
|
8376
|
+
|
|
8377
|
+
if (!data.sprints.length && !data.versions.length && !data.milestoned_issues.length) {
|
|
8378
|
+
container.innerHTML = '<div class="task-empty">No sprints, versions, or milestoned issues yet.</div>';
|
|
8379
|
+
return;
|
|
8380
|
+
}
|
|
8381
|
+
|
|
8382
|
+
// Sprints section
|
|
8383
|
+
if (data.sprints.length) {
|
|
8384
|
+
const section = document.createElement('div');
|
|
8385
|
+
section.className = 'roadmap-section';
|
|
8386
|
+
const h = document.createElement('h3');
|
|
8387
|
+
h.textContent = 'Sprints';
|
|
8388
|
+
section.appendChild(h);
|
|
8389
|
+
|
|
8390
|
+
const timeline = document.createElement('div');
|
|
8391
|
+
timeline.className = 'roadmap-timeline';
|
|
8392
|
+
|
|
8393
|
+
for (const s of data.sprints) {
|
|
8394
|
+
const bar = document.createElement('div');
|
|
8395
|
+
bar.className = `roadmap-sprint-bar roadmap-status-${s.status}`;
|
|
8396
|
+
|
|
8397
|
+
const label = document.createElement('div');
|
|
8398
|
+
label.className = 'roadmap-bar-label';
|
|
8399
|
+
label.textContent = `${s.name} (${s.issue_count} issues)`;
|
|
8400
|
+
|
|
8401
|
+
const dates = document.createElement('div');
|
|
8402
|
+
dates.className = 'roadmap-bar-dates';
|
|
8403
|
+
dates.textContent = `${s.start_date} → ${s.end_date}`;
|
|
8404
|
+
|
|
8405
|
+
const statusBadge = document.createElement('span');
|
|
8406
|
+
statusBadge.className = `roadmap-status-badge roadmap-status-${s.status}`;
|
|
8407
|
+
statusBadge.textContent = s.status;
|
|
8408
|
+
|
|
8409
|
+
bar.appendChild(label);
|
|
8410
|
+
bar.appendChild(dates);
|
|
8411
|
+
bar.appendChild(statusBadge);
|
|
8412
|
+
if (s.goal) {
|
|
8413
|
+
const goal = document.createElement('div');
|
|
8414
|
+
goal.className = 'roadmap-goal';
|
|
8415
|
+
goal.textContent = s.goal;
|
|
8416
|
+
bar.appendChild(goal);
|
|
8417
|
+
}
|
|
8418
|
+
timeline.appendChild(bar);
|
|
8419
|
+
}
|
|
8420
|
+
section.appendChild(timeline);
|
|
8421
|
+
container.appendChild(section);
|
|
8422
|
+
}
|
|
8423
|
+
|
|
8424
|
+
// Versions section
|
|
8425
|
+
if (data.versions.length) {
|
|
8426
|
+
const section = document.createElement('div');
|
|
8427
|
+
section.className = 'roadmap-section';
|
|
8428
|
+
const h = document.createElement('h3');
|
|
8429
|
+
h.textContent = 'Releases';
|
|
8430
|
+
section.appendChild(h);
|
|
8431
|
+
|
|
8432
|
+
for (const v of data.versions) {
|
|
8433
|
+
const row = document.createElement('div');
|
|
8434
|
+
row.className = 'roadmap-version-row';
|
|
8435
|
+
|
|
8436
|
+
const ver = document.createElement('span');
|
|
8437
|
+
ver.className = 'roadmap-version-tag';
|
|
8438
|
+
ver.textContent = `v${v.version}`;
|
|
8439
|
+
|
|
8440
|
+
const date = document.createElement('span');
|
|
8441
|
+
date.className = 'roadmap-version-date';
|
|
8442
|
+
date.textContent = v.released_at ? v.released_at.split('T')[0] : '';
|
|
8443
|
+
|
|
8444
|
+
const count = document.createElement('span');
|
|
8445
|
+
count.className = 'roadmap-version-count';
|
|
8446
|
+
count.textContent = `${v.resolved_count} issues resolved`;
|
|
8447
|
+
|
|
8448
|
+
row.appendChild(ver);
|
|
8449
|
+
row.appendChild(date);
|
|
8450
|
+
row.appendChild(count);
|
|
8451
|
+
section.appendChild(row);
|
|
8452
|
+
}
|
|
8453
|
+
container.appendChild(section);
|
|
8454
|
+
}
|
|
8455
|
+
|
|
8456
|
+
// Milestoned issues
|
|
8457
|
+
if (data.milestoned_issues.length) {
|
|
8458
|
+
const section = document.createElement('div');
|
|
8459
|
+
section.className = 'roadmap-section';
|
|
8460
|
+
const h = document.createElement('h3');
|
|
8461
|
+
h.textContent = 'Milestoned Issues';
|
|
8462
|
+
section.appendChild(h);
|
|
8463
|
+
|
|
8464
|
+
// Group by milestone_version
|
|
8465
|
+
const groups = {};
|
|
8466
|
+
for (const i of data.milestoned_issues) {
|
|
8467
|
+
const mv = i.milestone_version;
|
|
8468
|
+
if (!groups[mv]) groups[mv] = [];
|
|
8469
|
+
groups[mv].push(i);
|
|
8470
|
+
}
|
|
8471
|
+
|
|
8472
|
+
for (const [ver, items] of Object.entries(groups).sort()) {
|
|
8473
|
+
const group = document.createElement('div');
|
|
8474
|
+
group.className = 'roadmap-milestone-group';
|
|
8475
|
+
|
|
8476
|
+
const gh = document.createElement('div');
|
|
8477
|
+
gh.className = 'roadmap-milestone-header';
|
|
8478
|
+
gh.textContent = `v${ver} (${items.length} issues)`;
|
|
8479
|
+
group.appendChild(gh);
|
|
8480
|
+
|
|
8481
|
+
for (const item of items) {
|
|
8482
|
+
const row = document.createElement('div');
|
|
8483
|
+
row.className = `roadmap-issue-row priority-${(item.priority || 'p2').toLowerCase()}`;
|
|
8484
|
+
row.innerHTML = `<span class="roadmap-issue-pri">[${item.priority}]</span> ${item.title} <span class="roadmap-issue-status">${item.status}</span>`;
|
|
8485
|
+
group.appendChild(row);
|
|
8486
|
+
}
|
|
8487
|
+
|
|
8488
|
+
section.appendChild(group);
|
|
8489
|
+
}
|
|
8490
|
+
container.appendChild(section);
|
|
8491
|
+
}
|
|
8492
|
+
})
|
|
8493
|
+
.catch(err => { container.innerHTML = `<div class="error-text">Failed to load roadmap: ${err.message}</div>`; });
|
|
8494
|
+
}
|
|
8495
|
+
|
|
8496
|
+
// ---------------------------------------------------------------------------
|
|
8497
|
+
// Activity Feed Tab
|
|
8498
|
+
// ---------------------------------------------------------------------------
|
|
8499
|
+
|
|
8500
|
+
_renderProductActivity(slug, container) {
|
|
8501
|
+
container.innerHTML = '<div class="loading-text">Loading activity...</div>';
|
|
8502
|
+
fetch(`/api/product/${encodeURIComponent(slug)}/activity?limit=100`)
|
|
8503
|
+
.then(r => r.json())
|
|
8504
|
+
.then(entries => {
|
|
8505
|
+
container.innerHTML = '';
|
|
8506
|
+
|
|
8507
|
+
if (!entries.length) {
|
|
8508
|
+
container.innerHTML = '<div class="task-empty">No activity recorded yet.</div>';
|
|
8509
|
+
return;
|
|
8510
|
+
}
|
|
8511
|
+
|
|
8512
|
+
const feed = document.createElement('div');
|
|
8513
|
+
feed.className = 'activity-feed';
|
|
8514
|
+
|
|
8515
|
+
const eventIcons = {
|
|
8516
|
+
issue_created: '📋',
|
|
8517
|
+
issue_closed: '✅',
|
|
8518
|
+
issue_assigned: '👤',
|
|
8519
|
+
sprint_created: '🏃',
|
|
8520
|
+
sprint_closed: '🏁',
|
|
8521
|
+
version_released: '🚀',
|
|
8522
|
+
review_created: '📝',
|
|
8523
|
+
review_completed: '☑️',
|
|
8524
|
+
kr_updated: '📊',
|
|
8525
|
+
};
|
|
8526
|
+
|
|
8527
|
+
for (const entry of entries) {
|
|
8528
|
+
const item = document.createElement('div');
|
|
8529
|
+
item.className = 'activity-item';
|
|
8530
|
+
|
|
8531
|
+
const icon = document.createElement('span');
|
|
8532
|
+
icon.className = 'activity-icon';
|
|
8533
|
+
icon.textContent = eventIcons[entry.event_type] || '•';
|
|
8534
|
+
|
|
8535
|
+
const content = document.createElement('div');
|
|
8536
|
+
content.className = 'activity-content';
|
|
8537
|
+
|
|
8538
|
+
const headerLine = document.createElement('div');
|
|
8539
|
+
headerLine.className = 'activity-header';
|
|
8540
|
+
const typeLabel = document.createElement('span');
|
|
8541
|
+
typeLabel.className = 'activity-type';
|
|
8542
|
+
typeLabel.textContent = (entry.event_type || '').replace(/_/g, ' ');
|
|
8543
|
+
const actor = document.createElement('span');
|
|
8544
|
+
actor.className = 'activity-actor';
|
|
8545
|
+
actor.textContent = entry.actor || '';
|
|
8546
|
+
headerLine.appendChild(typeLabel);
|
|
8547
|
+
headerLine.appendChild(actor);
|
|
8548
|
+
|
|
8549
|
+
const detail = document.createElement('div');
|
|
8550
|
+
detail.className = 'activity-detail';
|
|
8551
|
+
detail.textContent = entry.detail || '';
|
|
8552
|
+
|
|
8553
|
+
const ts = document.createElement('div');
|
|
8554
|
+
ts.className = 'activity-ts';
|
|
8555
|
+
if (entry.ts) {
|
|
8556
|
+
const d = new Date(entry.ts);
|
|
8557
|
+
ts.textContent = d.toLocaleString();
|
|
8558
|
+
}
|
|
8559
|
+
|
|
8560
|
+
content.appendChild(headerLine);
|
|
8561
|
+
content.appendChild(detail);
|
|
8562
|
+
content.appendChild(ts);
|
|
8563
|
+
|
|
8564
|
+
item.appendChild(icon);
|
|
8565
|
+
item.appendChild(content);
|
|
8566
|
+
feed.appendChild(item);
|
|
8567
|
+
}
|
|
8568
|
+
|
|
8569
|
+
container.appendChild(feed);
|
|
8570
|
+
})
|
|
8571
|
+
.catch(err => { container.innerHTML = `<div class="error-text">Failed to load activity: ${err.message}</div>`; });
|
|
8572
|
+
}
|
|
8573
|
+
|
|
8249
8574
|
_doUpdateProjectsPanel() {
|
|
8250
8575
|
const panel = document.getElementById('projects-panel-list');
|
|
8251
8576
|
if (!panel) return;
|
package/frontend/style.css
CHANGED
|
@@ -6173,6 +6173,291 @@ body.resize-dragging {
|
|
|
6173
6173
|
align-items: center;
|
|
6174
6174
|
}
|
|
6175
6175
|
|
|
6176
|
+
/* ================================================================
|
|
6177
|
+
Kanban Board
|
|
6178
|
+
================================================================ */
|
|
6179
|
+
|
|
6180
|
+
.kanban-board {
|
|
6181
|
+
display: flex;
|
|
6182
|
+
gap: 8px;
|
|
6183
|
+
overflow-x: auto;
|
|
6184
|
+
padding: 4px 0;
|
|
6185
|
+
min-height: 200px;
|
|
6186
|
+
}
|
|
6187
|
+
|
|
6188
|
+
.kanban-column {
|
|
6189
|
+
flex: 1;
|
|
6190
|
+
min-width: 130px;
|
|
6191
|
+
max-width: 200px;
|
|
6192
|
+
background: rgba(255,255,255,0.02);
|
|
6193
|
+
border: 1px solid var(--border);
|
|
6194
|
+
border-radius: 2px;
|
|
6195
|
+
}
|
|
6196
|
+
|
|
6197
|
+
.kanban-column-header {
|
|
6198
|
+
padding: 6px 8px;
|
|
6199
|
+
font-size: calc(6px + var(--font-boost));
|
|
6200
|
+
color: var(--pixel-cyan);
|
|
6201
|
+
border-bottom: 1px solid var(--border);
|
|
6202
|
+
text-align: center;
|
|
6203
|
+
font-weight: bold;
|
|
6204
|
+
}
|
|
6205
|
+
|
|
6206
|
+
.kanban-card-list {
|
|
6207
|
+
padding: 4px;
|
|
6208
|
+
min-height: 40px;
|
|
6209
|
+
}
|
|
6210
|
+
|
|
6211
|
+
.kanban-card-list.kanban-drop-target {
|
|
6212
|
+
background: rgba(0,255,255,0.05);
|
|
6213
|
+
outline: 1px dashed var(--pixel-cyan);
|
|
6214
|
+
}
|
|
6215
|
+
|
|
6216
|
+
.kanban-card {
|
|
6217
|
+
background: rgba(0,0,0,0.3);
|
|
6218
|
+
border: 1px solid var(--border);
|
|
6219
|
+
border-left: 3px solid var(--text-dim);
|
|
6220
|
+
border-radius: 2px;
|
|
6221
|
+
padding: 4px 6px;
|
|
6222
|
+
margin-bottom: 4px;
|
|
6223
|
+
cursor: grab;
|
|
6224
|
+
font-size: calc(5px + var(--font-boost));
|
|
6225
|
+
transition: opacity 0.15s;
|
|
6226
|
+
}
|
|
6227
|
+
|
|
6228
|
+
.kanban-card.dragging {
|
|
6229
|
+
opacity: 0.4;
|
|
6230
|
+
}
|
|
6231
|
+
|
|
6232
|
+
.kanban-card.priority-p0 { border-left-color: #ff4444; }
|
|
6233
|
+
.kanban-card.priority-p1 { border-left-color: #ff8800; }
|
|
6234
|
+
.kanban-card.priority-p2 { border-left-color: var(--pixel-yellow); }
|
|
6235
|
+
.kanban-card.priority-p3 { border-left-color: var(--text-dim); }
|
|
6236
|
+
|
|
6237
|
+
.kanban-card.kanban-blocked {
|
|
6238
|
+
background: rgba(255,68,68,0.08);
|
|
6239
|
+
}
|
|
6240
|
+
|
|
6241
|
+
.kanban-priority {
|
|
6242
|
+
font-size: calc(4px + var(--font-boost));
|
|
6243
|
+
padding: 0 3px;
|
|
6244
|
+
border-radius: 1px;
|
|
6245
|
+
margin-right: 4px;
|
|
6246
|
+
}
|
|
6247
|
+
|
|
6248
|
+
.kanban-card-title {
|
|
6249
|
+
color: var(--pixel-white);
|
|
6250
|
+
word-break: break-word;
|
|
6251
|
+
}
|
|
6252
|
+
|
|
6253
|
+
.kanban-card-meta {
|
|
6254
|
+
color: var(--text-dim);
|
|
6255
|
+
font-size: calc(4px + var(--font-boost));
|
|
6256
|
+
margin-top: 3px;
|
|
6257
|
+
display: flex;
|
|
6258
|
+
gap: 4px;
|
|
6259
|
+
align-items: center;
|
|
6260
|
+
}
|
|
6261
|
+
|
|
6262
|
+
.kanban-sp {
|
|
6263
|
+
background: rgba(255,255,255,0.08);
|
|
6264
|
+
padding: 0 3px;
|
|
6265
|
+
border-radius: 1px;
|
|
6266
|
+
}
|
|
6267
|
+
|
|
6268
|
+
.kanban-blocked-icon {
|
|
6269
|
+
font-size: calc(5px + var(--font-boost));
|
|
6270
|
+
}
|
|
6271
|
+
|
|
6272
|
+
/* ================================================================
|
|
6273
|
+
Roadmap Timeline
|
|
6274
|
+
================================================================ */
|
|
6275
|
+
|
|
6276
|
+
.roadmap-section {
|
|
6277
|
+
margin-bottom: 16px;
|
|
6278
|
+
}
|
|
6279
|
+
|
|
6280
|
+
.roadmap-section h3 {
|
|
6281
|
+
color: var(--pixel-cyan);
|
|
6282
|
+
font-size: calc(7px + var(--font-boost));
|
|
6283
|
+
margin: 0 0 8px 0;
|
|
6284
|
+
border-bottom: 1px solid var(--border);
|
|
6285
|
+
padding-bottom: 4px;
|
|
6286
|
+
}
|
|
6287
|
+
|
|
6288
|
+
.roadmap-timeline {
|
|
6289
|
+
display: flex;
|
|
6290
|
+
flex-direction: column;
|
|
6291
|
+
gap: 6px;
|
|
6292
|
+
}
|
|
6293
|
+
|
|
6294
|
+
.roadmap-sprint-bar {
|
|
6295
|
+
background: rgba(0,255,255,0.05);
|
|
6296
|
+
border: 1px solid var(--border);
|
|
6297
|
+
border-left: 3px solid var(--pixel-cyan);
|
|
6298
|
+
border-radius: 2px;
|
|
6299
|
+
padding: 6px 8px;
|
|
6300
|
+
}
|
|
6301
|
+
|
|
6302
|
+
.roadmap-sprint-bar.roadmap-status-active {
|
|
6303
|
+
border-left-color: var(--pixel-green);
|
|
6304
|
+
background: rgba(0,255,0,0.05);
|
|
6305
|
+
}
|
|
6306
|
+
|
|
6307
|
+
.roadmap-sprint-bar.roadmap-status-closed {
|
|
6308
|
+
border-left-color: var(--text-dim);
|
|
6309
|
+
opacity: 0.7;
|
|
6310
|
+
}
|
|
6311
|
+
|
|
6312
|
+
.roadmap-bar-label {
|
|
6313
|
+
color: var(--pixel-white);
|
|
6314
|
+
font-size: calc(6px + var(--font-boost));
|
|
6315
|
+
font-weight: bold;
|
|
6316
|
+
}
|
|
6317
|
+
|
|
6318
|
+
.roadmap-bar-dates {
|
|
6319
|
+
color: var(--text-dim);
|
|
6320
|
+
font-size: calc(5px + var(--font-boost));
|
|
6321
|
+
margin-top: 2px;
|
|
6322
|
+
}
|
|
6323
|
+
|
|
6324
|
+
.roadmap-status-badge {
|
|
6325
|
+
display: inline-block;
|
|
6326
|
+
font-size: calc(4px + var(--font-boost));
|
|
6327
|
+
padding: 0 4px;
|
|
6328
|
+
border-radius: 2px;
|
|
6329
|
+
margin-top: 3px;
|
|
6330
|
+
color: var(--pixel-cyan);
|
|
6331
|
+
border: 1px solid var(--border);
|
|
6332
|
+
}
|
|
6333
|
+
|
|
6334
|
+
.roadmap-status-badge.roadmap-status-active { color: var(--pixel-green); border-color: var(--pixel-green); }
|
|
6335
|
+
.roadmap-status-badge.roadmap-status-closed { color: var(--text-dim); border-color: var(--text-dim); }
|
|
6336
|
+
|
|
6337
|
+
.roadmap-goal {
|
|
6338
|
+
color: var(--text-dim);
|
|
6339
|
+
font-size: calc(5px + var(--font-boost));
|
|
6340
|
+
font-style: italic;
|
|
6341
|
+
margin-top: 2px;
|
|
6342
|
+
}
|
|
6343
|
+
|
|
6344
|
+
.roadmap-version-row {
|
|
6345
|
+
display: flex;
|
|
6346
|
+
align-items: center;
|
|
6347
|
+
gap: 10px;
|
|
6348
|
+
padding: 4px 0;
|
|
6349
|
+
border-bottom: 1px solid rgba(255,255,255,0.03);
|
|
6350
|
+
font-size: calc(6px + var(--font-boost));
|
|
6351
|
+
}
|
|
6352
|
+
|
|
6353
|
+
.roadmap-version-tag {
|
|
6354
|
+
color: var(--pixel-green);
|
|
6355
|
+
font-weight: bold;
|
|
6356
|
+
min-width: 60px;
|
|
6357
|
+
}
|
|
6358
|
+
|
|
6359
|
+
.roadmap-version-date {
|
|
6360
|
+
color: var(--text-dim);
|
|
6361
|
+
min-width: 80px;
|
|
6362
|
+
}
|
|
6363
|
+
|
|
6364
|
+
.roadmap-version-count {
|
|
6365
|
+
color: var(--pixel-white);
|
|
6366
|
+
}
|
|
6367
|
+
|
|
6368
|
+
.roadmap-milestone-group {
|
|
6369
|
+
margin-bottom: 10px;
|
|
6370
|
+
}
|
|
6371
|
+
|
|
6372
|
+
.roadmap-milestone-header {
|
|
6373
|
+
color: var(--pixel-yellow);
|
|
6374
|
+
font-size: calc(6px + var(--font-boost));
|
|
6375
|
+
font-weight: bold;
|
|
6376
|
+
margin-bottom: 4px;
|
|
6377
|
+
}
|
|
6378
|
+
|
|
6379
|
+
.roadmap-issue-row {
|
|
6380
|
+
padding: 2px 8px;
|
|
6381
|
+
font-size: calc(5px + var(--font-boost));
|
|
6382
|
+
color: var(--pixel-white);
|
|
6383
|
+
border-left: 2px solid var(--text-dim);
|
|
6384
|
+
margin-left: 8px;
|
|
6385
|
+
}
|
|
6386
|
+
|
|
6387
|
+
.roadmap-issue-row.priority-p0 { border-left-color: #ff4444; }
|
|
6388
|
+
.roadmap-issue-row.priority-p1 { border-left-color: #ff8800; }
|
|
6389
|
+
|
|
6390
|
+
.roadmap-issue-pri {
|
|
6391
|
+
color: var(--text-dim);
|
|
6392
|
+
margin-right: 4px;
|
|
6393
|
+
}
|
|
6394
|
+
|
|
6395
|
+
.roadmap-issue-status {
|
|
6396
|
+
color: var(--text-dim);
|
|
6397
|
+
font-size: calc(4px + var(--font-boost));
|
|
6398
|
+
margin-left: 6px;
|
|
6399
|
+
}
|
|
6400
|
+
|
|
6401
|
+
/* ================================================================
|
|
6402
|
+
Activity Feed
|
|
6403
|
+
================================================================ */
|
|
6404
|
+
|
|
6405
|
+
.activity-feed {
|
|
6406
|
+
display: flex;
|
|
6407
|
+
flex-direction: column;
|
|
6408
|
+
gap: 2px;
|
|
6409
|
+
}
|
|
6410
|
+
|
|
6411
|
+
.activity-item {
|
|
6412
|
+
display: flex;
|
|
6413
|
+
gap: 8px;
|
|
6414
|
+
padding: 6px 8px;
|
|
6415
|
+
border-bottom: 1px solid rgba(255,255,255,0.03);
|
|
6416
|
+
}
|
|
6417
|
+
|
|
6418
|
+
.activity-icon {
|
|
6419
|
+
font-size: calc(7px + var(--font-boost));
|
|
6420
|
+
flex-shrink: 0;
|
|
6421
|
+
width: 20px;
|
|
6422
|
+
text-align: center;
|
|
6423
|
+
}
|
|
6424
|
+
|
|
6425
|
+
.activity-content {
|
|
6426
|
+
flex: 1;
|
|
6427
|
+
min-width: 0;
|
|
6428
|
+
}
|
|
6429
|
+
|
|
6430
|
+
.activity-header {
|
|
6431
|
+
display: flex;
|
|
6432
|
+
gap: 8px;
|
|
6433
|
+
align-items: center;
|
|
6434
|
+
}
|
|
6435
|
+
|
|
6436
|
+
.activity-type {
|
|
6437
|
+
color: var(--pixel-cyan);
|
|
6438
|
+
font-size: calc(5px + var(--font-boost));
|
|
6439
|
+
font-weight: bold;
|
|
6440
|
+
text-transform: capitalize;
|
|
6441
|
+
}
|
|
6442
|
+
|
|
6443
|
+
.activity-actor {
|
|
6444
|
+
color: var(--text-dim);
|
|
6445
|
+
font-size: calc(4px + var(--font-boost));
|
|
6446
|
+
}
|
|
6447
|
+
|
|
6448
|
+
.activity-detail {
|
|
6449
|
+
color: var(--pixel-white);
|
|
6450
|
+
font-size: calc(5px + var(--font-boost));
|
|
6451
|
+
margin-top: 1px;
|
|
6452
|
+
word-break: break-word;
|
|
6453
|
+
}
|
|
6454
|
+
|
|
6455
|
+
.activity-ts {
|
|
6456
|
+
color: var(--text-dim);
|
|
6457
|
+
font-size: calc(4px + var(--font-boost));
|
|
6458
|
+
margin-top: 1px;
|
|
6459
|
+
}
|
|
6460
|
+
|
|
6176
6461
|
/* Product Detail Button in panel */
|
|
6177
6462
|
.product-detail-btn {
|
|
6178
6463
|
margin-left: auto;
|
package/package.json
CHANGED