git-truck 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/build/index.js
CHANGED
|
@@ -2203,7 +2203,7 @@ var import_fs3 = require("fs");
|
|
|
2203
2203
|
|
|
2204
2204
|
// src/analyzer/model.ts
|
|
2205
2205
|
init_react();
|
|
2206
|
-
var AnalyzerDataInterfaceVersion =
|
|
2206
|
+
var AnalyzerDataInterfaceVersion = 10;
|
|
2207
2207
|
|
|
2208
2208
|
// src/analyzer/log.server.ts
|
|
2209
2209
|
init_react();
|
|
@@ -2301,7 +2301,7 @@ var import_path2 = require("path");
|
|
|
2301
2301
|
|
|
2302
2302
|
// package.json
|
|
2303
2303
|
var name = "git-truck";
|
|
2304
|
-
var version = "1.1.
|
|
2304
|
+
var version = "1.1.1";
|
|
2305
2305
|
var private2 = false;
|
|
2306
2306
|
var description = "Visualizing a Git repository";
|
|
2307
2307
|
var license = "MIT";
|
|
@@ -3062,6 +3062,62 @@ function TreeCleanup(tree) {
|
|
|
3062
3062
|
|
|
3063
3063
|
// src/analyzer/analyze.server.ts
|
|
3064
3064
|
var import_child_process2 = require("child_process");
|
|
3065
|
+
|
|
3066
|
+
// src/authorUnionUtil.server.ts
|
|
3067
|
+
init_react();
|
|
3068
|
+
var makeDupeMap = (authors) => {
|
|
3069
|
+
const dupeMap = {};
|
|
3070
|
+
for (const aliases of authors) {
|
|
3071
|
+
for (const alias of aliases) {
|
|
3072
|
+
dupeMap[alias] = aliases[0];
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
return dupeMap;
|
|
3076
|
+
};
|
|
3077
|
+
function unionAuthors(authors, authorAliasMap) {
|
|
3078
|
+
return Object.entries(authors).reduce((newAuthorObject, [authorOrAlias, contributionCount]) => {
|
|
3079
|
+
const author = authorAliasMap[authorOrAlias];
|
|
3080
|
+
if (author) {
|
|
3081
|
+
const credits = (newAuthorObject[author] ?? 0) + contributionCount;
|
|
3082
|
+
return __spreadProps(__spreadValues({}, newAuthorObject), {
|
|
3083
|
+
[author]: credits
|
|
3084
|
+
});
|
|
3085
|
+
}
|
|
3086
|
+
return __spreadProps(__spreadValues({}, newAuthorObject), { [authorOrAlias]: contributionCount });
|
|
3087
|
+
}, {});
|
|
3088
|
+
}
|
|
3089
|
+
function nameUnion(names, authorAliasMap) {
|
|
3090
|
+
let collector = [];
|
|
3091
|
+
for (const name2 of names) {
|
|
3092
|
+
const lookup = authorAliasMap[name2];
|
|
3093
|
+
if (lookup) {
|
|
3094
|
+
if (collector.includes(lookup))
|
|
3095
|
+
continue;
|
|
3096
|
+
collector.push(lookup);
|
|
3097
|
+
} else
|
|
3098
|
+
collector.push(name2);
|
|
3099
|
+
}
|
|
3100
|
+
return collector;
|
|
3101
|
+
}
|
|
3102
|
+
function addAuthorUnion(data, dupeMap) {
|
|
3103
|
+
data.commit.tree = addAuthorUnionRec(data.commit.tree, dupeMap);
|
|
3104
|
+
return data;
|
|
3105
|
+
}
|
|
3106
|
+
function addAuthorUnionRec(tree, authorUnions) {
|
|
3107
|
+
for (const child of tree.children) {
|
|
3108
|
+
if (child.type === "blob") {
|
|
3109
|
+
child.unionedAuthors = {
|
|
3110
|
+
HISTORICAL: unionAuthors(child.authors, authorUnions),
|
|
3111
|
+
BLAME: unionAuthors(child.blameAuthors, authorUnions)
|
|
3112
|
+
};
|
|
3113
|
+
} else {
|
|
3114
|
+
addAuthorUnionRec(child, authorUnions);
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
return tree;
|
|
3118
|
+
}
|
|
3119
|
+
|
|
3120
|
+
// src/analyzer/analyze.server.ts
|
|
3065
3121
|
var repoDir = ".";
|
|
3066
3122
|
async function analyzeCommitLight(hash) {
|
|
3067
3123
|
const rawContent = await GitCaller.getInstance().catFileCached(hash);
|
|
@@ -3260,10 +3316,12 @@ ${reasons.map((r) => ` - ${r}`).join("\n")}`);
|
|
|
3260
3316
|
let outPath = (0, import_path4.resolve)(args2.out ?? defaultOutPath);
|
|
3261
3317
|
if (!(0, import_path4.isAbsolute)(outPath))
|
|
3262
3318
|
outPath = (0, import_path4.resolve)(process.cwd(), outPath);
|
|
3319
|
+
const authorsUnion = nameUnion(authors, makeDupeMap(args2.unionedAuthors ?? []));
|
|
3263
3320
|
data = {
|
|
3264
3321
|
cached: false,
|
|
3265
3322
|
hiddenFiles,
|
|
3266
3323
|
authors,
|
|
3324
|
+
authorsUnion,
|
|
3267
3325
|
repo: repoName,
|
|
3268
3326
|
branch: branchName,
|
|
3269
3327
|
commit: hydratedRepoTree,
|
|
@@ -4312,47 +4370,6 @@ async function getTruckConfigWithArgs(repo) {
|
|
|
4312
4370
|
];
|
|
4313
4371
|
}
|
|
4314
4372
|
|
|
4315
|
-
// src/authorUnionUtil.server.ts
|
|
4316
|
-
init_react();
|
|
4317
|
-
var makeDupeMap = (authors) => {
|
|
4318
|
-
const dupeMap = {};
|
|
4319
|
-
for (const aliases of authors) {
|
|
4320
|
-
for (const alias of aliases) {
|
|
4321
|
-
dupeMap[alias] = aliases[0];
|
|
4322
|
-
}
|
|
4323
|
-
}
|
|
4324
|
-
return dupeMap;
|
|
4325
|
-
};
|
|
4326
|
-
function unionAuthors(authors, authorAliasMap) {
|
|
4327
|
-
return Object.entries(authors).reduce((newAuthorObject, [authorOrAlias, contributionCount]) => {
|
|
4328
|
-
const author = authorAliasMap[authorOrAlias];
|
|
4329
|
-
if (author) {
|
|
4330
|
-
const credits = (newAuthorObject[author] ?? 0) + contributionCount;
|
|
4331
|
-
return __spreadProps(__spreadValues({}, newAuthorObject), {
|
|
4332
|
-
[author]: credits
|
|
4333
|
-
});
|
|
4334
|
-
}
|
|
4335
|
-
return __spreadProps(__spreadValues({}, newAuthorObject), { [authorOrAlias]: contributionCount });
|
|
4336
|
-
}, {});
|
|
4337
|
-
}
|
|
4338
|
-
function addAuthorUnion(data, dupeMap) {
|
|
4339
|
-
data.commit.tree = addAuthorUnionRec(data.commit.tree, dupeMap);
|
|
4340
|
-
return data;
|
|
4341
|
-
}
|
|
4342
|
-
function addAuthorUnionRec(tree, authorUnions) {
|
|
4343
|
-
for (const child of tree.children) {
|
|
4344
|
-
if (child.type === "blob") {
|
|
4345
|
-
child.unionedAuthors = {
|
|
4346
|
-
HISTORICAL: unionAuthors(child.authors, authorUnions),
|
|
4347
|
-
BLAME: unionAuthors(child.blameAuthors, authorUnions)
|
|
4348
|
-
};
|
|
4349
|
-
} else {
|
|
4350
|
-
addAuthorUnionRec(child, authorUnions);
|
|
4351
|
-
}
|
|
4352
|
-
}
|
|
4353
|
-
return tree;
|
|
4354
|
-
}
|
|
4355
|
-
|
|
4356
4373
|
// src/components/Details.tsx
|
|
4357
4374
|
init_react();
|
|
4358
4375
|
var import_react7 = require("react");
|
|
@@ -4533,57 +4550,6 @@ function getColorFromExtension(extension) {
|
|
|
4533
4550
|
return colorResult.color;
|
|
4534
4551
|
}
|
|
4535
4552
|
|
|
4536
|
-
// src/util.ts
|
|
4537
|
-
init_react();
|
|
4538
|
-
function dateFormatLong(epochTime) {
|
|
4539
|
-
if (!epochTime)
|
|
4540
|
-
return "Invalid date";
|
|
4541
|
-
return new Date(epochTime * 1e3).toLocaleString("en-gb", {
|
|
4542
|
-
day: "2-digit",
|
|
4543
|
-
month: "short",
|
|
4544
|
-
year: "numeric"
|
|
4545
|
-
});
|
|
4546
|
-
}
|
|
4547
|
-
function dateTimeFormatShort(epochTime) {
|
|
4548
|
-
return new Date(epochTime).toLocaleString("en-gb", {
|
|
4549
|
-
hour: "2-digit",
|
|
4550
|
-
minute: "2-digit",
|
|
4551
|
-
day: "2-digit",
|
|
4552
|
-
month: "short",
|
|
4553
|
-
year: "2-digit"
|
|
4554
|
-
});
|
|
4555
|
-
}
|
|
4556
|
-
function dateFormatRelative(epochTime) {
|
|
4557
|
-
const now = Date.now();
|
|
4558
|
-
const hourMillis = 60 * 60 * 1e3;
|
|
4559
|
-
const dayMillis = 24 * hourMillis;
|
|
4560
|
-
const difference = now - epochTime * 1e3;
|
|
4561
|
-
if (difference < 0)
|
|
4562
|
-
return "Unknown time ago";
|
|
4563
|
-
if (difference > dayMillis) {
|
|
4564
|
-
const days = Math.floor(difference / dayMillis);
|
|
4565
|
-
return `${days} day${days > 1 ? "s" : ""} ago`;
|
|
4566
|
-
}
|
|
4567
|
-
const hours = Math.floor(difference / hourMillis);
|
|
4568
|
-
if (hours > 1)
|
|
4569
|
-
return `${hours} hours ago`;
|
|
4570
|
-
if (hours === 1)
|
|
4571
|
-
return "1 hour ago";
|
|
4572
|
-
return "<1 hour ago";
|
|
4573
|
-
}
|
|
4574
|
-
var last = (arr) => arr[arr.length - 1];
|
|
4575
|
-
var allExceptLast = (arr) => {
|
|
4576
|
-
if (arr.length <= 1)
|
|
4577
|
-
return [];
|
|
4578
|
-
return arr.slice(0, arr.length - 1);
|
|
4579
|
-
};
|
|
4580
|
-
function getSeparator(path) {
|
|
4581
|
-
if (path.includes("\\"))
|
|
4582
|
-
return "\\";
|
|
4583
|
-
return "/";
|
|
4584
|
-
}
|
|
4585
|
-
var getPathFromRepoAndHead = (repo, branch) => [repo, branch].join("/");
|
|
4586
|
-
|
|
4587
4553
|
// src/metrics.ts
|
|
4588
4554
|
var Authorship = {
|
|
4589
4555
|
HISTORICAL: "Complete history",
|
|
@@ -4594,14 +4560,18 @@ var Metric = {
|
|
|
4594
4560
|
MOST_COMMITS: "Number of commits",
|
|
4595
4561
|
LAST_CHANGED: "Last changed",
|
|
4596
4562
|
SINGLE_AUTHOR: "Single author",
|
|
4597
|
-
TOP_CONTRIBUTOR: "Top contributor"
|
|
4563
|
+
TOP_CONTRIBUTOR: "Top contributor",
|
|
4564
|
+
TRUCK_FACTOR: "Truck factor"
|
|
4598
4565
|
};
|
|
4599
4566
|
function createMetricData(data) {
|
|
4600
|
-
const authorColors = generateAuthorColors(data);
|
|
4601
|
-
return
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4567
|
+
const authorColors = generateAuthorColors(data.authors);
|
|
4568
|
+
return [
|
|
4569
|
+
{
|
|
4570
|
+
HISTORICAL: setupMetricsCache(data.commit.tree, getMetricCalcs(data, "HISTORICAL", authorColors)),
|
|
4571
|
+
BLAME: setupMetricsCache(data.commit.tree, getMetricCalcs(data, "BLAME", authorColors))
|
|
4572
|
+
},
|
|
4573
|
+
authorColors
|
|
4574
|
+
];
|
|
4605
4575
|
}
|
|
4606
4576
|
function getMetricDescription(metric, authorshipType) {
|
|
4607
4577
|
switch (metric) {
|
|
@@ -4610,24 +4580,28 @@ function getMetricDescription(metric, authorshipType) {
|
|
|
4610
4580
|
case "MOST_COMMITS":
|
|
4611
4581
|
return "Which files have had the most commits, throughout the repository's history?";
|
|
4612
4582
|
case "LAST_CHANGED":
|
|
4613
|
-
return "
|
|
4583
|
+
return "How long ago did the files change?";
|
|
4614
4584
|
case "SINGLE_AUTHOR":
|
|
4615
4585
|
return authorshipType === "HISTORICAL" ? "Which files are authored by only one person, throughout the repository's history?" : "Which files are authored by only one person, in the newest version?";
|
|
4616
4586
|
case "TOP_CONTRIBUTOR":
|
|
4617
4587
|
return authorshipType === "HISTORICAL" ? "Which person has made the most line-changes to a file, throughout the repository's history?" : "Which person has made the most line-changes to a file, in the newest version?";
|
|
4588
|
+
case "TRUCK_FACTOR":
|
|
4589
|
+
return "How many have contributed to a file?";
|
|
4618
4590
|
default:
|
|
4619
4591
|
throw new Error("Uknown metric type: " + metric);
|
|
4620
4592
|
}
|
|
4621
4593
|
}
|
|
4622
|
-
function
|
|
4594
|
+
function getMetricLegendType(metric) {
|
|
4623
4595
|
switch (metric) {
|
|
4624
4596
|
case "FILE_EXTENSION":
|
|
4625
4597
|
case "TOP_CONTRIBUTOR":
|
|
4626
4598
|
case "SINGLE_AUTHOR":
|
|
4627
|
-
return
|
|
4628
|
-
case "LAST_CHANGED":
|
|
4599
|
+
return "POINT";
|
|
4629
4600
|
case "MOST_COMMITS":
|
|
4630
|
-
return
|
|
4601
|
+
return "GRADIENT";
|
|
4602
|
+
case "LAST_CHANGED":
|
|
4603
|
+
case "TRUCK_FACTOR":
|
|
4604
|
+
return "SEGMENTS";
|
|
4631
4605
|
default:
|
|
4632
4606
|
throw new Error("Uknown metric type: " + metric);
|
|
4633
4607
|
}
|
|
@@ -4641,11 +4615,10 @@ var PointInfo = class {
|
|
|
4641
4615
|
this.weight += value;
|
|
4642
4616
|
}
|
|
4643
4617
|
};
|
|
4644
|
-
function generateAuthorColors(
|
|
4618
|
+
function generateAuthorColors(authors) {
|
|
4645
4619
|
const authorsMap = {};
|
|
4646
|
-
for (const author of
|
|
4620
|
+
for (const author of Object.keys(authors))
|
|
4647
4621
|
authorsMap[author] = 0;
|
|
4648
|
-
const authors = data.authors;
|
|
4649
4622
|
const palette = (0, import_distinct_colors.default)({ count: authors.length });
|
|
4650
4623
|
let index = 0;
|
|
4651
4624
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -4659,7 +4632,7 @@ function generateAuthorColors(data) {
|
|
|
4659
4632
|
function getMetricCalcs(data, authorshipType, authorColors) {
|
|
4660
4633
|
const commit = data.commit;
|
|
4661
4634
|
const heatmap = new HeatMapTranslater(commit.minNoCommits, commit.maxNoCommits);
|
|
4662
|
-
const
|
|
4635
|
+
const truckmap = new TruckFactorTranslater(data.authorsUnion.length);
|
|
4663
4636
|
return [
|
|
4664
4637
|
[
|
|
4665
4638
|
"FILE_EXTENSION",
|
|
@@ -4699,15 +4672,13 @@ function getMetricCalcs(data, authorshipType, authorColors) {
|
|
|
4699
4672
|
(blob, cache) => {
|
|
4700
4673
|
if (!cache.legend) {
|
|
4701
4674
|
cache.legend = [
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
coldmap.getColor(commit.oldestLatestChangeEpoch),
|
|
4707
|
-
coldmap.getColor(commit.newestLatestChangeEpoch)
|
|
4675
|
+
6,
|
|
4676
|
+
(n) => lastChangedColorText(n),
|
|
4677
|
+
(n) => `${lastChangedColorSteps(n)}`,
|
|
4678
|
+
(blob2) => mapEpochToStep(blob2.lastChangeEpoch ?? 0) ?? -1
|
|
4708
4679
|
];
|
|
4709
4680
|
}
|
|
4710
|
-
|
|
4681
|
+
cacheAgeColor(blob, cache);
|
|
4711
4682
|
}
|
|
4712
4683
|
],
|
|
4713
4684
|
[
|
|
@@ -4719,6 +4690,23 @@ function getMetricCalcs(data, authorshipType, authorColors) {
|
|
|
4719
4690
|
cache.legend = /* @__PURE__ */ new Map();
|
|
4720
4691
|
setDominantAuthorColor(authorColors, blob, cache, authorshipType);
|
|
4721
4692
|
}
|
|
4693
|
+
],
|
|
4694
|
+
[
|
|
4695
|
+
"TRUCK_FACTOR",
|
|
4696
|
+
(blob, cache) => {
|
|
4697
|
+
if (!cache.legend) {
|
|
4698
|
+
cache.legend = [
|
|
4699
|
+
Math.floor(Math.log2(data.authorsUnion.length)) + 1,
|
|
4700
|
+
(n) => `${Math.pow(2, n)}`,
|
|
4701
|
+
(n) => `hsl(0,75%,${50 + n * (40 / (Math.floor(Math.log2(data.authorsUnion.length)) + 1))}%)`,
|
|
4702
|
+
(blob2) => {
|
|
4703
|
+
var _a;
|
|
4704
|
+
return Math.floor(Math.log2(Object.entries(((_a = blob2.unionedAuthors) == null ? void 0 : _a.HISTORICAL) ?? []).length));
|
|
4705
|
+
}
|
|
4706
|
+
];
|
|
4707
|
+
}
|
|
4708
|
+
truckmap.setColor(blob, cache);
|
|
4709
|
+
}
|
|
4722
4710
|
]
|
|
4723
4711
|
];
|
|
4724
4712
|
}
|
|
@@ -4829,6 +4817,60 @@ function setDominanceColor(blob, cache, authorshipType) {
|
|
|
4829
4817
|
return;
|
|
4830
4818
|
}
|
|
4831
4819
|
}
|
|
4820
|
+
function lastChangedColorSteps(n) {
|
|
4821
|
+
switch (n) {
|
|
4822
|
+
case 5:
|
|
4823
|
+
return "#08519c";
|
|
4824
|
+
case 4:
|
|
4825
|
+
return "#3182bd";
|
|
4826
|
+
case 3:
|
|
4827
|
+
return "#6baed6";
|
|
4828
|
+
case 2:
|
|
4829
|
+
return "#9ecae1";
|
|
4830
|
+
case 1:
|
|
4831
|
+
return "#c6dbef";
|
|
4832
|
+
case 0:
|
|
4833
|
+
return "#cff2ff";
|
|
4834
|
+
default:
|
|
4835
|
+
return "grey";
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4838
|
+
function lastChangedColorText(n) {
|
|
4839
|
+
switch (n) {
|
|
4840
|
+
case 5:
|
|
4841
|
+
return "1y";
|
|
4842
|
+
case 4:
|
|
4843
|
+
return "1m";
|
|
4844
|
+
case 3:
|
|
4845
|
+
return "1w";
|
|
4846
|
+
case 2:
|
|
4847
|
+
return "2d";
|
|
4848
|
+
case 1:
|
|
4849
|
+
return "1d";
|
|
4850
|
+
case 0:
|
|
4851
|
+
return "now";
|
|
4852
|
+
default:
|
|
4853
|
+
return "grey";
|
|
4854
|
+
}
|
|
4855
|
+
}
|
|
4856
|
+
function mapEpochToStep(input) {
|
|
4857
|
+
const diff = Date.now() / 1e3 - input;
|
|
4858
|
+
if (diff >= 31556926)
|
|
4859
|
+
return 5;
|
|
4860
|
+
else if (diff < 31556926 && diff >= 2629743)
|
|
4861
|
+
return 4;
|
|
4862
|
+
else if (diff < 2629743 && diff >= 604800)
|
|
4863
|
+
return 3;
|
|
4864
|
+
else if (diff < 604800 && diff >= 172800)
|
|
4865
|
+
return 2;
|
|
4866
|
+
else if (diff < 172800 && diff >= 86400)
|
|
4867
|
+
return 1;
|
|
4868
|
+
else if (diff < 86400)
|
|
4869
|
+
return 0;
|
|
4870
|
+
}
|
|
4871
|
+
function cacheAgeColor(blob, cache) {
|
|
4872
|
+
cache.colormap.set(blob.path, lastChangedColorSteps(mapEpochToStep(blob.lastChangeEpoch ?? 0) ?? -1));
|
|
4873
|
+
}
|
|
4832
4874
|
var SpectrumTranslater = class {
|
|
4833
4875
|
constructor(input_min, input_max, target_min, target_max) {
|
|
4834
4876
|
this.scale = (target_max - target_min) / (input_max - input_min);
|
|
@@ -4843,27 +4885,29 @@ var SpectrumTranslater = class {
|
|
|
4843
4885
|
return this.target_max - this.translate(input) + this.target_min;
|
|
4844
4886
|
}
|
|
4845
4887
|
};
|
|
4846
|
-
var
|
|
4847
|
-
constructor(
|
|
4888
|
+
var TruckFactorTranslater = class {
|
|
4889
|
+
constructor(author_count) {
|
|
4848
4890
|
this.min_lightness = 50;
|
|
4849
|
-
this.
|
|
4850
|
-
this.
|
|
4891
|
+
this.max_lighness = 90;
|
|
4892
|
+
this.step = (this.max_lighness - this.min_lightness) / Math.floor(Math.log2(author_count));
|
|
4851
4893
|
}
|
|
4852
4894
|
getColor(value) {
|
|
4853
|
-
|
|
4895
|
+
const level = Math.floor(Math.log2(value));
|
|
4896
|
+
return `hsl(0,75%,${this.min_lightness + level * this.step}%)`;
|
|
4854
4897
|
}
|
|
4855
4898
|
setColor(blob, cache) {
|
|
4856
|
-
|
|
4899
|
+
var _a;
|
|
4900
|
+
cache.colormap.set(blob.path, this.getColor(Object.entries(((_a = blob.unionedAuthors) == null ? void 0 : _a.HISTORICAL) ?? []).length));
|
|
4857
4901
|
}
|
|
4858
4902
|
};
|
|
4859
4903
|
var HeatMapTranslater = class {
|
|
4860
4904
|
constructor(min, max) {
|
|
4861
4905
|
this.min_lightness = 50;
|
|
4862
4906
|
this.max_lightness = 95;
|
|
4863
|
-
this.
|
|
4907
|
+
this.translater = new SpectrumTranslater(min, max, this.min_lightness, this.max_lightness);
|
|
4864
4908
|
}
|
|
4865
4909
|
getColor(value) {
|
|
4866
|
-
return `hsl(20,100%,${this.
|
|
4910
|
+
return `hsl(20,100%,${this.translater.inverseTranslate(value)}%)`;
|
|
4867
4911
|
}
|
|
4868
4912
|
setColor(blob, cache) {
|
|
4869
4913
|
cache.colormap.set(blob.path, this.getColor(blob.noCommits));
|
|
@@ -4916,6 +4960,57 @@ function usePath() {
|
|
|
4916
4960
|
return context;
|
|
4917
4961
|
}
|
|
4918
4962
|
|
|
4963
|
+
// src/util.ts
|
|
4964
|
+
init_react();
|
|
4965
|
+
function dateFormatLong(epochTime) {
|
|
4966
|
+
if (!epochTime)
|
|
4967
|
+
return "Invalid date";
|
|
4968
|
+
return new Date(epochTime * 1e3).toLocaleString("en-gb", {
|
|
4969
|
+
day: "2-digit",
|
|
4970
|
+
month: "short",
|
|
4971
|
+
year: "numeric"
|
|
4972
|
+
});
|
|
4973
|
+
}
|
|
4974
|
+
function dateTimeFormatShort(epochTime) {
|
|
4975
|
+
return new Date(epochTime).toLocaleString("en-gb", {
|
|
4976
|
+
hour: "2-digit",
|
|
4977
|
+
minute: "2-digit",
|
|
4978
|
+
day: "2-digit",
|
|
4979
|
+
month: "short",
|
|
4980
|
+
year: "2-digit"
|
|
4981
|
+
});
|
|
4982
|
+
}
|
|
4983
|
+
function dateFormatRelative(epochTime) {
|
|
4984
|
+
const now = Date.now();
|
|
4985
|
+
const hourMillis = 60 * 60 * 1e3;
|
|
4986
|
+
const dayMillis = 24 * hourMillis;
|
|
4987
|
+
const difference = now - epochTime * 1e3;
|
|
4988
|
+
if (difference < 0)
|
|
4989
|
+
return "Unknown time ago";
|
|
4990
|
+
if (difference > dayMillis) {
|
|
4991
|
+
const days = Math.floor(difference / dayMillis);
|
|
4992
|
+
return `${days} day${days > 1 ? "s" : ""} ago`;
|
|
4993
|
+
}
|
|
4994
|
+
const hours = Math.floor(difference / hourMillis);
|
|
4995
|
+
if (hours > 1)
|
|
4996
|
+
return `${hours} hours ago`;
|
|
4997
|
+
if (hours === 1)
|
|
4998
|
+
return "1 hour ago";
|
|
4999
|
+
return "<1 hour ago";
|
|
5000
|
+
}
|
|
5001
|
+
var last = (arr) => arr[arr.length - 1];
|
|
5002
|
+
var allExceptLast = (arr) => {
|
|
5003
|
+
if (arr.length <= 1)
|
|
5004
|
+
return [];
|
|
5005
|
+
return arr.slice(0, arr.length - 1);
|
|
5006
|
+
};
|
|
5007
|
+
function getSeparator(path) {
|
|
5008
|
+
if (path.includes("\\"))
|
|
5009
|
+
return "\\";
|
|
5010
|
+
return "/";
|
|
5011
|
+
}
|
|
5012
|
+
var getPathFromRepoAndHead = (repo, branch) => [repo, branch].join("/");
|
|
5013
|
+
|
|
4919
5014
|
// src/components/Details.tsx
|
|
4920
5015
|
var import_byte_size = __toESM(require("byte-size"));
|
|
4921
5016
|
var import_material3 = require("@styled-icons/material");
|
|
@@ -5453,16 +5548,42 @@ var GradArrow = import_styled_components9.default.i`
|
|
|
5453
5548
|
left: calc(${({ position }) => position * 100}% - ${estimatedLetterWidth}px);
|
|
5454
5549
|
filter: drop-shadow(0px -2px 0px #fff);
|
|
5455
5550
|
`;
|
|
5551
|
+
var SegmentArrow = import_styled_components9.default.i`
|
|
5552
|
+
display: ${({ visible }) => visible ? "initital" : "none"};
|
|
5553
|
+
transition: 500ms;
|
|
5554
|
+
position: relative;
|
|
5555
|
+
bottom: ${({ height }) => `${height}px`};
|
|
5556
|
+
left: calc(${({ position }) => position}% - ${estimatedLetterWidth}px);
|
|
5557
|
+
filter: drop-shadow(0px -2px 0px #fff);
|
|
5558
|
+
`;
|
|
5456
5559
|
var StyledBox = (0, import_styled_components9.default)(Box)`
|
|
5457
5560
|
position: sticky;
|
|
5458
5561
|
bottom: 0;
|
|
5459
5562
|
`;
|
|
5460
5563
|
function Legend(props) {
|
|
5461
5564
|
const { metricType, authorshipType } = useOptions();
|
|
5462
|
-
const metricsData = useMetrics();
|
|
5565
|
+
const [metricsData, _] = useMetrics();
|
|
5463
5566
|
const metricCache = metricsData[authorshipType].get(metricType) ?? void 0;
|
|
5464
5567
|
if (metricCache === void 0)
|
|
5465
5568
|
return null;
|
|
5569
|
+
let legend = /* @__PURE__ */ React.createElement(React.Fragment, null);
|
|
5570
|
+
switch (getMetricLegendType(metricType)) {
|
|
5571
|
+
case "POINT":
|
|
5572
|
+
legend = /* @__PURE__ */ React.createElement(PointMetricLegend, {
|
|
5573
|
+
metricCache
|
|
5574
|
+
});
|
|
5575
|
+
break;
|
|
5576
|
+
case "GRADIENT":
|
|
5577
|
+
legend = /* @__PURE__ */ React.createElement(GradientMetricLegend, {
|
|
5578
|
+
metricCache
|
|
5579
|
+
});
|
|
5580
|
+
break;
|
|
5581
|
+
case "SEGMENTS":
|
|
5582
|
+
legend = /* @__PURE__ */ React.createElement(SegmentMetricLegend, {
|
|
5583
|
+
metricCache
|
|
5584
|
+
});
|
|
5585
|
+
break;
|
|
5586
|
+
}
|
|
5466
5587
|
return /* @__PURE__ */ React.createElement(StyledBox, null, /* @__PURE__ */ React.createElement(BoxSubTitle, null, Metric[metricType]), /* @__PURE__ */ React.createElement(Spacer, null), /* @__PURE__ */ React.createElement(BoxP, null, getMetricDescription(metricType, authorshipType)), /* @__PURE__ */ React.createElement(Spacer, {
|
|
5467
5588
|
lg: true
|
|
5468
5589
|
}), metricType === "TOP_CONTRIBUTOR" || metricType === "SINGLE_AUTHOR" ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Button, {
|
|
@@ -5472,10 +5593,74 @@ function Legend(props) {
|
|
|
5472
5593
|
height: "1rem"
|
|
5473
5594
|
}), "Merge duplicate users"), /* @__PURE__ */ React.createElement(Spacer, {
|
|
5474
5595
|
lg: true
|
|
5475
|
-
})) : null,
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5596
|
+
})) : null, legend);
|
|
5597
|
+
}
|
|
5598
|
+
function SegmentMetricLegend({ metricCache }) {
|
|
5599
|
+
const [steps, textGenerator, colorGenerator, offsetStepCalc] = metricCache.legend;
|
|
5600
|
+
const width = 100 / steps;
|
|
5601
|
+
let arrowVisible = false;
|
|
5602
|
+
let arrowOffset = 0;
|
|
5603
|
+
const { clickedObject } = useClickedObject();
|
|
5604
|
+
if ((clickedObject == null ? void 0 : clickedObject.type) == "blob") {
|
|
5605
|
+
arrowVisible = true;
|
|
5606
|
+
arrowOffset = width / 2 + width * offsetStepCalc(clickedObject);
|
|
5607
|
+
}
|
|
5608
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
|
|
5609
|
+
style: { display: `flex`, flexDirection: `row` }
|
|
5610
|
+
}, [...Array(steps).fill(1)].map((_, i) => {
|
|
5611
|
+
return steps > 5 ? /* @__PURE__ */ React.createElement(MetricSegment, {
|
|
5612
|
+
key: `legend-${i}`,
|
|
5613
|
+
width,
|
|
5614
|
+
color: colorGenerator(i),
|
|
5615
|
+
text: textGenerator(i),
|
|
5616
|
+
top: i % 2 === 0
|
|
5617
|
+
}) : /* @__PURE__ */ React.createElement(TopMetricSegment, {
|
|
5618
|
+
key: `legend-${i}`,
|
|
5619
|
+
width,
|
|
5620
|
+
color: colorGenerator(i),
|
|
5621
|
+
text: textGenerator(i)
|
|
5622
|
+
});
|
|
5623
|
+
})), /* @__PURE__ */ React.createElement(SegmentArrow, {
|
|
5624
|
+
visible: arrowVisible,
|
|
5625
|
+
position: arrowOffset,
|
|
5626
|
+
height: steps > 5 ? 50 : 10
|
|
5627
|
+
}, "\u25B2"));
|
|
5628
|
+
}
|
|
5629
|
+
function MetricSegment({ width, color, text, top }) {
|
|
5630
|
+
if (top)
|
|
5631
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
5632
|
+
style: { display: "flex", flexDirection: "column", width: `${width}%` }
|
|
5633
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
5634
|
+
style: { textAlign: "left", height: "20px", marginBottom: "-6px" }
|
|
5635
|
+
}, text), /* @__PURE__ */ React.createElement("div", {
|
|
5636
|
+
style: { textAlign: "left", height: "20px", marginBottom: "-2px" }
|
|
5637
|
+
}, "/"), /* @__PURE__ */ React.createElement("div", {
|
|
5638
|
+
style: { backgroundColor: color, height: "20px" }
|
|
5639
|
+
}), /* @__PURE__ */ React.createElement("div", {
|
|
5640
|
+
style: { textAlign: "left", height: "40px" }
|
|
5641
|
+
}));
|
|
5642
|
+
else
|
|
5643
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
5644
|
+
style: { display: "flex", flexDirection: "column", width: `${width}%` }
|
|
5645
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
5646
|
+
style: { textAlign: "left", height: "32px" }
|
|
5647
|
+
}), /* @__PURE__ */ React.createElement("div", {
|
|
5648
|
+
style: { backgroundColor: color, height: "20px" }
|
|
5649
|
+
}), /* @__PURE__ */ React.createElement("div", {
|
|
5650
|
+
style: { textAlign: "left", height: "20px", marginTop: "-7px" }
|
|
5651
|
+
}, "\\"), /* @__PURE__ */ React.createElement("div", {
|
|
5652
|
+
style: { textAlign: "left", height: "20px", marginTop: "-4px" }
|
|
5653
|
+
}, text));
|
|
5654
|
+
}
|
|
5655
|
+
function TopMetricSegment({ width, color, text }) {
|
|
5656
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
5657
|
+
style: { display: "flex", flexDirection: "column", width: `${width}%` }
|
|
5658
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
5659
|
+
style: { textAlign: "left", height: "20px", marginBottom: "-6px" }
|
|
5660
|
+
}, text), /* @__PURE__ */ React.createElement("div", {
|
|
5661
|
+
style: { textAlign: "left", height: "20px", marginBottom: "-2px" }
|
|
5662
|
+
}, "/"), /* @__PURE__ */ React.createElement("div", {
|
|
5663
|
+
style: { backgroundColor: color, height: "20px" }
|
|
5479
5664
|
}));
|
|
5480
5665
|
}
|
|
5481
5666
|
function GradientMetricLegend({ metricCache }) {
|
|
@@ -6287,7 +6472,7 @@ function Tooltip({ hoveredBlob }) {
|
|
|
6287
6472
|
const mouse = (0, import_react_use3.useMouse)(documentElementRef);
|
|
6288
6473
|
const unitRaw = useCSSVar("--unit");
|
|
6289
6474
|
const unit = unitRaw ? Number(unitRaw.replace("px", "")) : 0;
|
|
6290
|
-
const metricsData = useMetrics();
|
|
6475
|
+
const [metricsData, _] = useMetrics();
|
|
6291
6476
|
const color = (0, import_react12.useMemo)(() => {
|
|
6292
6477
|
var _a, _b;
|
|
6293
6478
|
if (!hoveredBlob) {
|
|
@@ -6326,7 +6511,7 @@ function Tooltip({ hoveredBlob }) {
|
|
|
6326
6511
|
})));
|
|
6327
6512
|
}
|
|
6328
6513
|
function ColorMetricDependentInfo(props) {
|
|
6329
|
-
var _a, _b, _c, _d, _e, _f;
|
|
6514
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
6330
6515
|
switch (props.metric) {
|
|
6331
6516
|
case "MOST_COMMITS":
|
|
6332
6517
|
const noCommits = (_a = props.hoveredBlob) == null ? void 0 : _a.noCommits;
|
|
@@ -6353,6 +6538,17 @@ function ColorMetricDependentInfo(props) {
|
|
|
6353
6538
|
if (!dominant)
|
|
6354
6539
|
return null;
|
|
6355
6540
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, dominant[0]);
|
|
6541
|
+
case "TRUCK_FACTOR":
|
|
6542
|
+
const authorCount = Object.entries(((_h = (_g = props.hoveredBlob) == null ? void 0 : _g.unionedAuthors) == null ? void 0 : _h.HISTORICAL) ?? []).length;
|
|
6543
|
+
switch (authorCount) {
|
|
6544
|
+
case 0:
|
|
6545
|
+
return null;
|
|
6546
|
+
case 1:
|
|
6547
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, "1 author");
|
|
6548
|
+
default:
|
|
6549
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, authorCount, " authors");
|
|
6550
|
+
}
|
|
6551
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null);
|
|
6356
6552
|
default:
|
|
6357
6553
|
return null;
|
|
6358
6554
|
}
|
|
@@ -6473,7 +6669,7 @@ var Node3 = (0, import_react13.memo)(function Node4({ d, isRoot }) {
|
|
|
6473
6669
|
});
|
|
6474
6670
|
function Circle({ d, isSearchMatch }) {
|
|
6475
6671
|
var _a;
|
|
6476
|
-
const metricsData = useMetrics();
|
|
6672
|
+
const [metricsData, _] = useMetrics();
|
|
6477
6673
|
const { metricType, authorshipType } = useOptions();
|
|
6478
6674
|
const props = useToggleableSpring({
|
|
6479
6675
|
cx: d.x,
|
|
@@ -6497,7 +6693,7 @@ var CircleSVG = (0, import_styled_components12.default)(import_web2.animated.cir
|
|
|
6497
6693
|
`;
|
|
6498
6694
|
function Rect({ d, isSearchMatch }) {
|
|
6499
6695
|
var _a;
|
|
6500
|
-
const metricsData = useMetrics();
|
|
6696
|
+
const [metricsData, _] = useMetrics();
|
|
6501
6697
|
const { metricType, authorshipType } = useOptions();
|
|
6502
6698
|
const props = useToggleableSpring({
|
|
6503
6699
|
x: d.x0,
|
|
@@ -7020,17 +7216,14 @@ function UnionAuthorsModal({ visible, onClose }) {
|
|
|
7020
7216
|
}
|
|
7021
7217
|
const transitionData = (0, import_remix6.useTransition)();
|
|
7022
7218
|
const disabled = transitionData.state !== "idle";
|
|
7023
|
-
const metrics = useMetrics();
|
|
7219
|
+
const [metrics, authorColors] = useMetrics();
|
|
7024
7220
|
const ungroupedUsersSorted = authors.filter((a) => !flattedUnionedAuthors.includes(a)).slice(0).sort(stringSorter);
|
|
7025
7221
|
function handleModalWrapperClick(event) {
|
|
7026
7222
|
if (event.target === event.currentTarget)
|
|
7027
7223
|
onClose();
|
|
7028
7224
|
}
|
|
7029
7225
|
(0, import_react_use5.useKey)("Escape", onClose);
|
|
7030
|
-
const getColorFromDisplayName = (displayName) =>
|
|
7031
|
-
var _a, _b;
|
|
7032
|
-
return ((_b = ((_a = metrics.HISTORICAL.get("TOP_CONTRIBUTOR")) == null ? void 0 : _a.legend).get(displayName)) == null ? void 0 : _b.color) ?? "#333";
|
|
7033
|
-
};
|
|
7226
|
+
const getColorFromDisplayName = (displayName) => authorColors.get(displayName) ?? "#333";
|
|
7034
7227
|
if (!visible)
|
|
7035
7228
|
return null;
|
|
7036
7229
|
return /* @__PURE__ */ React.createElement(ModalWrapper, {
|
|
@@ -7518,7 +7711,7 @@ var AnalyzedTag = import_styled_components20.default.span`
|
|
|
7518
7711
|
|
|
7519
7712
|
// server-assets-manifest:@remix-run/dev/assets-manifest
|
|
7520
7713
|
init_react();
|
|
7521
|
-
var assets_manifest_default = { "version": "
|
|
7714
|
+
var assets_manifest_default = { "version": "1ef27dc7", "entry": { "module": "/build/entry.client-CDN524WE.js", "imports": ["/build/_shared/chunk-Y7FU7OLJ.js", "/build/_shared/chunk-YDCVFN7Q.js"] }, "routes": { "root": { "id": "root", "parentId": void 0, "path": "", "index": void 0, "caseSensitive": void 0, "module": "/build/root-RVNUJ3UD.js", "imports": ["/build/_shared/chunk-FSZBSYJE.js", "/build/_shared/chunk-4LCJRRXI.js"], "hasAction": false, "hasLoader": false, "hasCatchBoundary": true, "hasErrorBoundary": true }, "routes/$repo.$": { "id": "routes/$repo.$", "parentId": "root", "path": ":repo/*", "index": void 0, "caseSensitive": void 0, "module": "/build/routes/$repo.$-DOVI33K6.js", "imports": ["/build/_shared/chunk-6WSXAQ4H.js"], "hasAction": true, "hasLoader": true, "hasCatchBoundary": false, "hasErrorBoundary": true }, "routes/index": { "id": "routes/index", "parentId": "root", "path": void 0, "index": true, "caseSensitive": void 0, "module": "/build/routes/index-QLBDLJWG.js", "imports": ["/build/_shared/chunk-6WSXAQ4H.js"], "hasAction": true, "hasLoader": true, "hasCatchBoundary": false, "hasErrorBoundary": false } }, "url": "/build/manifest-1EF27DC7.js" };
|
|
7522
7715
|
|
|
7523
7716
|
// server-entry-module:@remix-run/dev/server-build
|
|
7524
7717
|
var entry = { module: entry_server_exports };
|