@basementuniverse/kanbn 1.1.0 → 1.1.1
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/PLANS.md +9 -0
- package/package.json +1 -1
- package/src/controller/gantt.js +46 -1
- package/src/main.js +24 -3
package/PLANS.md
ADDED
package/package.json
CHANGED
package/src/controller/gantt.js
CHANGED
|
@@ -64,7 +64,8 @@ function createChartCell() {
|
|
|
64
64
|
return {
|
|
65
65
|
bg: null,
|
|
66
66
|
lineMask: 0,
|
|
67
|
-
arrowChar: null
|
|
67
|
+
arrowChar: null,
|
|
68
|
+
markerChar: null
|
|
68
69
|
};
|
|
69
70
|
}
|
|
70
71
|
|
|
@@ -121,6 +122,38 @@ function routeDependency(grid, sourceRow, sourceCol, targetRow, targetCol) {
|
|
|
121
122
|
grid[targetRow][targetCol].arrowChar = targetCol >= routeCol ? '→' : '←';
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
function setMarker(cell, markerChar) {
|
|
126
|
+
if (!cell.arrowChar && !cell.markerChar) {
|
|
127
|
+
cell.markerChar = markerChar;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function routeIncomingExternalDependency(grid, row, targetCol) {
|
|
132
|
+
const arrowCol = Math.max(0, targetCol);
|
|
133
|
+
grid[row][arrowCol].arrowChar = '→';
|
|
134
|
+
|
|
135
|
+
if (arrowCol > 0) {
|
|
136
|
+
addMask(grid[row][arrowCol], DIR_LEFT);
|
|
137
|
+
addMask(grid[row][arrowCol - 1], DIR_RIGHT);
|
|
138
|
+
}
|
|
139
|
+
if (arrowCol > 1) {
|
|
140
|
+
setMarker(grid[row][arrowCol - 2], '…');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function routeOutgoingExternalDependency(grid, row, sourceCol, width) {
|
|
145
|
+
const arrowCol = Math.min(width - 1, sourceCol);
|
|
146
|
+
grid[row][arrowCol].arrowChar = '→';
|
|
147
|
+
|
|
148
|
+
if (arrowCol < width - 1) {
|
|
149
|
+
addMask(grid[row][arrowCol], DIR_RIGHT);
|
|
150
|
+
addMask(grid[row][arrowCol + 1], DIR_LEFT);
|
|
151
|
+
}
|
|
152
|
+
if (arrowCol < width - 2) {
|
|
153
|
+
setMarker(grid[row][arrowCol + 2], '…');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
124
157
|
function buildDependencyOverlay(tasks, barGeometries, width) {
|
|
125
158
|
const grid = createChartGrid(tasks.length, width);
|
|
126
159
|
const taskRowMap = new Map(tasks.map((task, index) => [task.id, index]));
|
|
@@ -140,6 +173,14 @@ function buildDependencyOverlay(tasks, barGeometries, width) {
|
|
|
140
173
|
barGeometries[targetRow].start
|
|
141
174
|
);
|
|
142
175
|
});
|
|
176
|
+
|
|
177
|
+
if (Array.isArray(task.externalIncomingDependencies) && task.externalIncomingDependencies.length > 0) {
|
|
178
|
+
routeIncomingExternalDependency(grid, targetRow, barGeometries[targetRow].start);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (Array.isArray(task.externalOutgoingDependents) && task.externalOutgoingDependents.length > 0) {
|
|
182
|
+
routeOutgoingExternalDependency(grid, targetRow, barGeometries[targetRow].end, width);
|
|
183
|
+
}
|
|
143
184
|
});
|
|
144
185
|
|
|
145
186
|
return grid;
|
|
@@ -165,6 +206,10 @@ function renderChartRow(gridRow, barGeometry, barBackground, nowPosition) {
|
|
|
165
206
|
return styleCell(lineChar, ANSI_FG_LINE, bg);
|
|
166
207
|
}
|
|
167
208
|
|
|
209
|
+
if (cell.markerChar) {
|
|
210
|
+
return styleCell(cell.markerChar, ANSI_FG_LINE, bg);
|
|
211
|
+
}
|
|
212
|
+
|
|
168
213
|
if (nowPosition === column) {
|
|
169
214
|
return styleCell(NOW_MARKER, ANSI_FG_NOW, bg);
|
|
170
215
|
}
|
package/src/main.js
CHANGED
|
@@ -905,14 +905,26 @@ function findDependencyCycle(dependencyMap) {
|
|
|
905
905
|
* @param {Date} now
|
|
906
906
|
* @return {object}
|
|
907
907
|
*/
|
|
908
|
-
function buildGanttSchedule(index, tasks, now) {
|
|
908
|
+
function buildGanttSchedule(index, tasks, now, trackedTaskIds = new Set()) {
|
|
909
909
|
const taskById = new Map(tasks.map((task) => [task.id, task]));
|
|
910
910
|
const dependencyMap = new Map(tasks.map((task) => [task.id, new Set()]));
|
|
911
911
|
const dependentsMap = new Map();
|
|
912
912
|
const indegree = new Map(tasks.map((task) => [task.id, 0]));
|
|
913
|
+
const externalIncomingDependenciesMap = new Map(tasks.map((task) => [task.id, new Set()]));
|
|
914
|
+
const externalOutgoingDependentsMap = new Map(tasks.map((task) => [task.id, new Set()]));
|
|
915
|
+
|
|
916
|
+
const taskExistsInBoard = (taskId) => trackedTaskIds.has(taskId);
|
|
913
917
|
|
|
914
918
|
const addDependencyEdge = (dependencyId, dependentId) => {
|
|
919
|
+
if (!taskById.has(dependentId)) {
|
|
920
|
+
throw new Error(`Task "${dependentId}" depends on missing task "${dependencyId}"`);
|
|
921
|
+
}
|
|
922
|
+
|
|
915
923
|
if (!taskById.has(dependencyId)) {
|
|
924
|
+
if (taskExistsInBoard(dependencyId)) {
|
|
925
|
+
externalIncomingDependenciesMap.get(dependentId).add(dependencyId);
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
916
928
|
throw new Error(`Task "${dependentId}" depends on missing task "${dependencyId}"`);
|
|
917
929
|
}
|
|
918
930
|
|
|
@@ -939,7 +951,13 @@ function buildGanttSchedule(index, tasks, now) {
|
|
|
939
951
|
if (relationType === 'depends-on') {
|
|
940
952
|
addDependencyEdge(relation.task, task.id);
|
|
941
953
|
} else if (relationType === 'blocks') {
|
|
942
|
-
|
|
954
|
+
if (taskById.has(relation.task)) {
|
|
955
|
+
addDependencyEdge(task.id, relation.task);
|
|
956
|
+
} else if (taskExistsInBoard(relation.task)) {
|
|
957
|
+
externalOutgoingDependentsMap.get(task.id).add(relation.task);
|
|
958
|
+
} else {
|
|
959
|
+
throw new Error(`Task "${task.id}" blocks missing task "${relation.task}"`);
|
|
960
|
+
}
|
|
943
961
|
}
|
|
944
962
|
});
|
|
945
963
|
});
|
|
@@ -1036,6 +1054,8 @@ function buildGanttSchedule(index, tasks, now) {
|
|
|
1036
1054
|
const scheduledTask = {
|
|
1037
1055
|
...task,
|
|
1038
1056
|
dependencies,
|
|
1057
|
+
externalIncomingDependencies: [...(externalIncomingDependenciesMap.get(task.id) || [])],
|
|
1058
|
+
externalOutgoingDependents: [...(externalOutgoingDependentsMap.get(task.id) || [])],
|
|
1039
1059
|
start,
|
|
1040
1060
|
end,
|
|
1041
1061
|
blocked: dependencyEnd !== null && preferredStart instanceof Date && dependencyEnd.getTime() > preferredStart.getTime()
|
|
@@ -2850,7 +2870,8 @@ class Kanbn {
|
|
|
2850
2870
|
}
|
|
2851
2871
|
);
|
|
2852
2872
|
|
|
2853
|
-
|
|
2873
|
+
const trackedTaskIds = getTrackedTaskIds(index);
|
|
2874
|
+
return buildGanttSchedule(index, tasks, effectiveNow, trackedTaskIds);
|
|
2854
2875
|
}
|
|
2855
2876
|
|
|
2856
2877
|
/**
|