@ondrej-svec/hog 1.8.0 → 1.8.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/dist/cli.js CHANGED
@@ -2337,7 +2337,16 @@ function navReducer(state, action) {
2337
2337
  case "SET_ITEMS": {
2338
2338
  const sections = [...new Set(action.items.map((i) => i.section))];
2339
2339
  const isFirstLoad = state.sections.length === 0;
2340
- const collapsedSections = isFirstLoad ? new Set(sections.filter((s) => s === "activity")) : state.collapsedSections;
2340
+ let collapsedSections;
2341
+ if (isFirstLoad) {
2342
+ collapsedSections = new Set(sections.filter((s) => s === "activity"));
2343
+ } else {
2344
+ const validIds = /* @__PURE__ */ new Set([
2345
+ ...sections,
2346
+ ...action.items.filter((i) => i.type === "subHeader").map((i) => i.id)
2347
+ ]);
2348
+ collapsedSections = new Set([...state.collapsedSections].filter((id) => validIds.has(id)));
2349
+ }
2341
2350
  const selectionValid = state.selectedId != null && action.items.some((i) => i.id === state.selectedId);
2342
2351
  if (!isFirstLoad && selectionValid && arraysEqual(sections, state.sections)) {
2343
2352
  return state.allItems === action.items ? state : { ...state, allItems: action.items };
@@ -4990,128 +4999,121 @@ function groupByStatus(issues) {
4990
4999
  }
4991
5000
  return groups;
4992
5001
  }
4993
- function collectGroupIssues(statusGroup, byStatus) {
4994
- const issues = [];
4995
- for (const status of statusGroup.statuses) {
4996
- const list = byStatus.get(status);
4997
- if (list) issues.push(...list);
4998
- }
4999
- issues.sort((a, b) => issuePriorityRank(a) - issuePriorityRank(b));
5000
- return issues;
5001
- }
5002
- function buildNavItems(repos, tasks, activityCount) {
5003
- const items = [];
5004
- if (activityCount > 0) {
5005
- items.push({ id: "header:activity", section: "activity", type: "header" });
5006
- }
5007
- for (const rd of repos) {
5008
- items.push({ id: `header:${rd.repo.shortName}`, section: rd.repo.shortName, type: "header" });
5002
+ function buildBoardTree(repos, tasks, activity) {
5003
+ const sections = repos.map((rd) => {
5004
+ const sectionId = rd.repo.name;
5005
+ if (rd.error) {
5006
+ return { repo: rd.repo, sectionId, groups: [], error: rd.error };
5007
+ }
5009
5008
  const statusGroupDefs = resolveStatusGroups(rd.statusOptions, rd.repo.statusGroups);
5010
5009
  const byStatus = groupByStatus(rd.issues);
5011
- const coveredStatuses = /* @__PURE__ */ new Set();
5010
+ const coveredKeys = /* @__PURE__ */ new Set();
5011
+ const groups = [];
5012
5012
  for (const sg of statusGroupDefs) {
5013
- const groupIssues = collectGroupIssues(sg, byStatus);
5014
- if (groupIssues.length === 0) continue;
5015
- const subId = `sub:${rd.repo.shortName}:${sg.label}`;
5016
- items.push({ id: subId, section: rd.repo.shortName, type: "subHeader" });
5017
- for (const issue of groupIssues) {
5013
+ const issues = [];
5014
+ for (const [status, statusIssues] of byStatus) {
5015
+ if (sg.statuses.some((s) => s.toLowerCase().trim() === status.toLowerCase().trim())) {
5016
+ issues.push(...statusIssues);
5017
+ }
5018
+ }
5019
+ if (issues.length === 0) continue;
5020
+ issues.sort((a, b) => issuePriorityRank(a) - issuePriorityRank(b));
5021
+ groups.push({ label: sg.label, subId: `sub:${sectionId}:${sg.label}`, issues });
5022
+ for (const s of sg.statuses) coveredKeys.add(s.toLowerCase().trim());
5023
+ }
5024
+ for (const [status, statusIssues] of byStatus) {
5025
+ if (!(coveredKeys.has(status.toLowerCase().trim()) || isTerminalStatus(status))) {
5026
+ groups.push({ label: status, subId: `sub:${sectionId}:${status}`, issues: statusIssues });
5027
+ }
5028
+ }
5029
+ return { repo: rd.repo, sectionId, groups, error: null };
5030
+ });
5031
+ return { activity, sections, tasks };
5032
+ }
5033
+ function buildNavItems(tree) {
5034
+ const items = [];
5035
+ if (tree.activity.length > 0)
5036
+ items.push({ id: "header:activity", section: "activity", type: "header" });
5037
+ for (const { repo, sectionId, groups } of tree.sections) {
5038
+ items.push({ id: `header:${sectionId}`, section: sectionId, type: "header" });
5039
+ for (const group of groups) {
5040
+ items.push({ id: group.subId, section: sectionId, type: "subHeader" });
5041
+ for (const issue of group.issues) {
5018
5042
  items.push({
5019
- id: `gh:${rd.repo.name}:${issue.number}`,
5020
- section: rd.repo.shortName,
5043
+ id: `gh:${repo.name}:${issue.number}`,
5044
+ section: sectionId,
5021
5045
  type: "item",
5022
- subSection: subId
5046
+ subSection: group.subId
5023
5047
  });
5024
5048
  }
5025
- for (const s of sg.statuses) coveredStatuses.add(s);
5026
- }
5027
- for (const [status, issues] of byStatus) {
5028
- if (!(coveredStatuses.has(status) || isTerminalStatus(status)) && issues.length > 0) {
5029
- const subId = `sub:${rd.repo.shortName}:${status}`;
5030
- items.push({ id: subId, section: rd.repo.shortName, type: "subHeader" });
5031
- for (const issue of issues) {
5032
- items.push({
5033
- id: `gh:${rd.repo.name}:${issue.number}`,
5034
- section: rd.repo.shortName,
5035
- type: "item",
5036
- subSection: subId
5037
- });
5038
- }
5039
- }
5040
5049
  }
5041
5050
  }
5042
- if (tasks.length > 0) {
5051
+ if (tree.tasks.length > 0) {
5043
5052
  items.push({ id: "header:ticktick", section: "ticktick", type: "header" });
5044
- for (const task2 of tasks) {
5053
+ for (const task2 of tree.tasks)
5045
5054
  items.push({ id: `tt:${task2.id}`, section: "ticktick", type: "item" });
5046
- }
5047
5055
  }
5048
5056
  return items;
5049
5057
  }
5050
- function buildFlatRows(repos, tasks, activity, isCollapsed) {
5058
+ function buildFlatRows(tree, isCollapsed) {
5051
5059
  const rows = [];
5052
- if (activity.length > 0) {
5060
+ if (tree.activity.length > 0) {
5053
5061
  const collapsed = isCollapsed("activity");
5054
5062
  rows.push({
5055
5063
  type: "sectionHeader",
5056
5064
  key: "header:activity",
5057
5065
  navId: "header:activity",
5058
5066
  label: "Recent Activity (24h)",
5059
- count: activity.length,
5067
+ count: tree.activity.length,
5060
5068
  countLabel: "events",
5061
5069
  isCollapsed: collapsed
5062
5070
  });
5063
5071
  if (!collapsed) {
5064
- for (const [i, event] of activity.entries()) {
5072
+ for (const [i, event] of tree.activity.entries()) {
5065
5073
  rows.push({ type: "activity", key: `act:${i}`, navId: null, event });
5066
5074
  }
5067
5075
  }
5068
5076
  }
5069
- for (const rd of repos) {
5070
- const { repo, issues, error: repoError } = rd;
5071
- const collapsed = isCollapsed(repo.shortName);
5077
+ for (const { repo, sectionId, groups, error } of tree.sections) {
5078
+ const collapsed = isCollapsed(sectionId);
5079
+ const totalIssues = groups.reduce((s, g) => s + g.issues.length, 0);
5072
5080
  rows.push({
5073
5081
  type: "sectionHeader",
5074
- key: `header:${repo.shortName}`,
5075
- navId: `header:${repo.shortName}`,
5082
+ key: `header:${sectionId}`,
5083
+ navId: `header:${sectionId}`,
5076
5084
  label: repo.shortName,
5077
- count: issues.length,
5085
+ // display label still shows shortName
5086
+ count: totalIssues,
5078
5087
  countLabel: "issues",
5079
5088
  isCollapsed: collapsed
5080
5089
  });
5081
5090
  if (!collapsed) {
5082
- if (repoError) {
5083
- rows.push({ type: "error", key: `error:${repo.shortName}`, navId: null, text: repoError });
5084
- } else if (issues.length === 0) {
5091
+ if (error) {
5092
+ rows.push({ type: "error", key: `error:${sectionId}`, navId: null, text: error });
5093
+ } else if (groups.length === 0) {
5085
5094
  rows.push({
5086
5095
  type: "subHeader",
5087
- key: `empty:${repo.shortName}`,
5096
+ key: `empty:${sectionId}`,
5088
5097
  navId: null,
5089
5098
  text: "No open issues"
5090
5099
  });
5091
5100
  } else {
5092
- const statusGroupDefs = resolveStatusGroups(rd.statusOptions, rd.repo.statusGroups);
5093
- const byStatus = groupByStatus(issues);
5094
- const coveredStatuses = /* @__PURE__ */ new Set();
5095
5101
  let isFirstGroup = true;
5096
- for (const sg of statusGroupDefs) {
5097
- const groupIssues = collectGroupIssues(sg, byStatus);
5098
- if (groupIssues.length === 0) continue;
5099
- if (!isFirstGroup) {
5100
- rows.push({ type: "gap", key: `gap:${repo.shortName}:${sg.label}`, navId: null });
5101
- }
5102
+ for (const group of groups) {
5103
+ if (!isFirstGroup)
5104
+ rows.push({ type: "gap", key: `gap:${sectionId}:${group.label}`, navId: null });
5102
5105
  isFirstGroup = false;
5103
- const subId = `sub:${repo.shortName}:${sg.label}`;
5104
- const subCollapsed = isCollapsed(subId);
5106
+ const subCollapsed = isCollapsed(group.subId);
5105
5107
  rows.push({
5106
5108
  type: "subHeader",
5107
- key: subId,
5108
- navId: subId,
5109
- text: sg.label,
5110
- count: groupIssues.length,
5109
+ key: group.subId,
5110
+ navId: group.subId,
5111
+ text: group.label,
5112
+ count: group.issues.length,
5111
5113
  isCollapsed: subCollapsed
5112
5114
  });
5113
5115
  if (!subCollapsed) {
5114
- for (const issue of groupIssues) {
5116
+ for (const issue of group.issues) {
5115
5117
  rows.push({
5116
5118
  type: "issue",
5117
5119
  key: `gh:${repo.name}:${issue.number}`,
@@ -5121,55 +5123,24 @@ function buildFlatRows(repos, tasks, activity, isCollapsed) {
5121
5123
  });
5122
5124
  }
5123
5125
  }
5124
- for (const s of sg.statuses) coveredStatuses.add(s);
5125
- }
5126
- for (const [status, groupIssues] of byStatus) {
5127
- if (!(coveredStatuses.has(status) || isTerminalStatus(status)) && groupIssues.length > 0) {
5128
- if (!isFirstGroup) {
5129
- rows.push({ type: "gap", key: `gap:${repo.shortName}:${status}`, navId: null });
5130
- }
5131
- isFirstGroup = false;
5132
- const subId = `sub:${repo.shortName}:${status}`;
5133
- const subCollapsed = isCollapsed(subId);
5134
- rows.push({
5135
- type: "subHeader",
5136
- key: subId,
5137
- navId: subId,
5138
- text: status,
5139
- count: groupIssues.length,
5140
- isCollapsed: subCollapsed
5141
- });
5142
- if (!subCollapsed) {
5143
- for (const issue of groupIssues) {
5144
- rows.push({
5145
- type: "issue",
5146
- key: `gh:${repo.name}:${issue.number}`,
5147
- navId: `gh:${repo.name}:${issue.number}`,
5148
- issue,
5149
- repoName: repo.name
5150
- });
5151
- }
5152
- }
5153
- }
5154
5126
  }
5155
5127
  }
5156
5128
  }
5157
5129
  }
5158
- if (tasks.length > 0) {
5130
+ if (tree.tasks.length > 0) {
5159
5131
  const collapsed = isCollapsed("ticktick");
5160
5132
  rows.push({
5161
5133
  type: "sectionHeader",
5162
5134
  key: "header:ticktick",
5163
5135
  navId: "header:ticktick",
5164
5136
  label: "Personal (TickTick)",
5165
- count: tasks.length,
5137
+ count: tree.tasks.length,
5166
5138
  countLabel: "tasks",
5167
5139
  isCollapsed: collapsed
5168
5140
  });
5169
5141
  if (!collapsed) {
5170
- for (const task2 of tasks) {
5142
+ for (const task2 of tree.tasks)
5171
5143
  rows.push({ type: "task", key: `tt:${task2.id}`, navId: `tt:${task2.id}`, task: task2 });
5172
- }
5173
5144
  }
5174
5145
  }
5175
5146
  return rows;
@@ -5263,10 +5234,11 @@ function Dashboard({ config: config2, options, activeProfile }) {
5263
5234
  const q = searchQuery.toLowerCase();
5264
5235
  return allTasks.filter((t) => t.title.toLowerCase().includes(q));
5265
5236
  }, [allTasks, searchQuery]);
5266
- const navItems = useMemo3(
5267
- () => buildNavItems(repos, tasks, allActivity.length),
5268
- [repos, tasks, allActivity.length]
5237
+ const boardTree = useMemo3(
5238
+ () => buildBoardTree(repos, tasks, allActivity),
5239
+ [repos, tasks, allActivity]
5269
5240
  );
5241
+ const navItems = useMemo3(() => buildNavItems(boardTree), [boardTree]);
5270
5242
  const nav = useNavigation(navItems);
5271
5243
  const getRepoForId = useCallback11((id) => {
5272
5244
  if (id.startsWith("gh:")) {
@@ -5418,8 +5390,8 @@ function Dashboard({ config: config2, options, activeProfile }) {
5418
5390
  termSize.rows - CHROME_ROWS - overlayBarRows - toastRows - logPaneRows
5419
5391
  );
5420
5392
  const flatRows = useMemo3(
5421
- () => buildFlatRows(repos, tasks, allActivity, nav.isCollapsed),
5422
- [repos, tasks, allActivity, nav.isCollapsed]
5393
+ () => buildFlatRows(boardTree, nav.isCollapsed),
5394
+ [boardTree, nav.isCollapsed]
5423
5395
  );
5424
5396
  const scrollRef = useRef13(0);
5425
5397
  const selectedRowIdx = useMemo3(
@@ -6951,7 +6923,7 @@ function resolveProjectId(projectId) {
6951
6923
  process.exit(1);
6952
6924
  }
6953
6925
  var program = new Command();
6954
- program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.8.0").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
6926
+ program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.8.1").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
6955
6927
  const opts = thisCommand.opts();
6956
6928
  if (opts.json) setFormat("json");
6957
6929
  if (opts.human) setFormat("human");