@ondrej-svec/hog 1.24.3 → 1.25.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
@@ -908,51 +908,22 @@ function fetchProjectFields(repo, issueNumber, projectNumber) {
908
908
  return {};
909
909
  }
910
910
  }
911
+ function accumulateEnrichment(nodes, targetRepo, enrichMap) {
912
+ for (const item of nodes) {
913
+ if (!item?.content?.number) continue;
914
+ const itemRepo = item.content.repository?.nameWithOwner;
915
+ if (itemRepo && itemRepo !== targetRepo) continue;
916
+ const enrichment = parseFieldValues(item.fieldValues?.nodes ?? [], "projectStatus");
917
+ enrichMap.set(item.content.number, enrichment);
918
+ }
919
+ }
911
920
  function fetchProjectEnrichment(repo, projectNumber) {
912
921
  const [owner] = repo.split("/");
913
922
  if (!owner) return /* @__PURE__ */ new Map();
914
- const projectItemsFragment = `
915
- projectV2(number: $projectNumber) {
916
- items(first: 100, after: $cursor) {
917
- pageInfo { hasNextPage endCursor }
918
- nodes {
919
- content {
920
- ... on Issue {
921
- number
922
- }
923
- }
924
- fieldValues(first: 20) {
925
- nodes {
926
- ... on ProjectV2ItemFieldDateValue {
927
- field { ... on ProjectV2Field { name } }
928
- date
929
- }
930
- ... on ProjectV2ItemFieldSingleSelectValue {
931
- field { ... on ProjectV2SingleSelectField { name } }
932
- name
933
- }
934
- ... on ProjectV2ItemFieldTextValue {
935
- field { ... on ProjectV2Field { name } }
936
- text
937
- }
938
- ... on ProjectV2ItemFieldNumberValue {
939
- field { ... on ProjectV2Field { name } }
940
- number
941
- }
942
- ... on ProjectV2ItemFieldIterationValue {
943
- field { ... on ProjectV2IterationField { name } }
944
- title
945
- }
946
- }
947
- }
948
- }
949
- }
950
- }
951
- `;
952
923
  const query = `
953
924
  query($owner: String!, $projectNumber: Int!, $cursor: String) {
954
- organization(login: $owner) { ${projectItemsFragment} }
955
- user(login: $owner) { ${projectItemsFragment} }
925
+ organization(login: $owner) { ${PROJECT_ITEMS_FRAGMENT} }
926
+ user(login: $owner) { ${PROJECT_ITEMS_FRAGMENT} }
956
927
  }
957
928
  `;
958
929
  try {
@@ -973,12 +944,7 @@ function fetchProjectEnrichment(repo, projectNumber) {
973
944
  const result = runGhGraphQL(args);
974
945
  const ownerNode = result?.data?.organization ?? result?.data?.user;
975
946
  const page = ownerNode?.projectV2?.items;
976
- const nodes = page?.nodes ?? [];
977
- for (const item of nodes) {
978
- if (!item?.content?.number) continue;
979
- const enrichment = parseFieldValues(item.fieldValues?.nodes ?? [], "projectStatus");
980
- enrichMap.set(item.content.number, enrichment);
981
- }
947
+ accumulateEnrichment(page?.nodes ?? [], repo, enrichMap);
982
948
  if (!page?.pageInfo?.hasNextPage) break;
983
949
  cursor = page.pageInfo.endCursor ?? null;
984
950
  } while (cursor);
@@ -990,48 +956,10 @@ function fetchProjectEnrichment(repo, projectNumber) {
990
956
  async function fetchProjectEnrichmentAsync(repo, projectNumber) {
991
957
  const [owner] = repo.split("/");
992
958
  if (!owner) return /* @__PURE__ */ new Map();
993
- const projectItemsFragment = `
994
- projectV2(number: $projectNumber) {
995
- items(first: 100, after: $cursor) {
996
- pageInfo { hasNextPage endCursor }
997
- nodes {
998
- content {
999
- ... on Issue {
1000
- number
1001
- }
1002
- }
1003
- fieldValues(first: 20) {
1004
- nodes {
1005
- ... on ProjectV2ItemFieldDateValue {
1006
- field { ... on ProjectV2Field { name } }
1007
- date
1008
- }
1009
- ... on ProjectV2ItemFieldSingleSelectValue {
1010
- field { ... on ProjectV2SingleSelectField { name } }
1011
- name
1012
- }
1013
- ... on ProjectV2ItemFieldTextValue {
1014
- field { ... on ProjectV2Field { name } }
1015
- text
1016
- }
1017
- ... on ProjectV2ItemFieldNumberValue {
1018
- field { ... on ProjectV2Field { name } }
1019
- number
1020
- }
1021
- ... on ProjectV2ItemFieldIterationValue {
1022
- field { ... on ProjectV2IterationField { name } }
1023
- title
1024
- }
1025
- }
1026
- }
1027
- }
1028
- }
1029
- }
1030
- `;
1031
959
  const query = `
1032
960
  query($owner: String!, $projectNumber: Int!, $cursor: String) {
1033
- organization(login: $owner) { ${projectItemsFragment} }
1034
- user(login: $owner) { ${projectItemsFragment} }
961
+ organization(login: $owner) { ${PROJECT_ITEMS_FRAGMENT} }
962
+ user(login: $owner) { ${PROJECT_ITEMS_FRAGMENT} }
1035
963
  }
1036
964
  `;
1037
965
  try {
@@ -1052,12 +980,7 @@ async function fetchProjectEnrichmentAsync(repo, projectNumber) {
1052
980
  const result = await runGhGraphQLAsync(args);
1053
981
  const ownerNode = result?.data?.organization ?? result?.data?.user;
1054
982
  const page = ownerNode?.projectV2?.items;
1055
- const nodes = page?.nodes ?? [];
1056
- for (const item of nodes) {
1057
- if (!item?.content?.number) continue;
1058
- const enrichment = parseFieldValues(item.fieldValues?.nodes ?? [], "projectStatus");
1059
- enrichMap.set(item.content.number, enrichment);
1060
- }
983
+ accumulateEnrichment(page?.nodes ?? [], repo, enrichMap);
1061
984
  if (!page?.pageInfo?.hasNextPage) break;
1062
985
  cursor = page.pageInfo.endCursor ?? null;
1063
986
  } while (cursor);
@@ -1294,7 +1217,7 @@ async function updateProjectItemDateAsync(repo, issueNumber, projectConfig, dueD
1294
1217
  `date=${dueDate}`
1295
1218
  ]);
1296
1219
  }
1297
- var execFileAsync, DATE_FIELD_NAME_RE2, FIND_PROJECT_ITEM_QUERY, projectNodeIdCache;
1220
+ var execFileAsync, DATE_FIELD_NAME_RE2, FIND_PROJECT_ITEM_QUERY, projectNodeIdCache, PROJECT_ITEMS_FRAGMENT;
1298
1221
  var init_github = __esm({
1299
1222
  "src/github.ts"() {
1300
1223
  "use strict";
@@ -1339,6 +1262,45 @@ var init_github = __esm({
1339
1262
  }
1340
1263
  `;
1341
1264
  projectNodeIdCache = /* @__PURE__ */ new Map();
1265
+ PROJECT_ITEMS_FRAGMENT = `
1266
+ projectV2(number: $projectNumber) {
1267
+ items(first: 100, after: $cursor) {
1268
+ pageInfo { hasNextPage endCursor }
1269
+ nodes {
1270
+ content {
1271
+ ... on Issue {
1272
+ number
1273
+ repository { nameWithOwner }
1274
+ }
1275
+ }
1276
+ fieldValues(first: 20) {
1277
+ nodes {
1278
+ ... on ProjectV2ItemFieldDateValue {
1279
+ field { ... on ProjectV2Field { name } }
1280
+ date
1281
+ }
1282
+ ... on ProjectV2ItemFieldSingleSelectValue {
1283
+ field { ... on ProjectV2SingleSelectField { name } }
1284
+ name
1285
+ }
1286
+ ... on ProjectV2ItemFieldTextValue {
1287
+ field { ... on ProjectV2Field { name } }
1288
+ text
1289
+ }
1290
+ ... on ProjectV2ItemFieldNumberValue {
1291
+ field { ... on ProjectV2Field { name } }
1292
+ number
1293
+ }
1294
+ ... on ProjectV2ItemFieldIterationValue {
1295
+ field { ... on ProjectV2IterationField { name } }
1296
+ title
1297
+ }
1298
+ }
1299
+ }
1300
+ }
1301
+ }
1302
+ }
1303
+ `;
1342
1304
  }
1343
1305
  });
1344
1306
 
@@ -1571,31 +1533,72 @@ function buildFlatRowsForRepo(sections, repoName, statusGroupId) {
1571
1533
  repoName: section.repo.name
1572
1534
  }));
1573
1535
  }
1536
+ function tokenizeQuery(query) {
1537
+ const tokens = [];
1538
+ const raw = query.trim();
1539
+ if (!raw) return tokens;
1540
+ const re = /(\w+):"([^"]*)"?|(\w+):(\S+)|(\S+)/gi;
1541
+ for (const m of raw.matchAll(re)) {
1542
+ if (m[1] != null && m[2] != null) {
1543
+ tokens.push({ type: "field", field: m[1].toLowerCase(), value: m[2].toLowerCase() });
1544
+ } else if (m[3] != null && m[4] != null) {
1545
+ tokens.push({ type: "field", field: m[3].toLowerCase(), value: m[4].toLowerCase() });
1546
+ } else if (m[5] != null) {
1547
+ tokens.push({ type: "plain", value: m[5].toLowerCase() });
1548
+ }
1549
+ }
1550
+ return tokens;
1551
+ }
1574
1552
  function matchesSearch(issue, query) {
1575
- if (!query.trim()) return true;
1576
- const tokens = query.toLowerCase().trim().split(/\s+/);
1553
+ const tokens = tokenizeQuery(query);
1554
+ if (tokens.length === 0) return true;
1577
1555
  const labels = issue.labels ?? [];
1578
1556
  const assignees = issue.assignees ?? [];
1579
1557
  return tokens.every((token) => {
1580
- if (token.startsWith("#")) {
1581
- const num = parseInt(token.slice(1), 10);
1558
+ if (token.type === "field") {
1559
+ return matchesFieldToken(issue, token.field, token.value, labels, assignees);
1560
+ }
1561
+ const t = token.value;
1562
+ if (t.startsWith("#")) {
1563
+ const num = parseInt(t.slice(1), 10);
1582
1564
  return !Number.isNaN(num) && issue.number === num;
1583
1565
  }
1584
- if (token.startsWith("@")) {
1585
- const login = token.slice(1);
1566
+ if (t.startsWith("@")) {
1567
+ const login = t.slice(1);
1586
1568
  return assignees.some((a) => a.login.toLowerCase().includes(login));
1587
1569
  }
1588
- if (token === "unassigned") return assignees.length === 0;
1589
- if (token === "assigned") return assignees.length > 0;
1590
- if (issue.title.toLowerCase().includes(token)) return true;
1591
- if (labels.some((l) => l.name.toLowerCase().includes(token))) return true;
1592
- if (issue.projectStatus?.toLowerCase().includes(token)) return true;
1593
- if (issue.customFields && Object.values(issue.customFields).some((v) => v.toLowerCase().includes(token)))
1570
+ if (t === "unassigned") return assignees.length === 0;
1571
+ if (t === "assigned") return assignees.length > 0;
1572
+ if (issue.title.toLowerCase().includes(t)) return true;
1573
+ if (labels.some((l) => l.name.toLowerCase().includes(t))) return true;
1574
+ if (issue.projectStatus?.toLowerCase().includes(t)) return true;
1575
+ if (issue.customFields && Object.values(issue.customFields).some((v) => v.toLowerCase().includes(t)))
1594
1576
  return true;
1595
- if (assignees.some((a) => a.login.toLowerCase().includes(token))) return true;
1577
+ if (assignees.some((a) => a.login.toLowerCase().includes(t))) return true;
1596
1578
  return false;
1597
1579
  });
1598
1580
  }
1581
+ function matchesFieldToken(issue, field, value, labels, assignees) {
1582
+ if (field === "status") {
1583
+ return issue.projectStatus?.toLowerCase().includes(value) ?? false;
1584
+ }
1585
+ if (field === "label") {
1586
+ return labels.some((l) => l.name.toLowerCase().includes(value));
1587
+ }
1588
+ if (field === "assignee") {
1589
+ return assignees.some((a) => a.login.toLowerCase().includes(value));
1590
+ }
1591
+ if (issue.customFields) {
1592
+ for (const [k, v] of Object.entries(issue.customFields)) {
1593
+ if (k.toLowerCase().includes(field) && v.toLowerCase().includes(value)) {
1594
+ return true;
1595
+ }
1596
+ }
1597
+ }
1598
+ const combined = `${field}:${value}`;
1599
+ if (labels.some((l) => l.name.toLowerCase().includes(combined))) return true;
1600
+ return false;
1601
+ }
1599
1602
  function findSelectedIssueWithRepo(repos, selectedId) {
1600
1603
  if (!selectedId?.startsWith("gh:")) return null;
1601
1604
  for (const rd of repos) {
@@ -6551,7 +6554,7 @@ function SearchBar({ defaultValue, onChange, onSubmit }) {
6551
6554
  TextInput5,
6552
6555
  {
6553
6556
  defaultValue,
6554
- placeholder: "title, label, status, @user, #123, unassigned\u2026",
6557
+ placeholder: 'title, @user, #123, field:value, field:"multi word"\u2026',
6555
6558
  onChange,
6556
6559
  onSubmit
6557
6560
  }
@@ -9797,7 +9800,7 @@ async function resolveRef(ref, config2) {
9797
9800
  }
9798
9801
  }
9799
9802
  var program = new Command();
9800
- program.name("hog").description("Personal command deck \u2014 GitHub Projects dashboard with workflow orchestration").version("1.24.3").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
9803
+ program.name("hog").description("Personal command deck \u2014 GitHub Projects dashboard with workflow orchestration").version("1.25.1").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
9801
9804
  const opts = thisCommand.opts();
9802
9805
  if (opts.json) setFormat("json");
9803
9806
  if (opts.human) setFormat("human");