UNPKG

@activecollab/components

Version:

ActiveCollab Components

1,386 lines 54.2 kB
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Spine = exports.SourceCodeSection = exports.IssueRow = exports.HistoryDialog = exports.CompletedHeader = exports.CodeRow = void 0;
var _react = _interopRequireWildcard(require("react"));
var _styledComponents = _interopRequireWildcard(require("styled-components"));
var _LinkBranchOrPullRequestDialog = require("./LinkBranchOrPullRequestDialog");
var _LinkingCommandsButton = require("./LinkingCommandsButton");
var _RoundAvatar = require("./RoundAvatar");
var _tokens = require("./tokens");
var _AvatarGroup = require("../../components/AvatarGroup");
var _Button = require("../../components/Button");
var _AddToListButton = require("../../components/Button/AddToListButton");
var _Chip = require("../../components/Chip");
var _Dialog = require("../../components/Dialog");
var _IconButton = require("../../components/IconButton");
var _Icons = require("../../components/Icons");
var _StepSequence = require("../../components/StepSequence");
var _Tooltip = require("../../components/Tooltip");
var _Typography = require("../../components/Typography");
var _utils = require("../../utils");
var _excluded = ["size", "bg", "initials", "alt"];
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
/**
 * Source Code section of a task — the shared subsystem behind the
 * `Presentation/Source/Task Source` stories (Mix / All Open / All Completed).
 * Holds the row types (issue / pull-or-merge request / branch), the pipeline
 * spine, the history dialog, and the section that lays them out. Extracted into
 * `shared/` so all three stories render the same components; editing a row type
 * here updates every story at once.
 */

var SANS = '-apple-system, BlinkMacSystemFont, "Roboto", "Helvetica Neue", Arial, sans-serif';

/* Icons in the collection colour either via `stroke` (outline glyphs whose root
   is `fill="none"`) or via `fill`. To tint a history glyph by tone we must set
   the right one — this set marks the stroke-based glyphs used in the stream. */
var STROKE_ICONS = new Set([_Icons.GitBranchIcon, _Icons.GitCommitIcon, _Icons.GitPullRequestIcon, _Icons.GitPullRequestDraftIcon, _Icons.GitPullRequestClosedIcon, _Icons.GitMergeIcon, _Icons.GearIcon, _Icons.GearFailedIcon, _Icons.CloudDeployIcon, _Icons.CloudDeployFailedIcon, _Icons.GitRepositoryIcon]);

/** Every event glyph renders in the standard muted gray; success / failure is
    carried by a trailing check / cross after the title instead of the glyph. */
var iconColorProps = function iconColorProps(icon) {
  return STROKE_ICONS.has(icon) ? {
    stroke: "var(--color-theme-600)"
  } : {
    fill: "var(--color-theme-600)"
  };
};

/* ================================================================== */
/* Issue state glyphs (open / closed) — mirror the app's IssueStateIcon */
/* (`CircleDotIcon` when open, filled `CheckboxBlankTogglerIcon` when    */
/* closed). Kept as a helper so the row lead and the status chip share   */
/* the same glyph.                                                       */
/* ================================================================== */

var IssueStateIcon = function IssueStateIcon(_ref) {
  var closed = _ref.closed,
    _ref$size = _ref.size,
    size = _ref$size === void 0 ? 16 : _ref$size;
  return closed ? /*#__PURE__*/_react.default.createElement(_Icons.CheckboxBlankTogglerIcon, {
    width: size,
    height: size,
    fill: "var(--color-primary)"
  }) : /*#__PURE__*/_react.default.createElement(_Icons.CircleDotIcon, {
    width: size,
    height: size
  });
};

/* ================================================================== */
/* Source Code section — data model                                    */
/* ================================================================== */

var STAGE_NAMES = ["Branch", "Commits", "Pull request", "CI / Build", "Deploy"];
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var pad = function pad(n) {
  return String(n).padStart(2, "0");
};

/**
 * Reproduces ActiveCollab's standard `Ago` component (`Angie.functions.ago()`)
 * for the mock: "Just now", "N minutes ago", "Today HH:mm", "Yesterday HH:mm",
 * "MMM D. HH:mm", else "MMM D. YYYY HH:mm". Production must use the real one,
 * which also carries the absolute timestamp in a tooltip and auto-refreshes.
 */
var formatAgo = function formatAgo(minutesAgo) {
  var now = new Date();
  var then = new Date(now.getTime() - minutesAgo * 60000);
  if (minutesAgo < 2) {
    return "Just now";
  }
  if (minutesAgo < 60) {
    return "".concat(Math.floor(minutesAgo), " minutes ago");
  }
  var time = "".concat(pad(then.getHours()), ":").concat(pad(then.getMinutes()));
  if (then.toDateString() === now.toDateString()) {
    return "Today ".concat(time);
  }
  var yesterday = new Date(now.getTime() - 24 * 60 * 60000);
  if (then.toDateString() === yesterday.toDateString()) {
    return "Yesterday ".concat(time);
  }
  var monthDay = "".concat(MONTHS[then.getMonth()], " ").concat(then.getDate(), ".");
  if (then.getFullYear() === now.getFullYear()) {
    return "".concat(monthDay, " ").concat(time);
  }
  return "".concat(monthDay, " ").concat(then.getFullYear(), " ").concat(time);
};

/** A VCS issue. Weakly referenced by any number of branches / PRs. */

/** A branch or pull request read from the VCS. */

var mkStages = function mkStages(defs) {
  return defs.map(function (d, i) {
    return _objectSpread({
      name: STAGE_NAMES[i]
    }, d);
  });
};
var issueCompleted = function issueCompleted(i) {
  return i.state === "closed";
};
var codeCompleted = function codeCompleted(e) {
  return e.status !== "open";
};
var byRecency = function byRecency(a, b) {
  return a.updatedMinsAgo - b.updatedMinsAgo;
};

