@beastmode-develeap/beastmode 0.1.106 → 0.1.108
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/dist/web/board.html +408 -1
- package/dist/web/build-stamp.txt +1 -1
- package/package.json +1 -1
package/dist/web/board.html
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
}
|
|
16
16
|
</script>
|
|
17
17
|
<!--BOARD_DATA-->
|
|
18
|
-
<script>window.__BUILD_STAMP__ = "
|
|
18
|
+
<script>window.__BUILD_STAMP__ = "20260418-010109-1a0ff01";</script>
|
|
19
19
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
20
20
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
21
21
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
@@ -50,6 +50,10 @@
|
|
|
50
50
|
--accent-subtle: rgba(245, 166, 35, 0.12);
|
|
51
51
|
--accent-glow: rgba(245, 166, 35, 0.2);
|
|
52
52
|
|
|
53
|
+
/* Swimlane colors */
|
|
54
|
+
--purple: #a78bfa;
|
|
55
|
+
--orange: #f97316;
|
|
56
|
+
|
|
53
57
|
/* Semantic */
|
|
54
58
|
--success: #34d399;
|
|
55
59
|
--success-subtle: rgba(52, 211, 153, 0.12);
|
|
@@ -97,6 +101,8 @@
|
|
|
97
101
|
--accent-hover: #E5961A;
|
|
98
102
|
--accent-subtle: rgba(245, 166, 35, 0.10);
|
|
99
103
|
--accent-glow: rgba(245, 166, 35, 0.18);
|
|
104
|
+
--purple: #7c3aed;
|
|
105
|
+
--orange: #ea580c;
|
|
100
106
|
--success: #059669;
|
|
101
107
|
--success-subtle: rgba(5, 150, 105, 0.08);
|
|
102
108
|
--danger: #dc2626;
|
|
@@ -1285,6 +1291,163 @@ input[type="range"]::-webkit-slider-thumb {
|
|
|
1285
1291
|
display: none;
|
|
1286
1292
|
}
|
|
1287
1293
|
|
|
1294
|
+
/* ================================================================
|
|
1295
|
+
PIPELINE VIEW
|
|
1296
|
+
================================================================ */
|
|
1297
|
+
|
|
1298
|
+
.pipeline-view {
|
|
1299
|
+
display: flex;
|
|
1300
|
+
flex-direction: column;
|
|
1301
|
+
gap: 16px;
|
|
1302
|
+
padding: 0 0 24px 0;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
.pipeline-swimlane {
|
|
1306
|
+
background: var(--bg-card);
|
|
1307
|
+
border: 1px solid var(--border);
|
|
1308
|
+
border-radius: var(--radius-lg);
|
|
1309
|
+
overflow: hidden;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
.pipeline-swimlane-collapsed .pipeline-swimlane-body {
|
|
1313
|
+
display: none;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
.pipeline-swimlane-empty {
|
|
1317
|
+
opacity: 0.5;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
.pipeline-swimlane-header {
|
|
1321
|
+
display: flex;
|
|
1322
|
+
align-items: center;
|
|
1323
|
+
gap: 10px;
|
|
1324
|
+
padding: 12px 16px;
|
|
1325
|
+
background: var(--surface-elevated);
|
|
1326
|
+
border-bottom: 1px solid var(--border);
|
|
1327
|
+
border-left: 4px solid var(--lane-color, var(--text-muted));
|
|
1328
|
+
cursor: pointer;
|
|
1329
|
+
user-select: none;
|
|
1330
|
+
transition: background 0.15s ease;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
.pipeline-swimlane-collapsed .pipeline-swimlane-header {
|
|
1334
|
+
border-bottom: none;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
.pipeline-swimlane-header:hover {
|
|
1338
|
+
background: var(--bg-card-hover);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
.pipeline-swimlane-chevron {
|
|
1342
|
+
font-size: 10px;
|
|
1343
|
+
color: var(--text-muted);
|
|
1344
|
+
width: 14px;
|
|
1345
|
+
text-align: center;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
.pipeline-swimlane-color {
|
|
1349
|
+
width: 8px;
|
|
1350
|
+
height: 8px;
|
|
1351
|
+
border-radius: 50%;
|
|
1352
|
+
flex-shrink: 0;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
.pipeline-swimlane-label {
|
|
1356
|
+
font-size: 14px;
|
|
1357
|
+
font-weight: 600;
|
|
1358
|
+
color: var(--text);
|
|
1359
|
+
flex: 1;
|
|
1360
|
+
letter-spacing: 0.3px;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
.pipeline-swimlane-count {
|
|
1364
|
+
background: var(--lane-color, var(--accent));
|
|
1365
|
+
color: #1a1a1a;
|
|
1366
|
+
border-radius: 10px;
|
|
1367
|
+
padding: 1px 8px;
|
|
1368
|
+
font-size: 11px;
|
|
1369
|
+
font-weight: 700;
|
|
1370
|
+
min-width: 22px;
|
|
1371
|
+
text-align: center;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
.pipeline-swimlane-count-zero {
|
|
1375
|
+
background: var(--surface-elevated);
|
|
1376
|
+
color: var(--text-muted);
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
.pipeline-swimlane-body {
|
|
1380
|
+
display: flex;
|
|
1381
|
+
gap: 0;
|
|
1382
|
+
overflow-x: auto;
|
|
1383
|
+
padding: 0;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
.pipeline-swimlane-body::-webkit-scrollbar { height: 6px; }
|
|
1387
|
+
.pipeline-swimlane-body::-webkit-scrollbar-track { background: transparent; }
|
|
1388
|
+
.pipeline-swimlane-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
|
|
1389
|
+
.pipeline-swimlane-body::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
|
|
1390
|
+
|
|
1391
|
+
.pipeline-column {
|
|
1392
|
+
min-width: 200px;
|
|
1393
|
+
max-width: 240px;
|
|
1394
|
+
flex: 1;
|
|
1395
|
+
border-right: 1px solid var(--border-subtle);
|
|
1396
|
+
display: flex;
|
|
1397
|
+
flex-direction: column;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
.pipeline-column:last-child {
|
|
1401
|
+
border-right: none;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
.pipeline-column.drag-over {
|
|
1405
|
+
border: 2px dashed var(--accent);
|
|
1406
|
+
background: var(--accent-subtle);
|
|
1407
|
+
box-shadow: var(--shadow-glow);
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
.pipeline-column-header {
|
|
1411
|
+
padding: 10px 12px;
|
|
1412
|
+
border-top: 3px solid var(--col-color, var(--text-muted));
|
|
1413
|
+
background: var(--bg-card);
|
|
1414
|
+
font-size: 11px;
|
|
1415
|
+
font-weight: 600;
|
|
1416
|
+
color: var(--text-secondary);
|
|
1417
|
+
display: flex;
|
|
1418
|
+
justify-content: space-between;
|
|
1419
|
+
align-items: center;
|
|
1420
|
+
text-transform: uppercase;
|
|
1421
|
+
letter-spacing: 0.3px;
|
|
1422
|
+
cursor: pointer;
|
|
1423
|
+
user-select: none;
|
|
1424
|
+
white-space: nowrap;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
.pipeline-column-items {
|
|
1428
|
+
padding: 6px;
|
|
1429
|
+
flex: 1;
|
|
1430
|
+
min-height: 40px;
|
|
1431
|
+
max-height: 400px;
|
|
1432
|
+
overflow-y: auto;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
@media (max-width: 900px) {
|
|
1436
|
+
.pipeline-swimlane-body {
|
|
1437
|
+
flex-direction: column;
|
|
1438
|
+
overflow-x: hidden;
|
|
1439
|
+
}
|
|
1440
|
+
.pipeline-column {
|
|
1441
|
+
max-width: 100%;
|
|
1442
|
+
min-width: 100%;
|
|
1443
|
+
border-right: none;
|
|
1444
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
1445
|
+
}
|
|
1446
|
+
.pipeline-column:last-child {
|
|
1447
|
+
border-bottom: none;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1288
1451
|
/* Board stats bar */
|
|
1289
1452
|
.board-stats-bar {
|
|
1290
1453
|
display: flex;
|
|
@@ -2953,6 +3116,72 @@ function partitionByEpic(columnItems, allItems) {
|
|
|
2953
3116
|
return { ungrouped, groups, sortedGroupKeys };
|
|
2954
3117
|
}
|
|
2955
3118
|
|
|
3119
|
+
// ── Pipeline (swimlane) helpers ──
|
|
3120
|
+
|
|
3121
|
+
function computeSwimlaneColumns(laneConfig) {
|
|
3122
|
+
const seen = new Set();
|
|
3123
|
+
const ordered = [];
|
|
3124
|
+
for (const taskType of (laneConfig.taskTypes || laneConfig.task_types || [])) {
|
|
3125
|
+
const stages = getStagesForType(taskType);
|
|
3126
|
+
for (const stage of stages) {
|
|
3127
|
+
if (!seen.has(stage)) {
|
|
3128
|
+
seen.add(stage);
|
|
3129
|
+
ordered.push(stage);
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
return ordered;
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
function assignItemsToSwimlanes(items) {
|
|
3137
|
+
const result = new Map();
|
|
3138
|
+
for (const lane of SWIMLANE_CONFIG) {
|
|
3139
|
+
result.set(lane.key, []);
|
|
3140
|
+
}
|
|
3141
|
+
for (const item of items) {
|
|
3142
|
+
const lane = getSwimlaneForType(item.task_type);
|
|
3143
|
+
if (result.has(lane.key)) {
|
|
3144
|
+
result.get(lane.key).push(item);
|
|
3145
|
+
} else {
|
|
3146
|
+
result.set(lane.key, [item]);
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
return result;
|
|
3150
|
+
}
|
|
3151
|
+
|
|
3152
|
+
function getColumnMeta(stageId) {
|
|
3153
|
+
const col = KANBAN_COLUMNS.find(c => c.id === stageId);
|
|
3154
|
+
return col
|
|
3155
|
+
? { label: col.label, color: col.color, tooltip: col.tooltip, status: col.status }
|
|
3156
|
+
: { label: stageId, color: '#6b7280', tooltip: '', status: 'waiting' };
|
|
3157
|
+
}
|
|
3158
|
+
|
|
3159
|
+
function getItemColumn(item, laneColumns) {
|
|
3160
|
+
if (isOverlayStatus(item.status)) {
|
|
3161
|
+
const effective = getEffectivePipelineColumn(item);
|
|
3162
|
+
return laneColumns.includes(effective) ? effective : laneColumns[0];
|
|
3163
|
+
}
|
|
3164
|
+
if (!item.status || item.status === 'New' || item.status === '') {
|
|
3165
|
+
return 'New';
|
|
3166
|
+
}
|
|
3167
|
+
return laneColumns.includes(item.status) ? item.status : laneColumns[0];
|
|
3168
|
+
}
|
|
3169
|
+
|
|
3170
|
+
function isSwimlaneCollapsed(laneKey) {
|
|
3171
|
+
try {
|
|
3172
|
+
const state = JSON.parse(localStorage.getItem('beastmode-swimlane-collapse') || '{}');
|
|
3173
|
+
return state[laneKey] === true;
|
|
3174
|
+
} catch { return false; }
|
|
3175
|
+
}
|
|
3176
|
+
|
|
3177
|
+
function saveSwimlaneCollapse(laneKey, collapsed) {
|
|
3178
|
+
try {
|
|
3179
|
+
const state = JSON.parse(localStorage.getItem('beastmode-swimlane-collapse') || '{}');
|
|
3180
|
+
state[laneKey] = collapsed;
|
|
3181
|
+
localStorage.setItem('beastmode-swimlane-collapse', JSON.stringify(state));
|
|
3182
|
+
} catch {}
|
|
3183
|
+
}
|
|
3184
|
+
|
|
2956
3185
|
// ── HTML Content Renderer (for Monday.com update bodies) ──
|
|
2957
3186
|
|
|
2958
3187
|
function _sanitizeHtml(raw) {
|
|
@@ -3556,6 +3785,146 @@ function CreateTaskDialog({ onClose, onCreated }) {
|
|
|
3556
3785
|
`;
|
|
3557
3786
|
}
|
|
3558
3787
|
|
|
3788
|
+
// ── Pipeline (Swimlane) View ──
|
|
3789
|
+
|
|
3790
|
+
function PipelineView({
|
|
3791
|
+
filteredItems,
|
|
3792
|
+
items,
|
|
3793
|
+
onDragStart,
|
|
3794
|
+
onDragEnd,
|
|
3795
|
+
onDragOver,
|
|
3796
|
+
onDragLeave,
|
|
3797
|
+
onDrop,
|
|
3798
|
+
selectedProject,
|
|
3799
|
+
setSelectedItem,
|
|
3800
|
+
deleteItem,
|
|
3801
|
+
columnSorts,
|
|
3802
|
+
cycleSort,
|
|
3803
|
+
sortColumnItems,
|
|
3804
|
+
}) {
|
|
3805
|
+
const [collapseKey, setCollapseKey] = useState(0);
|
|
3806
|
+
const [, setEpicCollapseKey] = useState(0);
|
|
3807
|
+
|
|
3808
|
+
const laneItems = assignItemsToSwimlanes(filteredItems);
|
|
3809
|
+
|
|
3810
|
+
const renderCard = (item, colStatus, isParentEpic) => html`
|
|
3811
|
+
<div class=${'kanban-card' + (isParentEpic ? ' epic-parent-card' : '')} key=${item.id}
|
|
3812
|
+
data-status=${colStatus}
|
|
3813
|
+
data-overlay=${overlayKey(item.status) || ''}
|
|
3814
|
+
draggable="true"
|
|
3815
|
+
onDragStart=${e => onDragStart(e, item.id)}
|
|
3816
|
+
onDragEnd=${onDragEnd}>
|
|
3817
|
+
<button class="card-delete" onClick=${(e) => { e.stopPropagation(); deleteItem(item.id); }} title="Delete">
|
|
3818
|
+
<${Icon} name="trash" size=${12} />
|
|
3819
|
+
</button>
|
|
3820
|
+
<div class="card-id">#${item.id}</div>
|
|
3821
|
+
<div class="card-title" style="cursor:pointer;" onClick=${() => setSelectedItem(item)}>${item.name || item.title}</div>
|
|
3822
|
+
<div class="card-footer">
|
|
3823
|
+
${isOverlayStatus(item.status) && html`<span class=${'card-badge badge-overlay ' + overlayBadgeClass(item.status)} title=${overlayTooltip(item.status)}>${overlayBadgeLabel(item.status)}</span>`}
|
|
3824
|
+
${!isParentEpic && item.parent_epic && html`<span class="card-badge badge-epic">epic:${item.parent_epic}</span>`}
|
|
3825
|
+
${item.priority && html`<span class=${'card-badge ' + priorityBadgeClass(item.priority)}>${item.priority}</span>`}
|
|
3826
|
+
${item.task_type && html`<span class="card-badge badge-type">${item.task_type}</span>`}
|
|
3827
|
+
${selectedProject === 'all' && item.project_id && html`<span class="card-badge badge-project">${item.project_id}</span>`}
|
|
3828
|
+
<span class="card-time">${timeAgo(item.updated_at || item.created_at)}</span>
|
|
3829
|
+
</div>
|
|
3830
|
+
</div>
|
|
3831
|
+
`;
|
|
3832
|
+
|
|
3833
|
+
return html`
|
|
3834
|
+
<div class="pipeline-view" data-testid="pipeline-view">
|
|
3835
|
+
${SWIMLANE_CONFIG.map(lane => {
|
|
3836
|
+
const columns = computeSwimlaneColumns(lane);
|
|
3837
|
+
const laneItemList = laneItems.get(lane.key) || [];
|
|
3838
|
+
const collapsed = isSwimlaneCollapsed(lane.key);
|
|
3839
|
+
const isEmpty = laneItemList.length === 0;
|
|
3840
|
+
const swimlaneClasses = 'pipeline-swimlane'
|
|
3841
|
+
+ (collapsed ? ' pipeline-swimlane-collapsed' : '')
|
|
3842
|
+
+ (isEmpty ? ' pipeline-swimlane-empty' : '');
|
|
3843
|
+
const bodyId = 'pipeline-swimlane-body-' + lane.key;
|
|
3844
|
+
return html`
|
|
3845
|
+
<div class=${swimlaneClasses}
|
|
3846
|
+
data-testid=${'pipeline-swimlane-' + lane.key}
|
|
3847
|
+
data-swimlane=${lane.key}
|
|
3848
|
+
key=${'swimlane-' + lane.key}
|
|
3849
|
+
style=${'--lane-color: ' + lane.color}>
|
|
3850
|
+
<div class="pipeline-swimlane-header"
|
|
3851
|
+
role="button"
|
|
3852
|
+
aria-expanded=${!collapsed}
|
|
3853
|
+
aria-controls=${bodyId}
|
|
3854
|
+
onClick=${() => { saveSwimlaneCollapse(lane.key, !collapsed); setCollapseKey(k => k + 1); }}>
|
|
3855
|
+
<span class="pipeline-swimlane-chevron">${collapsed ? '\u25BA' : '\u25BC'}</span>
|
|
3856
|
+
<span class="pipeline-swimlane-color" style=${'background: ' + lane.color}></span>
|
|
3857
|
+
<span class="pipeline-swimlane-label">${lane.label}</span>
|
|
3858
|
+
<span class=${'pipeline-swimlane-count' + (isEmpty ? ' pipeline-swimlane-count-zero' : '')}>${laneItemList.length}</span>
|
|
3859
|
+
</div>
|
|
3860
|
+
<div class="pipeline-swimlane-body" id=${bodyId}>
|
|
3861
|
+
${columns.map(colId => {
|
|
3862
|
+
const meta = getColumnMeta(colId);
|
|
3863
|
+
const rawColItems = laneItemList.filter(item => getItemColumn(item, columns) === colId);
|
|
3864
|
+
const colItems = sortColumnItems(rawColItems, columnSorts[colId] || '');
|
|
3865
|
+
const sortMode = columnSorts[colId] || '';
|
|
3866
|
+
return html`
|
|
3867
|
+
<div class="pipeline-column"
|
|
3868
|
+
data-testid=${'pipeline-col-' + colId}
|
|
3869
|
+
data-column=${colId}
|
|
3870
|
+
key=${'pc-' + lane.key + '-' + colId}
|
|
3871
|
+
onDragOver=${onDragOver}
|
|
3872
|
+
onDragLeave=${onDragLeave}
|
|
3873
|
+
onDrop=${e => onDrop(e, colId)}>
|
|
3874
|
+
<div class="pipeline-column-header"
|
|
3875
|
+
style=${'--col-color: ' + meta.color}
|
|
3876
|
+
title=${meta.tooltip}
|
|
3877
|
+
onClick=${() => cycleSort(colId)}>
|
|
3878
|
+
<span>${meta.label}${sortMode && html`<span class="sort-indicator">${sortMode === 'priority' ? '\u25BC' : '\u25B2'}</span>`}</span>
|
|
3879
|
+
<span class=${'kanban-count' + (colItems.length === 0 ? ' kanban-count-zero' : '')}>${colItems.length}</span>
|
|
3880
|
+
</div>
|
|
3881
|
+
<div class="pipeline-column-items">
|
|
3882
|
+
${colItems.length === 0
|
|
3883
|
+
? html`<div class="kanban-drop-zone">No items</div>`
|
|
3884
|
+
: (() => {
|
|
3885
|
+
const { ungrouped, groups, sortedGroupKeys } = partitionByEpic(colItems, items);
|
|
3886
|
+
return html`
|
|
3887
|
+
${ungrouped.map(item => renderCard(item, meta.status, false))}
|
|
3888
|
+
${sortedGroupKeys.map(epicId => {
|
|
3889
|
+
const group = groups[epicId];
|
|
3890
|
+
const epCollapsed = isEpicGroupCollapsed(epicId);
|
|
3891
|
+
const totalCount = (group.epic ? 1 : 0) + group.children.length;
|
|
3892
|
+
const egBodyId = 'pipeline-epic-body-' + epicId + '-' + lane.key + '-' + colId;
|
|
3893
|
+
return html`
|
|
3894
|
+
<div class=${'epic-group' + (epCollapsed ? ' epic-group-collapsed' : '')}
|
|
3895
|
+
data-epic-id=${epicId}
|
|
3896
|
+
key=${'eg-' + epicId}>
|
|
3897
|
+
<div class="epic-group-header"
|
|
3898
|
+
role="button"
|
|
3899
|
+
aria-expanded=${!epCollapsed}
|
|
3900
|
+
aria-controls=${egBodyId}
|
|
3901
|
+
onClick=${() => { saveEpicGroupCollapse(epicId, !epCollapsed); setEpicCollapseKey(k => k + 1); }}>
|
|
3902
|
+
<span class="epic-group-chevron">${epCollapsed ? '\u25BA' : '\u25BC'}</span>
|
|
3903
|
+
<span class="epic-group-color" style="background: var(--accent)"></span>
|
|
3904
|
+
<span class="epic-group-name">${group.epicName}</span>
|
|
3905
|
+
<span class="epic-group-count">${totalCount}</span>
|
|
3906
|
+
</div>
|
|
3907
|
+
<div class="epic-group-body" id=${egBodyId}>
|
|
3908
|
+
${group.epic && renderCard(group.epic, meta.status, true)}
|
|
3909
|
+
${group.children.map(item => renderCard(item, meta.status, false))}
|
|
3910
|
+
</div>
|
|
3911
|
+
</div>
|
|
3912
|
+
`;
|
|
3913
|
+
})}
|
|
3914
|
+
`;
|
|
3915
|
+
})()}
|
|
3916
|
+
</div>
|
|
3917
|
+
</div>
|
|
3918
|
+
`;
|
|
3919
|
+
})}
|
|
3920
|
+
</div>
|
|
3921
|
+
</div>
|
|
3922
|
+
`;
|
|
3923
|
+
})}
|
|
3924
|
+
</div>
|
|
3925
|
+
`;
|
|
3926
|
+
}
|
|
3927
|
+
|
|
3559
3928
|
// ── Board Page ──
|
|
3560
3929
|
|
|
3561
3930
|
function BoardPage({ selectedProject }) {
|
|
@@ -3570,6 +3939,13 @@ function BoardPage({ selectedProject }) {
|
|
|
3570
3939
|
const [filters, setFilters] = useState({ priority: '', taskType: '', project: '', dateRange: '', parentEpic: '' });
|
|
3571
3940
|
const [columnSorts, setColumnSorts] = useState({});
|
|
3572
3941
|
const [epicCollapseKey, setEpicCollapseKey] = useState(0);
|
|
3942
|
+
const viewMode = (() => {
|
|
3943
|
+
try {
|
|
3944
|
+
const params = new URLSearchParams(window.location.search);
|
|
3945
|
+
if (params.get('view') === 'pipeline') return 'pipeline';
|
|
3946
|
+
} catch {}
|
|
3947
|
+
return 'board';
|
|
3948
|
+
})();
|
|
3573
3949
|
|
|
3574
3950
|
const fetchItems = useCallback(() => {
|
|
3575
3951
|
setLoading(true);
|
|
@@ -3911,6 +4287,23 @@ function BoardPage({ selectedProject }) {
|
|
|
3911
4287
|
</div>
|
|
3912
4288
|
`}
|
|
3913
4289
|
|
|
4290
|
+
${viewMode === 'pipeline'
|
|
4291
|
+
? html`<${PipelineView}
|
|
4292
|
+
filteredItems=${filteredItems}
|
|
4293
|
+
items=${items}
|
|
4294
|
+
onDragStart=${onDragStart}
|
|
4295
|
+
onDragEnd=${onDragEnd}
|
|
4296
|
+
onDragOver=${onDragOver}
|
|
4297
|
+
onDragLeave=${onDragLeave}
|
|
4298
|
+
onDrop=${onDrop}
|
|
4299
|
+
selectedProject=${selectedProject}
|
|
4300
|
+
setSelectedItem=${setSelectedItem}
|
|
4301
|
+
deleteItem=${deleteItem}
|
|
4302
|
+
columnSorts=${columnSorts}
|
|
4303
|
+
cycleSort=${cycleSort}
|
|
4304
|
+
sortColumnItems=${sortColumnItems}
|
|
4305
|
+
/>`
|
|
4306
|
+
: html`
|
|
3914
4307
|
<div class="kanban-wrapper">
|
|
3915
4308
|
<div class="kanban-scroll-bar">
|
|
3916
4309
|
<button class="kanban-scroll-btn" onClick=${() => {
|
|
@@ -4009,6 +4402,7 @@ function BoardPage({ selectedProject }) {
|
|
|
4009
4402
|
})}
|
|
4010
4403
|
</div>
|
|
4011
4404
|
</div>
|
|
4405
|
+
`}
|
|
4012
4406
|
|
|
4013
4407
|
${showCreateDialog && html`<${CreateTaskDialog} onClose=${() => setShowCreateDialog(false)} onCreated=${fetchItems} />`}
|
|
4014
4408
|
${selectedItem && html`<${ItemDetailSidebar} item=${selectedItem} onClose=${() => setSelectedItem(null)} onStatusChange=${() => { fetchItems(); setSelectedItem(null); }} />`}
|
|
@@ -6660,6 +7054,19 @@ function App() {
|
|
|
6660
7054
|
setSelectedProjectRaw(value);
|
|
6661
7055
|
}, []);
|
|
6662
7056
|
|
|
7057
|
+
// If ?view=pipeline or ?view=board is in the URL but no hash route is
|
|
7058
|
+
// set, the router would default to Dashboard. Redirect to #/board so
|
|
7059
|
+
// the board page renders (and BoardPage can read the ?view= param).
|
|
7060
|
+
useEffect(() => {
|
|
7061
|
+
try {
|
|
7062
|
+
const params = new URLSearchParams(window.location.search);
|
|
7063
|
+
const view = params.get('view');
|
|
7064
|
+
if ((view === 'pipeline' || view === 'board') && (!location.hash || location.hash === '#/' || location.hash === '#')) {
|
|
7065
|
+
navigate('#/board');
|
|
7066
|
+
}
|
|
7067
|
+
} catch (_) {}
|
|
7068
|
+
}, []);
|
|
7069
|
+
|
|
6663
7070
|
const boardData = window.__BOARD_DATA__ || {};
|
|
6664
7071
|
const factoryName = boardData.factoryName || 'BeastMode Factory';
|
|
6665
7072
|
|
package/dist/web/build-stamp.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
20260418-010109-1a0ff01
|