@beastmode-develeap/beastmode 0.1.23 → 0.1.25
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 +183 -21
- package/package.json +1 -1
package/dist/web/board.html
CHANGED
|
@@ -1211,6 +1211,79 @@ input[type="range"]::-webkit-slider-thumb {
|
|
|
1211
1211
|
.kanban-card[data-overlay="stuck"] { animation: none; }
|
|
1212
1212
|
}
|
|
1213
1213
|
|
|
1214
|
+
/* Epic group nesting */
|
|
1215
|
+
.epic-group {
|
|
1216
|
+
margin-bottom: 8px;
|
|
1217
|
+
border: 1px solid var(--border);
|
|
1218
|
+
border-radius: 8px;
|
|
1219
|
+
overflow: hidden;
|
|
1220
|
+
background: var(--bg-input);
|
|
1221
|
+
}
|
|
1222
|
+
.epic-group-header {
|
|
1223
|
+
display: flex;
|
|
1224
|
+
align-items: center;
|
|
1225
|
+
gap: 8px;
|
|
1226
|
+
padding: 6px 10px;
|
|
1227
|
+
cursor: pointer;
|
|
1228
|
+
user-select: none;
|
|
1229
|
+
background: var(--bg-card);
|
|
1230
|
+
border-bottom: 1px solid var(--border);
|
|
1231
|
+
transition: background 0.15s;
|
|
1232
|
+
font-size: 12px;
|
|
1233
|
+
}
|
|
1234
|
+
.epic-group-header:hover {
|
|
1235
|
+
background: var(--surface2, rgba(255,255,255,0.05));
|
|
1236
|
+
}
|
|
1237
|
+
.epic-group-collapsed .epic-group-header {
|
|
1238
|
+
border-bottom: none;
|
|
1239
|
+
}
|
|
1240
|
+
.epic-group-chevron {
|
|
1241
|
+
font-size: 10px;
|
|
1242
|
+
color: var(--text-muted);
|
|
1243
|
+
width: 14px;
|
|
1244
|
+
text-align: center;
|
|
1245
|
+
flex-shrink: 0;
|
|
1246
|
+
}
|
|
1247
|
+
.epic-group-color {
|
|
1248
|
+
width: 6px;
|
|
1249
|
+
height: 6px;
|
|
1250
|
+
border-radius: 50%;
|
|
1251
|
+
flex-shrink: 0;
|
|
1252
|
+
}
|
|
1253
|
+
.epic-group-name {
|
|
1254
|
+
font-weight: 600;
|
|
1255
|
+
color: var(--text-secondary);
|
|
1256
|
+
white-space: nowrap;
|
|
1257
|
+
overflow: hidden;
|
|
1258
|
+
text-overflow: ellipsis;
|
|
1259
|
+
flex: 1;
|
|
1260
|
+
min-width: 0;
|
|
1261
|
+
}
|
|
1262
|
+
.epic-group-count {
|
|
1263
|
+
font-size: 10px;
|
|
1264
|
+
color: var(--text-muted);
|
|
1265
|
+
background: var(--surface2, rgba(255,255,255,0.08));
|
|
1266
|
+
padding: 1px 7px;
|
|
1267
|
+
border-radius: 8px;
|
|
1268
|
+
font-weight: 500;
|
|
1269
|
+
flex-shrink: 0;
|
|
1270
|
+
}
|
|
1271
|
+
.epic-group-body {
|
|
1272
|
+
padding: 4px;
|
|
1273
|
+
}
|
|
1274
|
+
.epic-group-body .kanban-card {
|
|
1275
|
+
margin-bottom: 4px;
|
|
1276
|
+
}
|
|
1277
|
+
.epic-group-body .kanban-card:last-child {
|
|
1278
|
+
margin-bottom: 0;
|
|
1279
|
+
}
|
|
1280
|
+
.epic-parent-card {
|
|
1281
|
+
border-left: 3px dashed var(--accent);
|
|
1282
|
+
}
|
|
1283
|
+
.epic-group-collapsed .epic-group-body {
|
|
1284
|
+
display: none;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1214
1287
|
/* Board stats bar */
|
|
1215
1288
|
.board-stats-bar {
|
|
1216
1289
|
display: flex;
|
|
@@ -2734,6 +2807,67 @@ window.overlayKey = overlayKey;
|
|
|
2734
2807
|
window.overlayTooltip = overlayTooltip;
|
|
2735
2808
|
window.getEffectivePipelineColumn = getEffectivePipelineColumn;
|
|
2736
2809
|
|
|
2810
|
+
function isEpicGroupCollapsed(epicId) {
|
|
2811
|
+
try {
|
|
2812
|
+
const state = JSON.parse(localStorage.getItem('beastmode-epic-collapse') || '{}');
|
|
2813
|
+
return state[epicId] === true;
|
|
2814
|
+
} catch { return false; }
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
function saveEpicGroupCollapse(epicId, collapsed) {
|
|
2818
|
+
try {
|
|
2819
|
+
const state = JSON.parse(localStorage.getItem('beastmode-epic-collapse') || '{}');
|
|
2820
|
+
state[epicId] = collapsed;
|
|
2821
|
+
localStorage.setItem('beastmode-epic-collapse', JSON.stringify(state));
|
|
2822
|
+
} catch {}
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
function partitionByEpic(columnItems, allItems) {
|
|
2826
|
+
const ungrouped = [];
|
|
2827
|
+
const groups = {};
|
|
2828
|
+
|
|
2829
|
+
for (const item of columnItems) {
|
|
2830
|
+
const epicId = item.parent_epic;
|
|
2831
|
+
if (!epicId) {
|
|
2832
|
+
if (item.task_type === 'epic') {
|
|
2833
|
+
const childrenInCol = columnItems.filter(c => String(c.parent_epic) === String(item.id));
|
|
2834
|
+
if (childrenInCol.length > 0) {
|
|
2835
|
+
groups[item.id] = groups[item.id] || { epic: null, children: [] };
|
|
2836
|
+
groups[item.id].epic = item;
|
|
2837
|
+
continue;
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
ungrouped.push(item);
|
|
2841
|
+
} else {
|
|
2842
|
+
groups[epicId] = groups[epicId] || { epic: null, children: [] };
|
|
2843
|
+
groups[epicId].children.push(item);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
for (const epicId of Object.keys(groups)) {
|
|
2848
|
+
if (!groups[epicId].epic) {
|
|
2849
|
+
const parentItem = allItems.find(i => String(i.id) === String(epicId));
|
|
2850
|
+
groups[epicId].epicName = parentItem ? parentItem.name : 'Epic #' + epicId;
|
|
2851
|
+
groups[epicId].epicStatus = parentItem ? parentItem.status : null;
|
|
2852
|
+
} else {
|
|
2853
|
+
groups[epicId].epicName = groups[epicId].epic.name;
|
|
2854
|
+
groups[epicId].epicStatus = groups[epicId].epic.status;
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
const sortedGroupKeys = Object.keys(groups).sort((a, b) => {
|
|
2859
|
+
const idsA = groups[a].children.map(c => Number(c.id));
|
|
2860
|
+
if (groups[a].epic) idsA.push(Number(groups[a].epic.id));
|
|
2861
|
+
const idsB = groups[b].children.map(c => Number(c.id));
|
|
2862
|
+
if (groups[b].epic) idsB.push(Number(groups[b].epic.id));
|
|
2863
|
+
const minA = idsA.length > 0 ? Math.min(...idsA) : Infinity;
|
|
2864
|
+
const minB = idsB.length > 0 ? Math.min(...idsB) : Infinity;
|
|
2865
|
+
return minA - minB;
|
|
2866
|
+
});
|
|
2867
|
+
|
|
2868
|
+
return { ungrouped, groups, sortedGroupKeys };
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2737
2871
|
// ── HTML Content Renderer (for Monday.com update bodies) ──
|
|
2738
2872
|
|
|
2739
2873
|
function _sanitizeHtml(raw) {
|
|
@@ -3289,6 +3423,7 @@ function BoardPage({ selectedProject }) {
|
|
|
3289
3423
|
const [filtersOpen, setFiltersOpen] = useState(false);
|
|
3290
3424
|
const [filters, setFilters] = useState({ priority: '', taskType: '', project: '', dateRange: '', parentEpic: '' });
|
|
3291
3425
|
const [columnSorts, setColumnSorts] = useState({});
|
|
3426
|
+
const [epicCollapseKey, setEpicCollapseKey] = useState(0);
|
|
3292
3427
|
|
|
3293
3428
|
const fetchItems = useCallback(() => {
|
|
3294
3429
|
setLoading(true);
|
|
@@ -3673,28 +3808,55 @@ function BoardPage({ selectedProject }) {
|
|
|
3673
3808
|
<div class="kanban-items">
|
|
3674
3809
|
${colItems.length === 0
|
|
3675
3810
|
? html`<div class="kanban-drop-zone">No items</div>`
|
|
3676
|
-
:
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3811
|
+
: (() => {
|
|
3812
|
+
const { ungrouped, groups, sortedGroupKeys } = partitionByEpic(colItems, items);
|
|
3813
|
+
const renderCard = (item, isParentEpic) => html`
|
|
3814
|
+
<div class=${'kanban-card' + (isParentEpic ? ' epic-parent-card' : '')} key=${item.id}
|
|
3815
|
+
data-status=${col.status}
|
|
3816
|
+
data-overlay=${overlayKey(item.status) || ''}
|
|
3817
|
+
draggable="true"
|
|
3818
|
+
onDragStart=${e => onDragStart(e, item.id)}
|
|
3819
|
+
onDragEnd=${onDragEnd}>
|
|
3820
|
+
<button class="card-delete" onClick=${(e) => { e.stopPropagation(); deleteItem(item.id); }} title="Delete">
|
|
3821
|
+
<${Icon} name="trash" size=${12} />
|
|
3822
|
+
</button>
|
|
3823
|
+
<div class="card-id">#${item.id}</div>
|
|
3824
|
+
<div class="card-title" style="cursor:pointer;" onClick=${() => setSelectedItem(item)}>${item.name || item.title}</div>
|
|
3825
|
+
<div class="card-footer">
|
|
3826
|
+
${isOverlayStatus(item.status) && html`<span class=${'card-badge badge-overlay ' + overlayBadgeClass(item.status)} title=${overlayTooltip(item.status)}>${overlayBadgeLabel(item.status)}</span>`}
|
|
3827
|
+
${!isParentEpic && item.parent_epic && html`<span class="card-badge badge-epic">epic:${item.parent_epic}</span>`}
|
|
3828
|
+
${item.priority && html`<span class=${'card-badge ' + priorityBadgeClass(item.priority)}>${item.priority}</span>`}
|
|
3829
|
+
${item.task_type && html`<span class="card-badge badge-type">${item.task_type}</span>`}
|
|
3830
|
+
${selectedProject === 'all' && item.project_id && html`<span class="card-badge badge-project">${item.project_id}</span>`}
|
|
3831
|
+
<span class="card-time">${timeAgo(item.updated_at || item.created_at)}</span>
|
|
3832
|
+
</div>
|
|
3695
3833
|
</div>
|
|
3696
|
-
|
|
3697
|
-
|
|
3834
|
+
`;
|
|
3835
|
+
return html`
|
|
3836
|
+
${ungrouped.map(item => renderCard(item, false))}
|
|
3837
|
+
${sortedGroupKeys.map(epicId => {
|
|
3838
|
+
const group = groups[epicId];
|
|
3839
|
+
const collapsed = isEpicGroupCollapsed(epicId);
|
|
3840
|
+
const totalCount = (group.epic ? 1 : 0) + group.children.length;
|
|
3841
|
+
const bodyId = 'epic-group-body-' + epicId + '-' + col.id;
|
|
3842
|
+
return html`
|
|
3843
|
+
<div class=${'epic-group' + (collapsed ? ' epic-group-collapsed' : '')} data-epic-id=${epicId} key=${'eg-' + epicId}>
|
|
3844
|
+
<div class="epic-group-header" role="button" aria-expanded=${!collapsed} aria-controls=${bodyId}
|
|
3845
|
+
onClick=${() => { saveEpicGroupCollapse(epicId, !collapsed); setEpicCollapseKey(k => k + 1); }}>
|
|
3846
|
+
<span class="epic-group-chevron">${collapsed ? '\u25BA' : '\u25BC'}</span>
|
|
3847
|
+
<span class="epic-group-color" style="background: var(--accent)"></span>
|
|
3848
|
+
<span class="epic-group-name">${group.epicName}</span>
|
|
3849
|
+
<span class="epic-group-count">${totalCount}</span>
|
|
3850
|
+
</div>
|
|
3851
|
+
<div class="epic-group-body" id=${bodyId}>
|
|
3852
|
+
${group.epic && renderCard(group.epic, true)}
|
|
3853
|
+
${group.children.map(item => renderCard(item, false))}
|
|
3854
|
+
</div>
|
|
3855
|
+
</div>
|
|
3856
|
+
`;
|
|
3857
|
+
})}
|
|
3858
|
+
`;
|
|
3859
|
+
})()}
|
|
3698
3860
|
</div>
|
|
3699
3861
|
</div>
|
|
3700
3862
|
`;
|