/** External URL for an element — opens the object in the provider (new tab). */
var issueUrl = function issueUrl(i) {
  return "https://github.com/".concat(i.repoFull, "/issues/").concat(i.ref.replace("#", ""));
};
var codeUrl = function codeUrl(e) {
  if (e.kind === "pr") {
    var _e$title$match$, _e$title$match;
    var number = (_e$title$match$ = (_e$title$match = e.title.match(/#(\d+)/)) === null || _e$title$match === void 0 ? void 0 : _e$title$match[1]) !== null && _e$title$match$ !== void 0 ? _e$title$match$ : "";
    return "https://github.com/".concat(e.repoFull, "/pull/").concat(number);
  }
  return "https://github.com/".concat(e.repoFull, "/tree/").concat(e.title);
};

/* ---- Issues -------------------------------------------------------- */

var ISSUES = [{
  ref: "#482",
  title: "#482 Ranks reset when a contract is archived",
  repo: "backend",
  repoFull: "activecollab/backend",
  state: "open",
  updatedLabel: "20m ago",
  updatedMinsAgo: 20
}, {
  ref: "#455",
  title: "#455 Retainer totals off by a rounding cent",
  repo: "backend",
  repoFull: "activecollab/backend",
  state: "open",
  updatedLabel: "3h ago",
  updatedMinsAgo: 180
}, {
  ref: "#470",
  title: "#470 Cannot set a rank above 100",
  repo: "backend",
  repoFull: "activecollab/backend",
  state: "closed",
  updatedLabel: "4d ago",
  updatedMinsAgo: 5760
}];

/* ---- Branches / pull requests -------------------------------------- */

var CODE_ENTRIES = [{
  // Open PR with a pipeline mid-run: the CI / Build stage is "progress"
  // (blue node, white dot) while Deploy is still "todo". This is the one
  // state note 02 describes but the other examples never show — a healthy
  // task that is currently *doing something*, visible at a glance on the
  // spine. The connector into Build turns green (movement into the stage);
  // the connector into Deploy stays muted.
  kind: "pr",
  title: "#119921 Recalculate ranks when a contract is archived",
  headSha: "3d5a8f1c9b7e2604a1f8c3d5e6079b2a4c6d8e0f",
  repo: "backend",
  repoFull: "activecollab/backend",
  status: "open",
  sourceBranch: "fix/rank-archive-482",
  targetBranch: "main",
  closing: true,
  contributors: [{
    initials: "DA",
    bg: _tokens.AVATAR_COLORS.green
  }],
  commits: {
    value: 8,
    tip: "8 commits · last 1h ago by Dragana A."
  },
  diff: {
    add: 96,
    del: 12,
    tip: "96 additions, 12 deletions across 5 files"
  },
  comments: {
    value: 2,
    tip: "2 comments on the pull request"
  },
  updatedLabel: "10m ago",
  updatedMinsAgo: 10,
  references: ["#482"],
  stages: mkStages([{
    state: "done",
    details: ["fix/rank-archive-482", "on activecollab/backend"]
  }, {
    state: "done",
    details: ["8 commits", "last 1h ago by Dragana A."]
  }, {
    state: "done",
    details: ["#119921 opened", "awaiting review"]
  }, {
    state: "progress",
    details: ["Build running", "CI pipeline #501 in progress"]
  }, {
    state: "todo",
    details: ["Not deployed"]
  }]),
  pipelineSupported: true,
  history: [{
    icon: _Icons.GitBranchIcon,
    title: "Branch created",
    detail: "fix/rank-archive-482 by Dragana A.",
    minutesAgo: 600
  }, {
    icon: _Icons.GitCommitIcon,
    title: "8 commits pushed",
    detail: "Last by Dragana A.: “Recalculate ranks on contract archive”",
    minutesAgo: 90
  }, {
    icon: _Icons.GitPullRequestIcon,
    title: "Pull request opened",
    detail: "Target: main by Dragana A.",
    minutesAgo: 40,
    tone: "progress"
  }, {
    icon: _Icons.EyeIcon,
    title: "Review requested",
    detail: "Requested by Ilija S. and Marko K.",
    minutesAgo: 30
  }, {
    icon: _Icons.GearIcon,
    title: "Build started",
    detail: "CI pipeline #501",
    minutesAgo: 10,
    tone: "progress"
  }]
}, {
  kind: "branch",
  title: "spike/rank-cache",
  headSha: "9f3c1a2b7d4e5f60819a2b3c4d5e6f7081920304",
  repo: "backend",
  repoFull: "activecollab/backend",
  status: "open",
  contributors: [{
    initials: "IS",
    bg: _tokens.AVATAR_COLORS.purple
  }],
  commits: {
    value: 1,
    tip: "1 commit · 30m ago by Ilija S."
  },
  diff: {
    add: 38,
    del: 4,
    tip: "38 additions, 4 deletions across 2 files"
  },
  noPrLabel: "no pull request yet",
  updatedLabel: "30m ago",
  updatedMinsAgo: 30,
  references: [],
  stages: mkStages([{
    state: "done",
    details: ["spike/rank-cache", "on activecollab/backend"]
  }, {
    state: "done",
    details: ["1 commit", "30m ago by Ilija S."]
  }, {
    state: "todo",
    details: ["No pull request opened yet"]
  }]),
  pipelineSupported: false,
  history: [{
    icon: _Icons.GitBranchIcon,
    title: "Branch created",
    detail: "spike/rank-cache by Ilija Studen",
    minutesAgo: 120
  }, {
    icon: _Icons.GitCommitIcon,
    title: "One commit pushed",
    detail: "Ilija Studen: “Prototype rank cache”",
    minutesAgo: 30
  }]
}, {
  kind: "branch",
  title: "feature/retainers-ui-34",
  headSha: "4a7b9c2d1e3f5061728394a5b6c7d8e9f0a1b2c3",
  repo: "frontend",
  repoFull: "activecollab/frontend",
  status: "open",
  contributors: [{
    initials: "DA",
    bg: _tokens.AVATAR_COLORS.green
  }],
  commits: {
    value: 6,
    tip: "6 commits · last 1h ago by Dragana A."
  },
  diff: {
    add: 214,
    del: 52,
    tip: "214 additions, 52 deletions across 9 files"
  },
  noPrLabel: "no pull request yet",
  updatedLabel: "1h ago",
  updatedMinsAgo: 60,
  references: ["#482"],
  stages: mkStages([{
    state: "done",
    details: ["feature/retainers-ui-34", "on activecollab/frontend"]
  }, {
    state: "done",
    details: ["6 commits", "last 1h ago by Dragana A."]
  }, {
    state: "todo",
    details: ["No pull request opened yet"]
  }, {
    state: "todo",
    details: ["No build yet"]
  }, {
    state: "todo",
    details: ["Not deployed"]
  }]),
  pipelineSupported: true,
  history: [{
    icon: _Icons.GitBranchIcon,
    title: "Branch created",
    detail: "feature/retainers-ui-34 by Dragana A.",
    minutesAgo: 480
  }, {
    icon: _Icons.GitCommitIcon,
    title: "6 commits pushed",
    detail: "Last by Dragana A.: “Retainer settings screen”",
    minutesAgo: 60
  }]
}, {
  kind: "pr",
  title: "#119915 Contract UI rank controls",
  headSha: "b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5",
  repo: "frontend",
  repoFull: "activecollab/frontend",
  status: "merged",
  sourceBranch: "feature/contracts-ui-34",
  targetBranch: "main",
  closing: true,
  contributors: [{
    initials: "MK",
    bg: _tokens.AVATAR_COLORS.blue
  }],
  commits: {
    value: 11,
    tip: "11 commits · last 5h ago by Marko K."
  },
  diff: {
    add: 168,
    del: 24,
    tip: "168 additions, 24 deletions across 6 files"
  },
  comments: {
    value: 5,
    tip: "5 comments on the pull request"
  },
  updatedLabel: "5h ago",
  updatedMinsAgo: 300,
  references: ["#455"],
  stages: mkStages([{
    state: "done",
    details: ["feature/contracts-ui-34", "on activecollab/frontend"]
  }, {
    state: "done",
    details: ["11 commits", "last 5h ago by Marko K."]
  }, {
    state: "done",
    details: ["#119915 merged", "approved by 1 reviewer"]
  }, {
    state: "failed",
    details: ["Build failing", "3 of 12 checks failed"]
  }, {
    state: "todo",
    details: ["Not deployed"]
  }]),
  pipelineSupported: true,
  history: [{
    icon: _Icons.GitBranchIcon,
    title: "Branch created",
    detail: "feature/contracts-ui-34 by Marko K.",
    minutesAgo: 11520
  }, {
    icon: _Icons.GitCommitIcon,
    title: "6 commits pushed",
    detail: "Last by Marko K.: “Wire rank controls to contracts API”",
    minutesAgo: 10080
  }, {
    icon: _Icons.GitPullRequestDraftIcon,
    title: "Draft pull request opened",
    detail: "Target: main by Marko K.",
    minutesAgo: 8640
  }, {
    icon: _Icons.GearIcon,
    title: "Build started",
    detail: "CI pipeline #479",
    minutesAgo: 8639,
    tone: "progress"
  }, {
    icon: _Icons.GearFailedIcon,
    title: "Build failed",
    detail: "3 of 12 checks failed",
    minutesAgo: 8635,
    tone: "danger"
  }, {
    icon: _Icons.GitCommitIcon,
    title: "2 commits pushed",
    detail: "Last by Marko K.: “Fix failing snapshot tests”",
    minutesAgo: 7200
  }, {
    icon: _Icons.GearIcon,
    title: "Build passed",
    detail: "All 12 checks passed · CI pipeline #482",
    minutesAgo: 7195,
    tone: "success"
  }, {
    icon: _Icons.GitPullRequestIcon,
    title: "Marked ready for review",
    author: "Marko K.",
    minutesAgo: 5760,
    tone: "progress"
  }, {
    icon: _Icons.EyeIcon,
    title: "Review requested",
    detail: "Requested by Ana P., Ilija S. and 2 more",
    minutesAgo: 5755
  }, {
    icon: _Icons.MessageIcon,
    title: "Changes requested",
    detail: "Request on 4 files by Ana P.",
    minutesAgo: 4320
  }, {
    icon: _Icons.GitCommitIcon,
    title: "One commit pushed",
    detail: "Marko K.: “Address review feedback”",
    minutesAgo: 4000
  }, {
    icon: _Icons.GitPullRequestClosedIcon,
    title: "Pull request closed",
    detail: "Closed without merging by Marko K.",
    minutesAgo: 2880
  }, {
    icon: _Icons.GitPullRequestIcon,
    title: "Pull request reopened",
    detail: "Target: main by Marko K.",
    minutesAgo: 1680,
    tone: "progress"
  }, {
    icon: _Icons.GitCommitIcon,
    title: "4 commits pushed",
    detail: "Last by Marko K.: “Rebuild rank controls with a new segmented layout, keyboard navigation, and analytics events”",
    minutesAgo: 1560
  }, {
    icon: _Icons.CloudDeployIcon,
    title: "Deployed to staging",
    detail: "Release ci-4821",
    minutesAgo: 300,
    tone: "success"
  }, {
    icon: _Icons.CheckIcon,
    title: "Approved",
    detail: "2 approvals · Ana P., Ilija S.",
    minutesAgo: 180,
    tone: "success"
  }, {
    icon: _Icons.GitMergeIcon,
    title: "Pull request merged",
    detail: "Target: main by Marko K.",
    minutesAgo: 38,
    tone: "success"
  }, {
    icon: _Icons.CloudDeployFailedIcon,
    title: "Deploy failed",
    detail: "Target: production by Marko K.",
    minutesAgo: 24,
    tone: "danger"
  }, {
    icon: _Icons.CloudDeployIcon,
    title: "Deployed to production",
    detail: "Release v2026.7.3",
    minutesAgo: 1,
    tone: "success"
  }]
}, {
  kind: "branch",
  title: "feature/retainers-34",
  headSha: "1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d",
  repo: "backend",
  repoFull: "activecollab/backend",
  status: "merged",
  contributors: [{
    initials: "IS",
    bg: _tokens.AVATAR_COLORS.purple
  }],
  commits: {
    value: 14,
    tip: "14 commits · merged 2d ago by Ilija S."
  },
  diff: {
    add: 405,
    del: 37,
    tip: "405 additions, 37 deletions across 11 files"
  },
  updatedLabel: "2d ago",
  updatedMinsAgo: 2880,
  references: ["#482", "#470"],
  stages: mkStages([{
    state: "done",
    details: ["feature/retainers-34", "on activecollab/backend"]
  }, {
    state: "done",
    details: ["14 commits", "merged 2d ago by Ilija S."]
  }, {
    state: "done",
    details: ["Merged via #119909", "into main"]
  }]),
  pipelineSupported: false,
  history: [{
    icon: _Icons.GitBranchIcon,
    title: "Branch created",
    detail: "feature/retainers-34 by Ilija Studen",
    minutesAgo: 4320
  }, {
    icon: _Icons.GitCommitIcon,
    title: "14 commits pushed",
    detail: "Last by Ilija Studen: “Rank model + datastore updates”",
    minutesAgo: 3000
  }, {
    icon: _Icons.GitMergeIcon,
    title: "Branch merged",
    detail: "Target: main by Ilija Studen",
    minutesAgo: 2880,
    tone: "success"
  }]
}, {
  kind: "pr",
  title: "#119909 Allow and update ranks across datastores",
  headSha: "c4d5e6f70819202a3b4c5d6e7f8091a2b3c4d5e6",
  repo: "backend",
  repoFull: "activecollab/backend",
  status: "merged",
  sourceBranch: "feature/retainers-34",
  targetBranch: "main",
  contributors: [{
    initials: "IS",
    bg: _tokens.AVATAR_COLORS.purple
  }, {
    initials: "MK",
    bg: _tokens.AVATAR_COLORS.blue
  }],
  commits: {
    value: 14,
    tip: "14 commits · merged 2d ago by Ilija S."
  },
  diff: {
    add: 405,
    del: 37,
    tip: "405 additions, 37 deletions across 11 files"
  },
  comments: {
    value: 12,
    tip: "12 comments on the pull request"
  },
  updatedLabel: "2d ago",
  updatedMinsAgo: 2900,
  references: ["#482", "#470"],
  stages: mkStages([{
    state: "done",
    details: ["feature/retainers-34", "on activecollab/backend"]
  }, {
    state: "done",
    details: ["14 commits", "last 2d ago by Ilija S."]
  }, {
    state: "done",
    details: ["#119909 merged", "approved by 2 reviewers"]
  }]),
  pipelineSupported: false,
  history: [{
    icon: _Icons.GitPullRequestIcon,
    title: "Pull request opened",
    detail: "Target: main by Ilija Studen",
    minutesAgo: 3000,
    tone: "progress"
  }, {
    icon: _Icons.CheckIcon,
    title: "Approved",
    detail: "2 approvals · Marko K., Janko S.",
    minutesAgo: 2905,
    tone: "success"
  }, {
    icon: _Icons.GitMergeIcon,
    title: "Pull request merged",
    detail: "Target: main by Ilija Studen",
    minutesAgo: 2880,
    tone: "success"
  }]
}, {
  kind: "branch",
  title: "hotfix/rank-typo",
  headSha: "7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9012",
  repo: "backend",
  repoFull: "activecollab/backend",
  status: "deleted",
  contributors: [{
    initials: "MK",
    bg: _tokens.AVATAR_COLORS.blue
  }],
  commits: {
    value: 2,
    tip: "2 commits · deleted 5d ago"
  },
  diff: {
    add: 6,
    del: 3,
    tip: "6 additions, 3 deletions across 1 file"
  },
  updatedLabel: "5d ago",
  updatedMinsAgo: 7000,
  references: ["#470"],
  stages: mkStages([{
    state: "done",
    details: ["hotfix/rank-typo", "on activecollab/backend"]
  }, {
    state: "done",
    details: ["2 commits", "by Marko K."]
  }, {
    state: "todo",
    details: ["No pull request opened"]
  }]),
  pipelineSupported: false,
  history: [{
    icon: _Icons.GitBranchIcon,
    title: "Branch created",
    detail: "hotfix/rank-typo by Marko K.",
    minutesAgo: 8640
  }, {
    icon: _Icons.GitCommitIcon,
    title: "2 commits pushed",
    detail: "Last by Marko K.: “Fix rank label typo”",
    minutesAgo: 8600
  }, {
    icon: _Icons.TrashIcon,
    title: "Branch deleted",
    detail: "Soft deleted by Marko K.",
    minutesAgo: 7000
  }]
}, {
  kind: "pr",
  title: "#119870 Clamp rank to valid range",
  headSha: "d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f701",
  repo: "backend",
  repoFull: "activecollab/backend",
  status: "merged",
  sourceBranch: "fix/rank-clamp-33",
  targetBranch: "main",
  contributors: [{
    initials: "MK",
    bg: _tokens.AVATAR_COLORS.blue
  }],
  commits: {
    value: 4,
    tip: "4 commits · merged 5d ago by Marko K."
  },
  diff: {
    add: 52,
    del: 8,
    tip: "52 additions, 8 deletions across 3 files"
  },
  updatedLabel: "5d ago",
  updatedMinsAgo: 7200,
  references: ["#470"],
  stages: mkStages([{
    state: "done",
    details: ["fix/rank-clamp-33", "on activecollab/backend"]
  }, {
    state: "done",
    details: ["4 commits", "merged 5d ago by Marko K."]
  }, {
    state: "done",
    details: ["#119870 merged", "approved by 1 reviewer"]
  }]),
  pipelineSupported: false,
  history: [{
    icon: _Icons.GitBranchIcon,
    title: "Branch created",
    detail: "fix/rank-clamp-33 by Marko K.",
    minutesAgo: 8640
  }, {
    icon: _Icons.GitPullRequestIcon,
    title: "Pull request opened",
    detail: "Target: main by Marko K.",
    minutesAgo: 8600,
    tone: "progress"
  }, {
    icon: _Icons.GitMergeIcon,
    title: "Pull request merged",
    detail: "Target: main by Marko K.",
    minutesAgo: 7200,
    tone: "success"
  }]
}, {
  kind: "pr",
  title: "#119888 Cache ranks per datastore",
  headSha: "a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4",
  repo: "backend",
  repoFull: "activecollab/backend",
  status: "closed",
  sourceBranch: "feature/rank-datastore-cache",
  targetBranch: "main",
  contributors: [{
    initials: "IS",
    bg: _tokens.AVATAR_COLORS.purple
  }],
  commits: {
    value: 5,
    tip: "5 commits · closed 3d ago by Ilija S."
  },
  diff: {
    add: 120,
    del: 15,
    tip: "120 additions, 15 deletions across 4 files"
  },
  comments: {
    value: 3,
    tip: "3 comments on the pull request"
  },
  updatedLabel: "3d ago",
  updatedMinsAgo: 4320,
  references: ["#455"],
  stages: mkStages([{
    state: "done",
    details: ["feature/rank-datastore-cache", "on activecollab/backend"]
  }, {
    state: "done",
    details: ["5 commits", "last 3d ago by Ilija S."]
  }, {
    state: "todo",
    details: ["#119888 closed without merging"]
  }]),
  pipelineSupported: false,
  history: [{
    icon: _Icons.GitPullRequestIcon,
    title: "Pull request opened",
    detail: "Target: main by Ilija Studen",
    minutesAgo: 5760,
    tone: "progress"
  }, {
    icon: _Icons.GitPullRequestClosedIcon,
    title: "Pull request closed",
    detail: "Closed without merging by Ilija Studen",
    minutesAgo: 4320
  }]
}];

/* ================================================================== */
/* Spine + history dialog (for branches / pull requests)               */
/* ================================================================== */

var StageTip = function StageTip(_ref2) {
  var name = _ref2.name,
    details = _ref2.details;
  return /*#__PURE__*/_react.default.createElement("span", {
    style: {
      display: "block",
      textAlign: "left",
      lineHeight: 1.5
    }
  }, /*#__PURE__*/_react.default.createElement("span", {
    style: {
      display: "block",
      fontWeight: 700
    }
  }, "Stage: ", name), details.map(function (d, i) {
    return /*#__PURE__*/_react.default.createElement("span", {
      key: "".concat(name, "-").concat(i),
      style: {
        display: "block"
      }
    }, d);
  }));
};
var StyledSpineSequence = (0, _styledComponents.default)(_StepSequence.StepSequence).withConfig({
  displayName: "SourceCodeSection__StyledSpineSequence",
  componentId: "sc-rvqbh5-0"
})(["align-self:center;flex-shrink:0;"]);

/** Stage state → the generic look `StepSequence` renders it with. */
var STAGE_STEP = {
  done: {
    tone: "success",
    fill: "solid",
    icon: /*#__PURE__*/_react.default.createElement(_Icons.CheckIcon, {
      fill: "var(--only-white)",
      width: 14,
      height: 14
    })
  },
  progress: {
    tone: "info",
    fill: "solid"
  },
  failed: {
    tone: "danger",
    fill: "solid",
    icon: /*#__PURE__*/_react.default.createElement(_Icons.CloseIcon, {
      fill: "var(--only-white)",
      width: 12,
      height: 12
    })
  },
  todo: {
    tone: "neutral",
    fill: "outline"
  }
};
var Spine = exports.Spine = function Spine(_ref3) {
  var items = _ref3.items,
    onClick = _ref3.onClick;
  return /*#__PURE__*/_react.default.createElement(StyledSpineSequence, {
    ariaLabel: "Open source code history",
    onClick: onClick,
    steps: items.map(function (s) {
      return _objectSpread(_objectSpread({}, STAGE_STEP[s.state]), {}, {
        key: s.name,
        tooltip: /*#__PURE__*/_react.default.createElement(StageTip, s)
      });
    })
  });
};

/* The whole content scrolls together (header + stream + note) once the stream
   is long — the dialog title bar stays fixed, everything below scrolls. */
var StyledHistory = _styledComponents.default.div.withConfig({
  displayName: "SourceCodeSection__StyledHistory",
  componentId: "sc-rvqbh5-1"
})(["font-family:", ";max-height:60vh;overflow-y:auto;padding-right:4px;.hist-header{padding-bottom:20px;margin-bottom:20px;border-bottom:1px solid var(--border-primary);}.hist-name{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}.hist-branches{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:8px;font-size:13px;color:var(--color-theme-600);}.hist-branch{display:inline-flex;align-items:center;gap:4px;}.hist-repo{display:inline-flex;align-items:center;gap:4px;margin-top:6px;font-size:13px;color:var(--color-theme-600);}.sc-chip{display:inline-flex;align-items:center;gap:3px;height:20px;padding:0 8px;border-radius:6px;font-size:11px;font-weight:700;letter-spacing:0.02em;flex-shrink:0;}.sc-chip.done{color:var(--color-primary);background:color-mix(in srgb,var(--color-primary) 15%,transparent);}.sc-chip.gone{color:var(--color-theme-900);background:var(--color-theme-200);border:1px solid var(--border-primary);}.sc-chip.fail{color:var(--red-alert);background:color-mix(in srgb,var(--red-alert) 15%,transparent);}.hist-event{display:flex;align-items:center;gap:12px;padding-bottom:20px;}.hist-event:last-child{padding-bottom:0;}.hist-icon{flex-shrink:0;width:22px;height:22px;display:flex;align-items:center;justify-content:center;}.hist-body{flex:1 1 auto;min-width:0;}.hist-title{display:flex;align-items:center;gap:6px;min-width:0;}.hist-title > *:first-child{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}.hist-status{flex-shrink:0;display:inline-flex;}.hist-line{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:13px;line-height:1.5;color:var(--color-theme-600);}.hist-meta{flex-shrink:0;align-self:flex-start;text-align:right;white-space:nowrap;}.hist-note{display:flex;align-items:center;gap:6px;margin-top:16px;color:var(--color-theme-500);}.hist-note svg{flex-shrink:0;}"], SANS);
var HistoryDialog = exports.HistoryDialog = function HistoryDialog(_ref4) {
  var entry = _ref4.entry,
    onClose = _ref4.onClose;
  return /*#__PURE__*/_react.default.createElement(_Dialog.Dialog, {
    open: !!entry,
    onClose: onClose,
    enableBackgroundClick: true
  }, /*#__PURE__*/_react.default.createElement(_Dialog.Dialog.Title, {
    disableDefaultHeading: true
  }, /*#__PURE__*/_react.default.createElement("div", {
    style: {
      display: "flex",
      alignItems: "center",
      justifyContent: "space-between",
      gap: 12
    }
  }, /*#__PURE__*/_react.default.createElement(_Typography.Header3, null, (entry === null || entry === void 0 ? void 0 : entry.kind) === "branch" ? "Branch History" : "Pull Request History"), /*#__PURE__*/_react.default.createElement(_IconButton.IconButton, {
    type: "button",
    variant: "text gray",
    onClick: onClose
  }, /*#__PURE__*/_react.default.createElement(_Icons.CancelCrossIcon, null)))), /*#__PURE__*/_react.default.createElement(_Dialog.Dialog.ContentDivider, null), /*#__PURE__*/_react.default.createElement(_Dialog.Dialog.Content, null, entry && /*#__PURE__*/_react.default.createElement(StyledHistory, null, /*#__PURE__*/_react.default.createElement("div", {
    className: "hist-header"
  }, /*#__PURE__*/_react.default.createElement("div", {
    className: "hist-name"
  }, /*#__PURE__*/_react.default.createElement(_Typography.Body1, {
    weight: "medium"
  }, entry.status === "deleted" ? entry.title : /*#__PURE__*/_react.default.createElement(TitleLink, {
    href: codeUrl(entry),
    target: "_blank",
    rel: "noopener noreferrer"
  }, entry.title)), /*#__PURE__*/_react.default.createElement(CodeStatusChip, {
    entry: entry
  })), entry.kind === "pr" && entry.sourceBranch && entry.targetBranch && /*#__PURE__*/_react.default.createElement("div", {
    className: "hist-branches"
  }, /*#__PURE__*/_react.default.createElement("span", {
    className: "hist-branch"
  }, /*#__PURE__*/_react.default.createElement(_Icons.GitBranchIcon, {
    width: 14,
    height: 14
  }), entry.sourceBranch), /*#__PURE__*/_react.default.createElement(_Icons.ArrowRightIcon, {
    width: 14,
    height: 14
  }), /*#__PURE__*/_react.default.createElement("span", {
    className: "hist-branch"
  }, /*#__PURE__*/_react.default.createElement(_Icons.GitBranchIcon, {
    width: 14,
    height: 14
  }), entry.targetBranch)), /*#__PURE__*/_react.default.createElement("span", {
    className: "hist-repo"
  }, /*#__PURE__*/_react.default.createElement(_Icons.GitRepositoryIcon, {
    width: 14,
    height: 14
  }), entry.repoFull)), [...entry.history].sort(function (a, b) {
    return a.minutesAgo - b.minutesAgo;
  }).map(function (ev, i) {
    return /*#__PURE__*/_react.default.createElement("div", {
      className: "hist-event",
      key: "".concat(ev.title, "-").concat(i)
    }, /*#__PURE__*/_react.default.createElement("span", {
      className: "hist-icon"
    }, /*#__PURE__*/_react.default.createElement(ev.icon, _extends({
      width: 22,
      height: 22
    }, iconColorProps(ev.icon)))), /*#__PURE__*/_react.default.createElement("div", {
      className: "hist-body"
    }, /*#__PURE__*/_react.default.createElement("div", {
      className: "hist-title"
    }, /*#__PURE__*/_react.default.createElement(_Typography.Body1, {
      weight: "medium"
    }, ev.title), ev.tone === "success" && /*#__PURE__*/_react.default.createElement("span", {
      className: "hist-status"
    }, /*#__PURE__*/_react.default.createElement(_Icons.CheckIcon, {
      width: 16,
      height: 16,
      fill: "var(--color-sucess-green)"
    })), ev.tone === "danger" && /*#__PURE__*/_react.default.createElement("span", {
      className: "sc-chip fail"
    }, /*#__PURE__*/_react.default.createElement(_Icons.CloseIcon, {
      width: 12,
      height: 12,
      fill: "var(--red-alert)"
    }), "Failed")), ev.detail && /*#__PURE__*/_react.default.createElement("span", {
      className: "hist-line"
    }, ev.detail), ev.author && /*#__PURE__*/_react.default.createElement("span", {
      className: "hist-line"
    }, ev.author)), /*#__PURE__*/_react.default.createElement("div", {
      className: "hist-meta"
    }, /*#__PURE__*/_react.default.createElement("span", {
      className: "hist-line"
    }, formatAgo(ev.minutesAgo))));
  }), !entry.pipelineSupported && /*#__PURE__*/_react.default.createElement("div", {
    className: "hist-note"
  }, /*#__PURE__*/_react.default.createElement(_Icons.InfoSmallIcon, {
    width: 15,
    height: 15
  }), /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
    color: "secondary"
  }, "No CI or deployment pipeline is configured for this repository.")))));
};

/* ================================================================== */
/* Source Code section — flat list, split open / completed             */
/* ================================================================== */

var StyledSourceCode = _styledComponents.default.div.withConfig({
  displayName: "SourceCodeSection__StyledSourceCode",
  componentId: "sc-rvqbh5-2"
})(["font-family:", ";margin:0 0 16px;padding-bottom:16px;border-bottom:1px solid var(--border-primary);", " .sc-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:4px;}.sc-completed-row{display:flex;align-items:center;margin-top:8px;padding-top:8px;border-top:1px solid var(--border-primary);}.sc-add{margin-top:8px;padding-top:12px;border-top:1px solid var(--border-primary);}.sc-add .c--add-to-list-btn svg{box-sizing:content-box;}.sc-item{padding:12px 0;}.sc-item + .sc-item{border-top:1px solid var(--border-primary);}.sc-row{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;}.sc-main{flex:1 1 0%;min-width:0;}.sc-name{display:flex;align-items:center;gap:8px;flex-wrap:nowrap;min-width:0;}.sc-lead{flex-shrink:0;display:inline-flex;color:var(--color-theme-600);}.sc-title{flex:0 1 auto;min-width:0;display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}.sc-title.strike{text-decoration:line-through;}.sc-title.strike-link{text-decoration:line-through;}.sc-title.strike-link:hover{text-decoration:none;}.sc-sigs{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:10px;font-size:12px;color:var(--color-theme-600);}.sc-sig{display:inline-flex;align-items:center;gap:4px;}.sc-closing{display:inline-flex;align-items:center;flex-shrink:0;cursor:default;}.sc-sha{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;}.sc-muted{color:var(--color-theme-600);}.sc-refs{display:inline-flex;align-items:center;gap:6px;}.sc-refs .ref-link{color:var(--color-primary);font-weight:500;}"], SANS, function (p) {
  return p.$flush && (0, _styledComponents.css)(["margin:0;padding-bottom:0;border-bottom:none;"]);
});

/* Element name — a link that opens the object in a new tab. Keeps the row's
   typography (inherits color + weight), turns primary on hover, link cursor. */
var TitleLink = _styledComponents.default.a.withConfig({
  displayName: "SourceCodeSection__TitleLink",
  componentId: "sc-rvqbh5-3"
})(["color:inherit;text-decoration:none;cursor:pointer;transition:color 200ms ease;&:hover{color:var(--color-primary);}"]);

/* Status label chip — the DS `Chip` styled to match the app's
   `SourceCodeStatusChip`: a "done" tone (primary text on a translucent-primary
   fill) and a "gone" tone (muted text on a bordered theme-200 fill). */
var CHIP_BASE_STYLE = {
  height: "1.25rem",
  paddingLeft: "0.5rem",
  paddingRight: "0.5rem",
  borderRadius: "0.375rem",
  gap: "3px",
  flexShrink: 0
};
var CHIP_DONE_STYLE = _objectSpread(_objectSpread({}, CHIP_BASE_STYLE), {}, {
  backgroundColor: "color-mix(in srgb, var(--color-primary) 15%, transparent)"
});
var CHIP_GONE_STYLE = _objectSpread(_objectSpread({}, CHIP_BASE_STYLE), {}, {
  backgroundColor: "var(--color-theme-200)",
  border: "1px solid var(--border-primary)"
});

/* Info tone — the default (blue) InfoBox recipe: blueSky tint + solid border. */
var CHIP_INFO_STYLE = _objectSpread(_objectSpread({}, CHIP_BASE_STYLE), {}, {
  backgroundColor: "".concat(_utils.colors.blueSky.color, "1A"),
  border: "1px solid ".concat(_utils.colors.blueSky.color)
});
var StatusChip = function StatusChip(_ref5) {
  var label = _ref5.label,
    tone = _ref5.tone,
    glyph = _ref5.glyph;
  return /*#__PURE__*/_react.default.createElement(_Chip.Chip, {
    label: label,
    startAdornment: glyph,
    color: tone === "done" ? "var(--color-primary)" : tone === "info" ? _utils.colors.blueSky.lighter : undefined,
    style: tone === "done" ? CHIP_DONE_STYLE : tone === "info" ? CHIP_INFO_STYLE : CHIP_GONE_STYLE,
    typographyProps: {
      variant: "Caption 1",
      weight: "bold",
      align: "center"
    }
  });
};

/* Contributor avatars — the app renders real user images through the DS
   `AvatarGroup` (`ContributorAvatars.jsx`). The mock feeds that same component
   initials avatars via `MockAvatar`, which honours AvatarGroup's cloneElement
   contract (it injects `size`, `alt` and `style` — the overlap margin + paper
   ring), so the grouping, overlap and "+N" overflow behave identically. */
var CONTRIBUTOR_NAMES = {
  DA: "Dragana A.",
  IS: "Ilija Studen",
  MK: "Marko K."
};
var MockAvatar = /*#__PURE__*/_react.default.forwardRef(function (_ref6, ref) {
  var _ref6$size = _ref6.size,
    size = _ref6$size === void 0 ? 20 : _ref6$size,
    bg = _ref6.bg,
    initials = _ref6.initials,
    alt = _ref6.alt,
    rest = _objectWithoutProperties(_ref6, _excluded);
  return (
    /*#__PURE__*/
    // `...rest` carries the props AvatarGroup and its Tooltip inject via
    // cloneElement — `style` (overlap margin + paper ring) and the hover handlers
    // (`onMouseOver` / `onMouseLeave`) — plus the forwarded `ref`, all of which
    // must reach the DOM node for the tooltip to open.
    _react.default.createElement(_RoundAvatar.RoundAvatar, _extends({
      ref: ref,
      $bg: bg,
      $size: size,
      $bordered: false
    }, rest), initials)
  );
});
MockAvatar.displayName = "MockAvatar";

/* The app removes AvatarGroup's default padding with `tw-p-0`; the mock does
   the same through a styled wrapper (`tw-` classes don't run in Storybook). */
var StyledAvatarGroup = (0, _styledComponents.default)(_AvatarGroup.AvatarGroup).withConfig({
  displayName: "SourceCodeSection__StyledAvatarGroup",
  componentId: "sc-rvqbh5-4"
})(["&&{padding:0;}"]);
var ContributorAvatars = function ContributorAvatars(_ref7) {
  var contributors = _ref7.contributors;
  return /*#__PURE__*/_react.default.createElement(StyledAvatarGroup, {
    limit: 4,
    size: 20,
    hasTooltip: true
  }, contributors.map(function (c) {
    var _CONTRIBUTOR_NAMES$c$;
    return /*#__PURE__*/_react.default.createElement(MockAvatar, {
      key: c.initials,
      bg: c.bg,
      initials: c.initials,
      alt: (_CONTRIBUTOR_NAMES$c$ = CONTRIBUTOR_NAMES[c.initials]) !== null && _CONTRIBUTOR_NAMES$c$ !== void 0 ? _CONTRIBUTOR_NAMES$c$ : c.initials
    });
  }));
};
var IssueRow = exports.IssueRow = function IssueRow(_ref8) {
  var issue = _ref8.issue;
  var closed = issue.state === "closed";
  return /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-row"
  }, /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-main"
  }, /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-name"
  }, /*#__PURE__*/_react.default.createElement("span", {
    className: "sc-lead",
    style: {
      color: closed ? "var(--color-primary)" : undefined
    }
  }, /*#__PURE__*/_react.default.createElement(IssueStateIcon, {
    closed: closed
  })), /*#__PURE__*/_react.default.createElement(_Typography.Body1, {
    weight: "medium",
    className: "sc-title"
  }, /*#__PURE__*/_react.default.createElement(TitleLink, {
    href: issueUrl(issue),
    target: "_blank",
    rel: "noopener noreferrer"
  }, issue.title)), closed && /*#__PURE__*/_react.default.createElement(StatusChip, {
    label: "Closed",
    tone: "done",
    glyph: /*#__PURE__*/_react.default.createElement(IssueStateIcon, {
      closed: true,
      size: 12
    })
  })), /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-sigs"
  }, /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, {
    title: "Repository: ".concat(issue.repoFull)
  }, /*#__PURE__*/_react.default.createElement("span", {
    className: "sc-sig"
  }, /*#__PURE__*/_react.default.createElement(_Icons.GitRepositoryIcon, {
    width: 14,
    height: 14
  }), issue.repo)), /*#__PURE__*/_react.default.createElement("span", {
    className: "sc-muted"
  }, issue.updatedLabel))));
};
var CodeStatusChip = function CodeStatusChip(_ref9) {
  var entry = _ref9.entry;
  if (entry.status === "merged") {
    return /*#__PURE__*/_react.default.createElement(StatusChip, {
      label: "Merged",
      tone: "done",
      glyph: /*#__PURE__*/_react.default.createElement(_Icons.GitPullRequestIcon, {
        width: 12,
        height: 12,
        fill: "var(--color-primary)"
      })
    });
  }
  if (entry.status === "deleted") {
    return /*#__PURE__*/_react.default.createElement(StatusChip, {
      label: "Deleted",
      tone: "gone",
      glyph: /*#__PURE__*/_react.default.createElement(_Icons.TrashIcon, {
        width: 12,
        height: 12,
        fill: "var(--color-theme-900)"
      })
    });
  }
  if (entry.status === "closed") {
    return /*#__PURE__*/_react.default.createElement(StatusChip, {
      label: "Closed",
      tone: "gone"
    });
  }
  // Open branches / PRs show no status label.
  return null;
};
var CodeRow = exports.CodeRow = function CodeRow(_ref0) {
  var entry = _ref0.entry,
    onOpenHistory = _ref0.onOpenHistory;
  var deleted = entry.status === "deleted";
  // A closed-without-merge PR is still a live link, but its name is struck
  // through to signal the dead-end; the strike lifts on hover so it reads as a
  // normal PR link.
  var closedPr = entry.kind === "pr" && entry.status === "closed";
  return /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-row"
  }, /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-main"
  }, /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-name"
  }, /*#__PURE__*/_react.default.createElement("span", {
    className: "sc-lead"
  }, entry.kind === "pr" ? /*#__PURE__*/_react.default.createElement(_Icons.GitPullRequestIcon, {
    width: 16,
    height: 16
  }) : /*#__PURE__*/_react.default.createElement(_Icons.GitBranchIcon, {
    width: 16,
    height: 16
  })), deleted ? /*#__PURE__*/_react.default.createElement(_Typography.Body1, {
    weight: "medium",
    className: "sc-title strike"
  }, entry.title) : /*#__PURE__*/_react.default.createElement(_Typography.Body1, {
    weight: "medium",
    className: closedPr ? "sc-title strike-link" : "sc-title"
  }, /*#__PURE__*/_react.default.createElement(TitleLink, {
    href: codeUrl(entry),
    target: "_blank",
    rel: "noopener noreferrer"
  }, entry.title)), /*#__PURE__*/_react.default.createElement(CodeStatusChip, {
    entry: entry
  }), entry.kind === "pr" && entry.status === "open" && entry.closing && /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, {
    title: "Marks the task as completed when this pull request is merged."
  }, /*#__PURE__*/_react.default.createElement("span", {
    className: "sc-closing"
  }, /*#__PURE__*/_react.default.createElement(StatusChip, {
    label: "Closing",
    tone: "info",
    glyph: /*#__PURE__*/_react.default.createElement(_Icons.CheckIcon, {
      width: 12,
      height: 12,
      fill: _utils.colors.blueSky.lighter
    })
  })))), /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-sigs"
  }, /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, {
    title: "Repository: ".concat(entry.repoFull)
  }, /*#__PURE__*/_react.default.createElement("span", {
    className: "sc-sig"
  }, /*#__PURE__*/_react.default.createElement(_Icons.GitRepositoryIcon, {
    width: 14,
    height: 14
  }), entry.repo)), /*#__PURE__*/_react.default.createElement(ContributorAvatars, {
    contributors: entry.contributors
  }), /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, {
    title: entry.commits.tip
  }, /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
    color: "tertiary",
    className: "sc-sig"
  }, /*#__PURE__*/_react.default.createElement(_Icons.GitCommitIcon, {
    width: 14,
    height: 14
  }), entry.commits.value)), /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, {
    title: "Head commit: ".concat(entry.headSha)
  }, /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
    color: "tertiary",
    className: "sc-sig sc-sha"
  }, entry.headSha.slice(0, 8))), entry.diff && /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, {
    title: entry.diff.tip
  }, /*#__PURE__*/_react.default.createElement("span", {
    className: "sc-sig sc-diff"
  }, /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
    color: "success"
  }, "+", entry.diff.add), /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
    color: "alert"
  }, "\u2212", entry.diff.del))), entry.comments && /*#__PURE__*/_react.default.createElement(_Tooltip.Tooltip, {
    title: entry.comments.tip
  }, /*#__PURE__*/_react.default.createElement(_Typography.Caption1, {
    color: "tertiary",
    className: "sc-sig"
  }, /*#__PURE__*/_react.default.createElement(_Icons.MessageSmallIcon, null), entry.comments.value)), /*#__PURE__*/_react.default.createElement("span", {
    className: "sc-muted"
  }, entry.updatedLabel))), /*#__PURE__*/_react.default.createElement(Spine, {
    items: entry.stages,
    onClick: onOpenHistory
  }));
};
var CompletedHeader = exports.CompletedHeader = function CompletedHeader(_ref1) {
  var expanded = _ref1.expanded,
    count = _ref1.count,
    onToggle = _ref1.onToggle;
  return /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-completed-row"
  }, /*#__PURE__*/_react.default.createElement(_Button.Button, {
    type: "button",
    variant: "text colored",
    onClick: onToggle,
    "aria-expanded": expanded,
    style: {
      marginLeft: -8
    }
  }, expanded ? "Hide completed elements" : "Show ".concat(count, " more completed elements")));
};
var SourceCodeSection = exports.SourceCodeSection = function SourceCodeSection(_ref10) {
  var _ref10$variant = _ref10.variant,
    variant = _ref10$variant === void 0 ? "mix" : _ref10$variant,
    issues = _ref10.issues,
    code = _ref10.code,
    _ref10$showHeader = _ref10.showHeader,
    showHeader = _ref10$showHeader === void 0 ? true : _ref10$showHeader,
    _ref10$showLink = _ref10.showLink,
    showLink = _ref10$showLink === void 0 ? true : _ref10$showLink,
    _ref10$flush = _ref10.flush,
    flush = _ref10$flush === void 0 ? false : _ref10$flush;
  var _useState = (0, _react.useState)(null),
    _useState2 = _slicedToArray(_useState, 2),
    openEntry = _useState2[0],
    setOpenEntry = _useState2[1];
  var _useState3 = (0, _react.useState)(false),
    _useState4 = _slicedToArray(_useState3, 2),
    completedExpanded = _useState4[0],
    setCompletedExpanded = _useState4[1];
  var _useState5 = (0, _react.useState)(false),
    _useState6 = _slicedToArray(_useState5, 2),
    linkOpen = _useState6[0],
    setLinkOpen = _useState6[1];
  var issuesData = issues !== null && issues !== void 0 ? issues : ISSUES;
  var codeData = code !== null && code !== void 0 ? code : CODE_ENTRIES;
  var openIssues = issuesData.filter(function (i) {
    return !issueCompleted(i);
  }).sort(byRecency);
  var openCode = codeData.filter(function (e) {
    return !codeCompleted(e);
  }).sort(byRecency);
  var completed = [...issuesData.filter(issueCompleted).map(function (issue) {
    return {
      key: issue.ref,
      updatedMinsAgo: issue.updatedMinsAgo,
      node: /*#__PURE__*/_react.default.createElement(IssueRow, {
        issue: issue
      })
    };
  }), ...codeData.filter(codeCompleted).map(function (entry) {
    return {
      key: "".concat(entry.repo, "-").concat(entry.title),
      updatedMinsAgo: entry.updatedMinsAgo,
      node: /*#__PURE__*/_react.default.createElement(CodeRow, {
        entry: entry,
        onOpenHistory: function onOpenHistory() {
          return setOpenEntry(entry);
        }
      })
    };
  })].sort(byRecency);
  var showOpen = variant === "mix" || variant === "open";
  var showCompleted = variant === "mix" || variant === "completed";
  // In the "completed" variant there is no collapsible header and everything is
  // shown; in "mix" the section is collapsed by default.
  var completedVisible = variant === "completed" ? true : completedExpanded;
  return /*#__PURE__*/_react.default.createElement(StyledSourceCode, {
    $flush: flush
  }, showHeader && /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-header"
  }, /*#__PURE__*/_react.default.createElement(_Typography.Body1, {
    weight: "bold"
  }, "Source Code"), /*#__PURE__*/_react.default.createElement(_LinkingCommandsButton.LinkingCommandsButton, null)), showOpen && openIssues.map(function (issue) {
    return /*#__PURE__*/_react.default.createElement("div", {
      className: "sc-item",
      key: issue.ref
    }, /*#__PURE__*/_react.default.createElement(IssueRow, {
      issue: issue
    }));
  }), showOpen && openCode.map(function (entry) {
    return /*#__PURE__*/_react.default.createElement("div", {
      className: "sc-item",
      key: "".concat(entry.repo, "-").concat(entry.title)
    }, /*#__PURE__*/_react.default.createElement(CodeRow, {
      entry: entry,
      onOpenHistory: function onOpenHistory() {
        return setOpenEntry(entry);
      }
    }));
  }), showCompleted && completedVisible && completed.map(function (c) {
    return /*#__PURE__*/_react.default.createElement("div", {
      className: "sc-item",
      key: c.key
    }, c.node);
  }), showCompleted && completed.length > 0 && variant === "mix" && /*#__PURE__*/_react.default.createElement(CompletedHeader, {
    expanded: completedExpanded,
    count: completed.length,
    onToggle: function onToggle() {
      return setCompletedExpanded(function (v) {
        return !v;
      });
    }
  }), showLink && /*#__PURE__*/_react.default.createElement("div", {
    className: "sc-add"
  }, /*#__PURE__*/_react.default.createElement(_AddToListButton.AddToListButton, {
    text: "Link Branch or Pull Request",
    style: {
      marginLeft: -4
    },
    onClick: function onClick() {
      return setLinkOpen(true);
    }
  })), /*#__PURE__*/_react.default.createElement(HistoryDialog, {
    entry: openEntry,
    onClose: function onClose() {
      return setOpenEntry(null);
    }
  }), /*#__PURE__*/_react.default.createElement(_LinkBranchOrPullRequestDialog.LinkBranchOrPullRequestDialog, {
    open: linkOpen,
    onClose: function onClose() {
      return setLinkOpen(false);
    }
  }));
};
//# sourceMappingURL=SourceCodeSection.js.map