@atomist/sdm-pack-aspect
Version:
an Atomist SDM Extension Pack for visualizing drift across an organization
185 lines • 8.82 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const React = require("react");
const _ = require("lodash");
const api_1 = require("../lib/routes/api");
function displayCurrentIdeal(currentIdeal) {
return React.createElement("h2", null,
"Current ideal: ",
currentIdeal.displayValue);
}
/* This element will contain the full data value for one level, about the item hovered over. */
function levelDataListItem(item) {
return React.createElement("li", { key: "li-" + item.textAreaId },
React.createElement("label", { htmlFor: item.textAreaId },
item.labelText,
": "),
React.createElement("div", { className: "unfrozenLevelData", id: item.textAreaId }));
}
function displayTagGroup(tagGroup) {
return React.createElement("div", null,
tagGroup.tagSelection.length > 0 && React.createElement("div", { className: "tagGroup" },
"clear:",
React.createElement("form", { method: "GET", action: "/explore" },
React.createElement("input", { type: "hidden", name: "explore", value: "true" }),
React.createElement("input", { className: "resetTagSelection", type: "submit", value: "CLEAR" }))),
tagGroup.allTagNames().map(n => displayTagButtons(tagGroup, n)));
}
function displayTagButtons(tagGroup, tagName) {
const percentageWithTag = tagGroup.getPercentageOfProjects(tagName);
const percentageBar = React.createElement("div", { className: "percentageOfProjectWithoutTag" },
React.createElement("div", { className: "percentageOfProjectsWithTag", style: { width: percentageWithTag + "%" } },
percentageWithTag,
"%"),
100 - percentageWithTag,
"%");
const description = tagGroup.getDescription(tagName) + (tagGroup.isWarning(tagName) ? " - WARN" : "")
+ (tagGroup.isError(tagName) ? " - ERROR" : "");
return React.createElement("div", { className: "tagGroup " +
(tagGroup.isWarning(tagName) ? "warnTagGroup " : "") +
(tagGroup.isError(tagName) ? "errorTagGroup " : "") +
(tagGroup.isRequired(tagName) ? "requiredTag " : "") +
(tagGroup.isExcluded(tagName) ? "excludedTag" : "") },
percentageBar,
React.createElement("img", { className: "taggydoober", src: "/taggydoober.png", title: description }),
React.createElement("span", { className: "tagDescription", title: description }, tagName),
React.createElement("form", { method: "GET", action: "/explore" },
React.createElement("input", { type: "hidden", name: "explore", value: "true" }),
React.createElement("input", { type: "hidden", name: "tags", value: tagGroup.tagSelectionForRequire(tagName).join(",") }),
React.createElement("input", { className: "requireButton", type: "submit", value: "Yes please", title: tagGroup.describeRequire(tagName) })),
React.createElement("form", { method: "GET", action: "/explore" },
React.createElement("input", { type: "hidden", name: "explore", value: "true" }),
React.createElement("input", { type: "hidden", name: "tags", value: tagGroup.tagSelectionForExclude(tagName).join(",") }),
React.createElement("input", { className: "excludeButton", type: "submit", value: "Please no", alt: "alt text", title: tagGroup.describeExclude(tagName) })));
}
/**
* Class backing displayTagButtons
*/
class TagGroup {
constructor(tagSelection, treeWithTags) {
this.tagSelection = tagSelection;
this.tagsInData = treeWithTags && treeWithTags.tags ? treeWithTags.tags : [];
this.totalProjectsDisplayed = treeWithTags ? treeWithTags.matchingRepoCount : 0;
}
allTagNames() {
const tagsFromData = this.tagsInData.map(t => t.name);
const tagsFromSelection = this.tagSelection.map(this.dontFeelExcluded);
return _.uniq([...tagsFromSelection, ...tagsFromData]);
}
isRequired(tagName) {
return this.tagSelection.includes(tagName);
}
isExcluded(tagName) {
return this.tagSelection.includes(this.pleaseExclude(tagName));
}
isWarning(tagName) {
const tagUsage = this.tagsInData.find(tu => tu.name === tagName);
return tagUsage && tagUsage.severity === "warn";
}
isError(tagName) {
const tagUsage = this.tagsInData.find(tu => tu.name === tagName);
return tagUsage && tagUsage.severity === "error";
}
getDescription(tagName) {
const tagUsage = this.tagsInData.find(tu => tu.name === tagName);
return tagUsage ? tagUsage.description : "";
}
getPercentageOfProjects(tagName) {
if (this.isExcluded(tagName)) {
return 0;
}
if (this.isRequired(tagName)) {
return 100;
}
const data = this.tagsInData.find(t => t.name === tagName);
if (!data) {
return 0; // whatever
}
return Math.round(data.count * 100 / this.totalProjectsDisplayed);
}
describeExclude(tagName) {
if (this.isRequired(tagName)) {
return `Switch to excluding ${tagName} projects`;
}
if (this.isExcluded(tagName)) {
return `Currently excluding ${tagName} projects`;
}
return `Exclude ${tagName} projects`;
}
describeRequire(tagName) {
if (this.isRequired(tagName)) {
return `Currently showing only ${tagName} projects`;
}
const dataTag = this.tagsInData.find(t => t.name === tagName);
if (dataTag) {
return `Show only ${tagName} projects (${dataTag.count})`;
}
return `Show only ${tagName} projects`;
}
tagSelectionForRequire(tagName) {
if (this.isRequired(tagName)) {
// toggle
return this.tagSelection.filter(tn => tn !== tagName);
}
const existingTagsMinusAnyExclusionOfThisTag = this.tagSelection.filter(tn => tn !== this.pleaseExclude(tagName));
return [...existingTagsMinusAnyExclusionOfThisTag, tagName];
}
tagSelectionForExclude(tagName) {
if (this.isExcluded(tagName)) {
// toggle
return this.tagSelection.filter(tn => tn !== this.pleaseExclude(tagName));
}
const existingTagsMinusAnyRequireOfThisTag = this.tagSelection.filter(tn => tn !== tagName);
return [...existingTagsMinusAnyRequireOfThisTag, this.pleaseExclude(tagName)];
}
pleaseExclude(tagName) {
return "!" + tagName;
}
dontFeelExcluded(tagName) {
return tagName.replace("!", "");
}
}
exports.TagGroup = TagGroup;
function SunburstPage(props) {
const perLevelDataItems = !props.tree || !props.tree.circles ?
[] :
props.tree.circles.map((c, i) => ({ textAreaId: "levelData-" + i, labelText: c.meaning }));
const d3ScriptCall = `<script>
const data = ${JSON.stringify(props.tree)};
SunburstYo.sunburst("${props.workspaceId}",
data,
window.innerWidth - 250,
window.innerHeight - 100,
{ perLevelDataElementIds: [${perLevelDataItems.map(p => `"` + p.textAreaId + `"`).join(",")}],
fieldsToDisplay: ${JSON.stringify(props.fieldsToDisplay)}
});
</script>`;
const thingies = !props.tree ? "Hover over a slice to see its details" :
React.createElement("ul", null, perLevelDataItems.map(levelDataListItem));
const tagGroup = new TagGroup(props.selectedTags, props.tree);
const tagButtons = displayTagGroup(tagGroup);
const h2 = props.subheading ?
React.createElement("h2", null, props.subheading) :
React.createElement("h2", null,
api_1.describeSelectedTagsToAnimals(props.selectedTags),
" - ",
props.tree.matchingRepoCount,
" of ",
props.tree.repoCount,
" repositories");
const idealDisplay = props.currentIdeal ? displayCurrentIdeal(props.currentIdeal) : "";
return React.createElement("div", { className: "sunburst" },
React.createElement("h1", null, props.heading),
h2,
tagButtons,
idealDisplay,
React.createElement("div", { className: "wrapper" },
React.createElement("div", { id: "putSvgHere", className: "sunburstSvg" }),
React.createElement("div", { id: "dataAboutWhatYouClicked", className: "sunburstData" },
thingies,
React.createElement("div", { id: "additionalDataAboutWhatYouClicked" }))),
React.createElement("div", { dangerouslySetInnerHTML: { __html: d3ScriptCall } }),
React.createElement("a", { href: props.dataUrl, type: "application/json" }, "Raw data"));
}
exports.SunburstPage = SunburstPage;
//# sourceMappingURL=sunburstPage.js.map