diff --git a/components/common/editor/editor.css b/components/common/editor/editor.css index f49c51a9..be3d1997 100644 --- a/components/common/editor/editor.css +++ b/components/common/editor/editor.css @@ -145,3 +145,14 @@ color: var(--color-text-light-1) !important; } } + +/* GitHub's attach control leads with a paperclip; Dropzone renders the button, so draw it in CSS. */ +.page-content.repository.view.issue.github-conversation .comment.form .ui.dropzone .dz-button::before { + content: ""; + flex-shrink: 0; + width: 16px; + height: 16px; + background-color: currentcolor; + mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M12.212 3.02a1.753 1.753 0 0 0-2.478.003l-5.83 5.83a3 3 0 0 0-.88 2.127c0 .795.315 1.551.88 2.116.567.567 1.333.89 2.126.89.79 0 1.548-.321 2.116-.89l5.48-5.48a.75.75 0 0 1 1.061 1.06l-5.48 5.48a4.5 4.5 0 0 1-3.177 1.33c-1.2 0-2.345-.487-3.187-1.33a4.48 4.48 0 0 1-1.32-3.177c0-1.195.475-2.341 1.32-3.186l5.83-5.83a3.25 3.25 0 0 1 5.553 2.297c0 .863-.343 1.691-.953 2.301L7.439 12.39c-.375.377-.884.59-1.416.593a2 2 0 0 1-1.412-.593 1.99 1.99 0 0 1 0-2.828l5.48-5.48a.75.75 0 0 1 1.042.018.75.75 0 0 1 .018 1.042l-5.48 5.48a.49.49 0 0 0 0 .707.5.5 0 0 0 .352.154.5.5 0 0 0 .356-.154l5.833-5.827a1.755 1.755 0 0 0 0-2.481Z'/%3E%3C/svg%3E") + center / 16px no-repeat; +} diff --git a/components/repository/label/label.tmpl b/components/repository/label/label.tmpl new file mode 100644 index 00000000..fe0bd71d --- /dev/null +++ b/components/repository/label/label.tmpl @@ -0,0 +1,10 @@ +{{- /* An issue label whose colour reaches the theme as a variable, so its stylesheet can adapt it to light and dark +mode. Forgejo's RenderLabel writes the colours inline with !important, which no stylesheet can override. Scoped +labels keep Forgejo's two-part rendering. */ -}} +{{if .ExclusiveScope -}} + {{RenderLabel ctx .}} +{{- else -}} + {{- $description := .Description -}} + {{- if .IsArchived}}{{$description = print "(" (ctx.Locale.Tr "archived") ") " .Description}}{{end -}} +
{{RenderEmoji ctx .Name}}
+{{- end}} diff --git a/public/assets/js/diff-file-tree.js b/public/assets/js/diff-file-tree.js index 73bd9208..c1a3ca40 100644 --- a/public/assets/js/diff-file-tree.js +++ b/public/assets/js/diff-file-tree.js @@ -110,11 +110,6 @@ toggleAttribute(group, "data-tree-filtered", !visible); visit(group, `${path}/`, level + 1); } - if (!row.querySelector(".tree-directory-icon")) { - const icon = document.getElementById("diff-tree-icon-directory").content.firstElementChild.cloneNode(true); - icon.classList.add("tree-directory-icon"); - row.insertBefore(icon, row.querySelector("span")); - } // Reveal matching descendants when searching, including Vue's lazy subtrees. if (revealMatches && visible && row.getAttribute("aria-expanded") === "false") row.click(); } else if (row.matches(".item-file")) { @@ -127,18 +122,6 @@ setAttribute(row, "aria-level", level); setAttribute(row, "aria-selected", row.classList.contains("selected")); setAttribute(row, "tabindex", -1); - if (!row.querySelector(".tree-file-icon")) { - const kind = row.querySelector(".octicon-diff-added") - ? "added" - : row.querySelector(".octicon-diff-removed") - ? "removed" - : "diff"; - const icon = document.getElementById(`diff-tree-icon-${kind}`)?.content.firstElementChild.cloneNode(true); - if (icon) { - icon.classList.add("tree-file-icon"); - row.prepend(icon); - } - } } else if (row.matches(".diff-file-tree-items")) visit(row, prefix, level); } } diff --git a/public/assets/js/diff-view.js b/public/assets/js/diff-view.js index 5c8d7431..b9e09ece 100644 --- a/public/assets/js/diff-view.js +++ b/public/assets/js/diff-view.js @@ -178,10 +178,6 @@ }); const boxes = document.getElementById("diff-file-boxes"); function updateFoldLabels() { - // Forgejo's initial hunk labels omit the first @, while loaded excerpts include both. - for (const code of container.querySelectorAll(".tag-code .code-inner")) { - if (/^@ [+-]/.test(code.textContent)) code.prepend(document.createTextNode("@")); - } for (const box of boxes?.querySelectorAll(".diff-file-box") || []) { const expand = box.querySelector(".diff-expand-file"); if (expand) { diff --git a/public/assets/js/issue-conversation.js b/public/assets/js/issue-conversation.js index 4455f030..7c157e87 100644 --- a/public/assets/js/issue-conversation.js +++ b/public/assets/js/issue-conversation.js @@ -1,80 +1,14 @@ (() => { - const page = document.querySelector(".github-conversation"); - if (!page) return; - const form = page.querySelector(".comment.form"); - if (form && !form.querySelector(".comment-editor-heading")) { - const heading = document.createElement("h2"); - heading.className = "comment-editor-heading"; - heading.textContent = "Add a comment"; - form.prepend(heading); - } - if (form) { - const dropzone = form.querySelector(".dropzone"); - const icon = page.parentElement.querySelector("#conversation-upload-icon")?.content.firstElementChild; - if (dropzone && icon) { - const decorateUpload = () => { - const button = dropzone.querySelector(".dz-button"); - if (button && !button.querySelector("svg")) button.prepend(icon.cloneNode(true)); - }; - decorateUpload(); - new MutationObserver(decorateUpload).observe(dropzone, { childList: true, subtree: true }); - } - - const textarea = form.querySelector("textarea.markdown-text-editor"); - const submit = form.querySelector(".button-sequence > .primary.button"); - const files = form.querySelector(".dropzone .files"); - if (textarea && submit) { - const updateSubmit = () => { - submit.disabled = !textarea.value.trim() && !files?.children.length; - }; - textarea.addEventListener("input", updateSubmit); - if (files) new MutationObserver(updateSubmit).observe(files, { childList: true, subtree: true }); - updateSubmit(); - } - } - const first = page.querySelector(".comment.first"); - if (first && page.classList.contains("github-issue-conversation")) { - const header = first.querySelector(".comment-header-left .text"); - if (header) - for (const node of header.childNodes) - if (node.nodeType === Node.TEXT_NODE) node.textContent = node.textContent.replace(/commented/, "opened"); - } - // Place the existing reaction selector beside the body, preserving its native handlers. - for (const comment of page.querySelectorAll(".timeline-item.comment:not(.form)")) { - const reaction = comment.querySelector(".comment-header .select-reaction"); - const body = comment.querySelector(".comment-body"); - if (reaction && body) { - const footer = document.createElement("div"); - footer.className = "conversation-body-actions"; - reaction.classList.remove("right"); - footer.append(reaction); - body.append(footer); - } - } - const sidebar = page.querySelector(".issue-content-right"); - if (sidebar) { - // Keep Forgejo's controls and their sibling relationships together. - const groups = []; - let group = []; - for (const child of [...sidebar.children]) { - if (child.classList.contains("divider")) { - groups.push({ nodes: group, divider: child }); - group = []; - } else group.push(child); - } - if (group.length) groups.push({ nodes: group }); - const priority = group => { - if (group.nodes.some(n => n.matches(".select-assignees-modify, .assignees"))) return 0; - if (group.nodes.some(n => n.matches(".select-label, .labels"))) return 1; - if (group.nodes.some(n => n.matches(".select-project"))) return 2; - if (group.nodes.some(n => n.id === "milestone-section")) return 3; - if (group.nodes.some(n => n.matches(".depending"))) return 4; - if (group.nodes.some(n => n.matches(".select-branch"))) return 5; - if (group.nodes.some(n => n.matches(".watching"))) return 6; - if (group.nodes.some(n => n.matches("span.text") && /participant/i.test(n.textContent))) return 7; - return 8; - }; - groups.sort((a, b) => priority(a) - priority(b)); - for (const group of groups) sidebar.append(...group.nodes, ...(group.divider ? [group.divider] : [])); - } + // GitHub keeps Comment disabled until there is text or an attachment to send. + const form = document.querySelector(".github-conversation .comment.form"); + const textarea = form?.querySelector("textarea.markdown-text-editor"); + const submit = form?.querySelector(".button-sequence > .primary.button"); + if (!textarea || !submit) return; + const files = form.querySelector(".dropzone .files"); + const updateSubmit = () => { + submit.disabled = !textarea.value.trim() && !files?.children.length; + }; + textarea.addEventListener("input", updateSubmit); + if (files) new MutationObserver(updateSubmit).observe(files, { childList: true, subtree: true }); + updateSubmit(); })(); diff --git a/public/assets/js/issue-list.js b/public/assets/js/issue-list.js index fc19f7c1..906ff78a 100644 --- a/public/assets/js/issue-list.js +++ b/public/assets/js/issue-list.js @@ -1,75 +1,8 @@ (() => { - const page = document.querySelector(".github-issues, .github-pull-list"); - if (!page) return; - const isPullList = page.classList.contains("github-pull-list"); - const form = page.querySelector(".issue-list-search"); - const input = form?.querySelector('input[name="q"]'); - if (!input) return; - // The dashboard's milestone list reuses this layout and keeps its own translated placeholder. - if (!page.classList.contains("github-milestones")) { - input.setAttribute("aria-label", isPullList ? "Search pull requests" : "Search Issues"); - input.placeholder = isPullList ? "Search all pull requests" : "Search Issues"; - } - const toolbar = page.querySelector("#issue-filters"); - const filterRow = toolbar?.querySelector(".issue-list-toolbar-right"); - if (filterRow) { - filterRow.id = "issue-filter-controls"; - const toggle = document.createElement("button"); - toggle.type = "button"; - toggle.className = "theme-icon-button issue-mobile-filter-toggle"; - toggle.setAttribute("aria-label", "Filter options"); - toggle.setAttribute("aria-controls", filterRow.id); - toggle.setAttribute("aria-expanded", "false"); - toggle.textContent = "…"; - toolbar.append(toggle); - toggle.addEventListener("click", () => { - const open = toolbar.classList.toggle("issue-mobile-filters-open"); - toggle.setAttribute("aria-expanded", open); - }); - const typeFilter = filterRow.querySelector(".list-header-type"); - if (typeFilter) { - const all = [...typeFilter.querySelectorAll("a")].find(a => a.href.includes("type=all")); - if (all) { - const allStates = document.createElement("a"); - allStates.className = "item"; - allStates.textContent = "All states"; - allStates.href = toolbar.querySelector('[data-test-name="all-issue-count"]').href; - typeFilter.querySelector(".menu").append(allStates); - } - } - } - const decorateRows = () => { - for (const row of page.querySelectorAll("#issue-list > .flex-item")) { - const labels = row.querySelector(".labels-list"); - const main = row.querySelector(".flex-item-main"); - if (!isPullList && labels?.textContent.trim() && labels.parentElement !== main) main.append(labels); - } - }; - decorateRows(); - const issues = page.querySelector("#issue-list"); - if (issues) new MutationObserver(decorateRows).observe(issues, { childList: true, subtree: true }); - const empty = page.querySelector("#issue-list > .tw-text-center"); - if (empty) { - empty.classList.add("theme-empty", "theme-empty-compact"); - if (isPullList) empty.querySelector("h3").textContent = "No pull requests matched your search"; - const icon = page.querySelector('[data-test-name="open-issue-count"] svg')?.cloneNode(true); - if (icon) { - icon.setAttribute("width", "24"); - icon.setAttribute("height", "24"); - empty.prepend(icon); - } - } - const filters = page.querySelector("#issue-filters"); - if (filters) { - for (const anchor of filters.querySelectorAll(".switch > a")) { - const text = [...anchor.childNodes].find(node => node.nodeType === Node.TEXT_NODE && node.textContent.trim()); - const match = text?.textContent.trim().match(/^([\d.,\s]+)\s+(.+)$/); - if (!match) continue; - text.textContent = match[2]; - const badge = document.createElement("span"); - badge.className = "theme-counter issue-state-count"; - badge.textContent = match[1].trim(); - anchor.append(badge); - } - } + const toolbar = document.querySelector("#issue-filters"); + const toggle = toolbar?.querySelector(".issue-mobile-filter-toggle"); + toggle?.addEventListener("click", () => { + const open = toolbar.classList.toggle("issue-mobile-filters-open"); + toggle.setAttribute("aria-expanded", open); + }); })(); diff --git a/public/assets/js/pull-review.js b/public/assets/js/pull-review.js index 94404b0c..c050d5ac 100644 --- a/public/assets/js/pull-review.js +++ b/public/assets/js/pull-review.js @@ -1,42 +1,16 @@ (() => { - const decorate = () => { - const box = document.querySelector(".github-pull-review .timeline-item.merge"); - const section = box?.querySelector(".merge-section"); - const form = section?.querySelector(":scope > #pull-request-merge-form"); - if (!form) return; - const state = window.config?.pageData?.pullRequestMergeForm; - const status = section.querySelector(":scope > .item"); - const check = status?.querySelector(":scope > .octicon-check"); - if (check && state?.canMergeNow && state?.allOverridableChecksOk) { - box.classList.add("merge-ready"); - status.classList.add("pull-merge-status"); - const content = document.createElement("div"); - const title = document.createElement("h3"); - for (const node of [...status.childNodes]) if (node !== check) title.append(node); - content.append(title); - const note = status.nextElementSibling; - if (note?.matches(".item:has(> .octicon-unlock, > .octicon-lock)")) { - note.classList.add("pull-merge-note"); - content.append(note); - } - status.append(content); - } - const instructions = section.querySelector(":scope > details.collapsible"); - const actions = document.createElement("div"); - actions.className = "pull-merge-actions"; - actions.append(form); - if (instructions) actions.append(instructions); - section.append(actions); - // Forgejo colours the collapsed button red whenever checks are unmet, even when the action - // only schedules the merge. A label longer than the plain merge action is a scheduled merge. - const plain = (state?.mergeStyles ?? []).map(style => style.textDoMerge?.trim()); - const sync = () => { - const label = form.querySelector(".merge-button .button-text")?.textContent.replace(/\s+/g, " ").trim(); - actions.classList.toggle("merge-scheduled", Boolean(label) && !plain.includes(label)); - }; - sync(); - new MutationObserver(sync).observe(form, { childList: true, subtree: true, characterData: true }); + const actions = document.querySelector(".github-pull-review .merge-section > .pull-merge-actions"); + const form = actions?.querySelector(":scope > #pull-request-merge-form"); + if (!form) return; + // Forgejo colours the collapsed button red whenever checks are unmet, even when the action + // only schedules the merge. A label longer than the plain merge action is a scheduled merge. + const plain = (window.config?.pageData?.pullRequestMergeForm?.mergeStyles ?? []).map(style => + style.textDoMerge?.trim() + ); + const sync = () => { + const label = form.querySelector(".merge-button .button-text")?.textContent.replace(/\s+/g, " ").trim(); + actions.classList.toggle("merge-scheduled", Boolean(label) && !plain.includes(label)); }; - if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", decorate, { once: true }); - else decorate(); + sync(); + new MutationObserver(sync).observe(form, { childList: true, subtree: true, characterData: true }); })(); diff --git a/public/assets/js/repo-releases.js b/public/assets/js/repo-releases.js index 4004777a..70252a7c 100644 --- a/public/assets/js/repo-releases.js +++ b/public/assets/js/repo-releases.js @@ -16,17 +16,6 @@ for (const digest of document.querySelectorAll(".github-release-digest[data-dige }) .catch(() => digest.remove()); } -for (const status of document.querySelectorAll('a[data-tippy="commit-statuses"]')) { - const icon = status.querySelector("svg"); - const label = icon?.classList.contains("yellow") - ? "Checks pending" - : icon?.classList.contains("green") - ? "Checks passed" - : icon?.classList.contains("red") - ? "Checks failed" - : "Checks"; - status.setAttribute("aria-label", label); -} const releaseMenu = document.querySelector(".github-release-mobile-toc"); releaseMenu?.addEventListener("click", event => { if (event.target.closest("a")) releaseMenu.open = false; diff --git a/public/assets/js/repository-labels.js b/public/assets/js/repository-labels.js deleted file mode 100644 index a426394a..00000000 --- a/public/assets/js/repository-labels.js +++ /dev/null @@ -1,38 +0,0 @@ -(() => { - // Forgejo renders label colors inline. Keep their source colors as variables so - // one component can adapt them to the active light/dark theme, including labels - // replaced by native metadata controls or timeline updates. - const selector = ".labels-list .ui.label, .ui.labels .ui.label"; - function decorate(label) { - const color = label.style.backgroundColor; - if (!color || color.startsWith("var(")) return; - const channels = color.match(/[\d.]+/g)?.map(Number); - if (!channels || channels.length < 3) return; - const [red, green, blue] = channels; - const perceived = (red * 0.2126 + green * 0.7152 + blue * 0.0722) / 255; - label.style.setProperty("--repository-label-color", color); - if (label.style.color && !label.style.color.startsWith("var(")) - label.style.setProperty("--repository-label-foreground", label.style.color); - label.style.setProperty("--repository-label-lighten", String(Math.max(0, (0.6 - perceived) * 100))); - label.style.setProperty( - "--repository-label-light-border", - String(Math.max(0, Math.min(1, (perceived - 0.96) * 100))) - ); - label.classList.add("repository-label"); - label.style.setProperty("background-color", "var(--repository-label-background)", "important"); - label.style.setProperty("color", "var(--repository-label-text)", "important"); - } - function scan(node) { - if (!(node instanceof Element)) return; - if (node.matches(selector)) decorate(node); - for (const label of node.querySelectorAll(selector)) decorate(label); - } - scan(document.body); - new MutationObserver(records => { - for (const record of records) { - if (record.type === "attributes") { - if (record.target.matches(selector)) decorate(record.target); - } else for (const node of record.addedNodes) scan(node); - } - }).observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["style"] }); -})(); diff --git a/styles/components/file_tree.ts b/styles/components/file_tree.ts index ea8f0e85..4e43b4a4 100644 --- a/styles/components/file_tree.ts +++ b/styles/components/file_tree.ts @@ -101,6 +101,43 @@ export default css` order: -1; flex: 0 0 16px; } + /* Forgejo renders the diff tree in Vue, so its GitHub icons are drawn here instead of inserted into its rows. */ + #diff-file-tree .item-directory::before, + #diff-file-tree .item-file::before { + content: ""; + flex: 0 0 16px; + width: 16px; + height: 16px; + background-color: currentcolor; + mask: var(--diff-tree-icon) center / 16px no-repeat; + } + #diff-file-tree .item-directory > svg:first-child { + order: -1; + } + #diff-file-tree .item-directory::before { + --diff-tree-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M.513 1.513A1.75 1.75 0 0 1 1.75 1h3.5c.55 0 1.07.26 1.4.7l.9 1.2a.25.25 0 0 0 .2.1H13a1 1 0 0 1 1 1v.5H2.75a.75.75 0 0 0 0 1.5h11.978a1 1 0 0 1 .994 1.117L15 13.25A1.75 1.75 0 0 1 13.25 15H1.75A1.75 1.75 0 0 1 0 13.25V2.75c0-.464.184-.91.513-1.237'/%3E%3C/svg%3E"); + color: ${themeVars.color.text.light.num1}; + } + /* Vue swaps the chevron with the folder's state; collapsed folders show its closed folder icon instead. */ + #diff-file-tree .item-directory:has(> .octicon-chevron-right)::before { + display: none; + } + #diff-file-tree .item-directory:has(> .octicon-chevron-right) > svg:nth-child(2) { + display: block; + color: ${themeVars.color.text.light.num1} !important; + } + #diff-file-tree .item-file::before { + --diff-tree-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25m-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75'/%3E%3C/svg%3E"); + order: -1; + } + #diff-file-tree .item-file:has(.octicon-diff-added)::before { + --diff-tree-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073Zm4.48 3.758a.75.75 0 0 1 .755.745l.01 1.497h1.497a.75.75 0 0 1 0 1.5H9v1.507a.75.75 0 0 1-1.5 0V9.005l-1.502.01a.75.75 0 0 1-.01-1.5l1.507-.01-.01-1.492a.75.75 0 0 1 .745-.755'/%3E%3C/svg%3E"); + color: ${themeVars.color.green.self}; + } + #diff-file-tree .item-file:has(.octicon-diff-removed)::before { + --diff-tree-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073Zm4.5 6h2.242a.75.75 0 0 1 0 1.5h-2.24l-2.254.015a.75.75 0 0 1-.01-1.5Z'/%3E%3C/svg%3E"); + color: ${themeVars.color.red.self}; + } .repository .file-tree [data-tree-filtered] { display: none !important; } diff --git a/styles/components/issues/issue_conversation.ts b/styles/components/issues/issue_conversation.ts index 9a913b1c..76c70bad 100644 --- a/styles/components/issues/issue_conversation.ts +++ b/styles/components/issues/issue_conversation.ts @@ -317,6 +317,11 @@ export default css` text-decoration: none !important; } } + /* The issue's "opened … by " sentence comes from Forgejo's translation, so its author link has no classes. */ + & .comment.first .comment-header-left > .text > a:not(.author, :has(relative-time)) { + color: ${themeVars.color.text.self}; + font-weight: 600; + } & .comment-header .role-label { border: 1px solid ${themeVars.color.light.border}; border-radius: 20px; diff --git a/styles/components/issues/pull_review.ts b/styles/components/issues/pull_review.ts index 06dddd9a..6dc66f6c 100644 --- a/styles/components/issues/pull_review.ts +++ b/styles/components/issues/pull_review.ts @@ -333,10 +333,10 @@ export default css` height: 24px; } } - &.merge-ready > .timeline-avatar { + &:has(.pull-merge-status) > .timeline-avatar { background: ${themeVars.github.bgColor.success.emphasis}; } - &.merge-ready > .content { + &:has(.pull-merge-status) > .content { border-color: ${themeVars.github.bgColor.success.emphasis}; } /* GitHub keeps the badge and border neutral for blocked, conflicting, draft and closed pull requests. */ diff --git a/styles/public/label/repository_issue_label.ts b/styles/public/label/repository_issue_label.ts index 69af2f38..9d57b865 100644 --- a/styles/public/label/repository_issue_label.ts +++ b/styles/public/label/repository_issue_label.ts @@ -1,8 +1,14 @@ import { css } from "@lutinglt/gitea-github-theme/core"; +// GitHub's issue label colours. The label template passes the source colour and Forgejo's contrast text colour as +// variables. GitHub lightens dark labels in dark mode by how far their perceived lightness falls below 60%; the +// luma variant carries that lightness in its alpha channel so one relative colour can use it as a number. export default css` - .ui.label.repository-label { - --repository-label-dark-text: hsl(from var(--repository-label-color) h s calc(l + var(--repository-label-lighten))); + .ui.ui.label.repository-label { + --repository-label-luma: rgb( + from var(--repository-label-color) r g b / calc((r * 0.2126 + g * 0.7152 + b * 0.0722) / 255) + ); + --repository-label-dark-text: hsl(from var(--repository-label-luma) h s calc(l + max(0, (0.6 - alpha) * 100)) / 1); --repository-label-background: light-dark( var(--repository-label-color), rgb(from var(--repository-label-color) r g b / 0.18) @@ -10,9 +16,11 @@ export default css` --repository-label-text: light-dark(var(--repository-label-foreground), var(--repository-label-dark-text)); border: 1px solid light-dark( - hsl(from var(--repository-label-color) h s calc(l - 25) / var(--repository-label-light-border)), + hsl(from var(--repository-label-luma) h s calc(l - 25) / clamp(0, (alpha - 0.96) * 100, 1)), hsl(from var(--repository-label-dark-text) h s l / 0.3) ); + background-color: var(--repository-label-background) !important; + color: var(--repository-label-text) !important; font-size: 12px; font-weight: 500; line-height: 18px; diff --git a/templates/repo/commit_statuses.tmpl b/templates/repo/commit_statuses.tmpl new file mode 100644 index 00000000..75ece564 --- /dev/null +++ b/templates/repo/commit_statuses.tmpl @@ -0,0 +1,19 @@ +{{if .Statuses}} + {{if and (eq (len .Statuses) 1) .Status.TargetURL}} + {{$label := ""}} + {{if .StatusLabel}} + {{/* GitHub names the overall result; Forgejo's merge box has the same sentences. */}} + {{if eq .Status.State "pending"}}{{$label = ctx.Locale.Tr "repo.pulls.status_checking"}}{{else if eq .Status.State "success"}}{{$label = ctx.Locale.Tr "repo.pulls.status_checks_success"}}{{else if eq .Status.State "warning"}}{{$label = ctx.Locale.Tr "repo.pulls.status_checks_warning"}}{{else if eq .Status.State "failure"}}{{$label = ctx.Locale.Tr "repo.pulls.status_checks_failure"}}{{else if eq .Status.State "error"}}{{$label = ctx.Locale.Tr "repo.pulls.status_checks_error"}}{{end}} + {{end}} + + {{template "repo/commit_status" .Status}} + + {{else}} + + {{template "repo/commit_status" .Status}} + + {{end}} +
+ {{template "repo/pulls/status" (dict "CommitStatuses" .Statuses "CommitStatus" .Status)}} +
+{{end}} diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 1c05f077..64b50abc 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -108,10 +108,6 @@
- - - - diff --git a/templates/repo/diff/section_split.tmpl b/templates/repo/diff/section_split.tmpl new file mode 100644 index 00000000..cebdf8d1 --- /dev/null +++ b/templates/repo/diff/section_split.tmpl @@ -0,0 +1,156 @@ +{{$file := .file}} +{{$blobExcerptRepoLink := or $.root.CommitRepoLink $.root.RepoLink}} + + + + + + + + + + +{{range $j, $section := $file.Sections}} + {{range $k, $line := $section.Lines}} + {{$hasmatch := ne $line.Match -1}} + {{if or (ne .GetType 2) (not $hasmatch)}} + + {{if eq .GetType 4}} + +
+ {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} + + {{end}} + {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} + + {{end}} + {{if eq $line.GetExpandDirection 2}} + + {{end}} +
+ {{$inlineDiff := $section.GetComputedInlineDiffFor $line ctx.Locale}} + {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} + {{/* + */}}{{/* Forgejo's inline diff drops the first character of a hunk header as if it were the +/- marker. */}}{{template "repo/diff/section_code" dict "diff" (dict "Content" $line.Content "EscapeStatus" $inlineDiff.EscapeStatus)}}{{/* + */}} + {{else if and (eq .GetType 3) $hasmatch}}{{/* DEL */}} + {{$match := index $section.Lines $line.Match}} + {{- $leftDiff := ""}}{{if $line.LeftIdx}}{{$leftDiff = $section.GetComputedInlineDiffFor $line ctx.Locale}}{{end}} + {{- $rightDiff := ""}}{{if $match.RightIdx}}{{$rightDiff = $section.GetComputedInlineDiffFor $match ctx.Locale}}{{end}} + + {{if $line.LeftIdx}}{{if $leftDiff.EscapeStatus.Escaped}}{{end}}{{end}} + + {{/* + */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles}}{{/* + */}}{{/* + */}}{{end}}{{/* + */}}{{if $line.LeftIdx}}{{/* + */}}{{template "repo/diff/section_code" dict "diff" $leftDiff}}{{/* + */}}{{else}}{{/* + */}}{{/* + */}}{{end}}{{/* + */}} + + {{if $match.RightIdx}}{{if $rightDiff.EscapeStatus.Escaped}}{{end}}{{end}} + {{if $match.RightIdx}}{{end}} + {{/* + */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles}}{{/* + */}}{{/* + */}}{{end}}{{/* + */}}{{if $match.RightIdx}}{{/* + */}}{{template "repo/diff/section_code" dict "diff" $rightDiff}}{{/* + */}}{{else}}{{/* + */}}{{/* + */}}{{end}}{{/* + */}} + {{else}} + {{$inlineDiff := $section.GetComputedInlineDiffFor $line ctx.Locale}} + + {{if $line.LeftIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}{{end}}{{end}} + {{if $line.LeftIdx}}{{end}} + {{/* + */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 2))}}{{/* + */}}{{/* + */}}{{end}}{{/* + */}}{{if $line.LeftIdx}}{{/* + */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{/* + */}}{{else}}{{/* + */}}{{/* + */}}{{end}}{{/* + */}} + + {{if $line.RightIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}{{end}}{{end}} + {{if $line.RightIdx}}{{end}} + {{/* + */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 3))}}{{/* + */}}{{/* + */}}{{end}}{{/* + */}}{{if $line.RightIdx}}{{/* + */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{/* + */}}{{else}}{{/* + */}}{{/* + */}}{{end}}{{/* + */}} + {{end}} + + {{if and (eq .GetType 3) $hasmatch}} + {{$match := index $section.Lines $line.Match}} + {{if or $line.Conversations $match.Conversations}} + + + {{if $line.Conversations}} + {{if eq $line.GetCommentSide "previous"}} + {{template "repo/diff/conversations" dict "." $.root "conversations" $line.Conversations}} + {{end}} + {{end}} + {{if $match.Conversations}} + {{if eq $match.GetCommentSide "previous"}} + {{template "repo/diff/conversations" dict "." $.root "conversations" $match.Conversations}} + {{end}} + {{end}} + + + {{if $line.Conversations}} + {{if eq $line.GetCommentSide "proposed"}} + {{template "repo/diff/conversations" dict "." $.root "conversations" $line.Conversations}} + {{end}} + {{end}} + {{if $match.Conversations}} + {{if eq $match.GetCommentSide "proposed"}} + {{template "repo/diff/conversations" dict "." $.root "conversations" $match.Conversations}} + {{end}} + {{end}} + + + {{end}} + {{else if $line.Conversations}} + + + {{if eq $line.GetCommentSide "previous"}} + {{template "repo/diff/conversations" dict "." $.root "conversations" $line.Conversations}} + {{end}} + + + {{if eq $line.GetCommentSide "proposed"}} + {{template "repo/diff/conversations" dict "." $.root "conversations" $line.Conversations}} + {{end}} + + + {{end}} + {{end}} + {{end}} +{{end}} diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl new file mode 100644 index 00000000..f82cfb73 --- /dev/null +++ b/templates/repo/diff/section_unified.tmpl @@ -0,0 +1,72 @@ +{{$file := .file}} +{{$blobExcerptRepoLink := or $.root.CommitRepoLink $.root.RepoLink}} + + + + + + + +{{range $j, $section := $file.Sections}} + {{range $k, $line := $section.Lines}} + + {{if eq .GetType 4}} + {{if $.root.AfterCommitID}} + +
+ {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} + + {{end}} + {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4)}} + + {{end}} + {{if eq $line.GetExpandDirection 2}} + + {{end}} +
+ + {{else}} + {{/* for code file preview page or comment diffs on pull comment pages, do not show the expansion arrows */}} + + {{end}} + {{else}} + + + {{end}} + {{$inlineDiff := $section.GetComputedInlineDiffFor $line ctx.Locale -}} + + {{- if $inlineDiff.EscapeStatus.Escaped -}} + + {{- end -}} + + + {{if eq .GetType 4}} + {{/* + */}}{{/* Forgejo's inline diff drops the first character of a hunk header as if it were the +/- marker. */}}{{template "repo/diff/section_code" dict "diff" (dict "Content" $line.Content "EscapeStatus" $inlineDiff.EscapeStatus)}}{{/* + */}} + {{else}} + {{/* + */}}{{if and $.root.SignedUserID $.root.PageIsPullFiles}}{{/* + */}}{{/* + */}}{{end}}{{/* + */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{/* + */}} + {{end}} + + {{if $line.Conversations}} + + + {{template "repo/diff/conversations" dict "." $.root "conversations" $line.Conversations}} + + + {{end}} + {{end}} +{{end}} diff --git a/templates/repo/global_header.tmpl b/templates/repo/global_header.tmpl index 15b5e27e..88107755 100644 --- a/templates/repo/global_header.tmpl +++ b/templates/repo/global_header.tmpl @@ -118,4 +118,3 @@
- diff --git a/templates/repo/home_sidebar_bottom.tmpl b/templates/repo/home_sidebar_bottom.tmpl index 80f20bae..1ba1798a 100644 --- a/templates/repo/home_sidebar_bottom.tmpl +++ b/templates/repo/home_sidebar_bottom.tmpl @@ -15,7 +15,7 @@ Loading latest release… Latest - + + {{CountFmt .NumReleases}} releases diff --git a/templates/repo/issue/openclose.tmpl b/templates/repo/issue/openclose.tmpl new file mode 100644 index 00000000..daa396a9 --- /dev/null +++ b/templates/repo/issue/openclose.tmpl @@ -0,0 +1,22 @@ +
+ + {{if .PageIsMilestones}} + {{svg "octicon-milestone" 16}} + {{else if .PageIsPullList}} + {{svg "octicon-git-pull-request" 16}} + {{else}} + {{svg "octicon-issue-opened" 16}} + {{end}} + {{if $.themeList}}{{ctx.Locale.Tr "repo.issues.open_title"}} {{ctx.Locale.PrettyNumber .OpenCount}}{{else}}{{ctx.Locale.PrettyNumber .OpenCount}} {{ctx.Locale.Tr "repo.issues.open_title"}}{{end}} + + + {{svg "octicon-issue-closed" 16}} + {{if $.themeList}}{{ctx.Locale.Tr "repo.issues.closed_title"}} {{ctx.Locale.PrettyNumber .ClosedCount}}{{else}}{{ctx.Locale.PrettyNumber .ClosedCount}} {{ctx.Locale.Tr "repo.issues.closed_title"}}{{end}} + + {{if not .PageIsMilestones}} + + {{svg "octicon-eye" 16}} + {{if $.themeList}}{{ctx.Locale.Tr "repo.issues.all_title"}} {{ctx.Locale.PrettyNumber (.AllCount)}}{{else}}{{ctx.Locale.PrettyNumber (.AllCount)}} {{ctx.Locale.Tr "repo.issues.all_title"}}{{end}} + + {{end}} +
diff --git a/templates/repo/issue/view.tmpl b/templates/repo/issue/view.tmpl index 09886191..a5f292bf 100644 --- a/templates/repo/issue/view.tmpl +++ b/templates/repo/issue/view.tmpl @@ -8,7 +8,6 @@ {{template "repo/issue/view_content" .}} - {{if .Issue.IsPull}}{{end}} {{template "base/footer" .}} diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl new file mode 100644 index 00000000..526c45a1 --- /dev/null +++ b/templates/repo/issue/view_content.tmpl @@ -0,0 +1,191 @@ +
+ + + + + + + + {{$createdStr:= DateUtils.TimeSince .Issue.CreatedUnix}} +
+
+
+ {{if .Issue.OriginalAuthor}} + + {{ctx.AvatarUtils.Avatar nil 40}} + + {{else}} + + {{end}} +
+
+
+ {{if .Issue.OriginalAuthor}} + + {{svg (MigrationIcon .Repository.GetOriginalURLHostname)}} + {{.Issue.OriginalAuthor}} + + + {{ctx.Locale.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr}} + + + {{if .Repository.OriginalURL}} ({{ctx.Locale.Tr "repo.migrated_from" .Repository.OriginalURL .Repository.GetOriginalURLHostname}}){{end}} + + {{else}} + + {{ctx.AvatarUtils.Avatar .Issue.Poster 24}} + + + {{if .Issue.IsPull}} + {{template "shared/user/authorlink" .Issue.Poster}} + {{ctx.Locale.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr}} + {{else}} + {{/* GitHub says an issue was opened; Forgejo's translation places the author itself. */}} + {{ctx.Locale.Tr "repo.issues.opened_by" (HTMLFormat `%s` .Issue.HashTag $createdStr) .Issue.Poster.HomeLink .Issue.Poster.GetDisplayName}} + {{end}} + + {{end}} +
+
+ {{template "repo/issue/view_content/show_role" dict "ShowRole" .Issue.ShowRole "IgnorePoster" true "IsPull" .Issue.IsPull}} + {{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" .Issue "delete" false "issue" true "diff" false "IsCommentPoster" $.IsIssuePoster}} +
+
+
+
+ {{if .Issue.RenderedContent}} + {{.Issue.RenderedContent}} + {{else}} + {{ctx.Locale.Tr "repo.issues.no_content"}} + {{end}} +
+
{{.Issue.Content}}
+
+ {{if .Issue.Attachments}} + {{template "repo/issue/view_content/attachments" dict "Attachments" .Issue.Attachments "RenderedContent" .Issue.RenderedContent}} + {{end}} + {{if not $.Repository.IsArchived}} + {{template "repo/issue/view_content/body_actions" dict "ctxData" $ "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index)}} + {{end}} +
+ {{$reactions := .Issue.Reactions.GroupByType}} + {{if $reactions}} + {{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) "Reactions" $reactions}} + {{end}} +
+
+ + {{template "repo/issue/view_content/comments" .}} +
+ + {{if and .Issue.IsPull (not $.Repository.IsArchived)}} + {{template "repo/issue/view_content/pull".}} + {{end}} + + {{if .Repository.IsArchived}} +
+ {{ctx.Locale.Tr "repo.archive.nocomment"}} +
+ {{else if .IsBlocked}} +
+ {{ctx.Locale.Tr "repo.comment.blocked_by_user"}} +
+ {{else if and .Issue.IsLocked (not (or .IsRepoAdmin .HasIssuesOrPullsWritePermission))}} +
+ {{ctx.Locale.Tr "discussion.locked"}} +
+ {{else if .IsSigned}} +
+

Add a comment

+ + {{ctx.AvatarUtils.Avatar .SignedUser 40}} + +
+
+ {{template "repo/issue/comment_tab" .}} + +
+
+
+ {{else}} {{/* not .IsSigned */}} +
+ {{ctx.Locale.Tr "repo.issues.sign_in_require_desc" .SignInLink}} +
+ {{end}} +
+
+ + {{template "repo/issue/view_content/sidebar" .}} +
+ + + +{{template "repo/issue/view_content/reference_issue_dialog" .}} + +
+ {{ctx.Locale.Tr "repo.issues.no_content"}} +
+ + diff --git a/templates/repo/issue/view_content/add_reaction.tmpl b/templates/repo/issue/view_content/add_reaction.tmpl new file mode 100644 index 00000000..576d6452 --- /dev/null +++ b/templates/repo/issue/view_content/add_reaction.tmpl @@ -0,0 +1,12 @@ +{{if .ctxData.IsSigned}} + +{{end}} diff --git a/templates/repo/issue/view_content/body_actions.tmpl b/templates/repo/issue/view_content/body_actions.tmpl new file mode 100644 index 00000000..55e937e7 --- /dev/null +++ b/templates/repo/issue/view_content/body_actions.tmpl @@ -0,0 +1,6 @@ +{{/* GitHub puts the reaction picker below the comment body rather than in its header. */}} +{{if .ctxData.IsSigned}} +
+ {{template "repo/issue/view_content/add_reaction" dict "ctxData" .ctxData "ActionURL" .ActionURL "Footer" true}} +
+{{end}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl new file mode 100644 index 00000000..302099ad --- /dev/null +++ b/templates/repo/issue/view_content/comments.tmpl @@ -0,0 +1,773 @@ +{{template "base/alert"}} +{{range .Issue.Comments}} + {{if call $.ShouldShowCommentType .Type}} + {{$createdStr := HTMLFormat `%s` .EventTag .HashTag (DateUtils.TimeSince .CreatedUnix)}} + + + {{if eq .Type 0}} +
+ {{if .OriginalAuthor}} + + {{ctx.AvatarUtils.Avatar nil 40}} + + {{else}} + + {{ctx.AvatarUtils.Avatar .Poster 40}} + + {{end}} +
+
+
+ {{if .OriginalAuthor}} + + {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} + {{.OriginalAuthor}} + + + {{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdStr}} {{if $.Repository.OriginalURL}} + + + ({{ctx.Locale.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname}}){{end}} + + {{else}} + {{if gt .Poster.ID 0}} + + {{ctx.AvatarUtils.Avatar .Poster 24}} + + {{end}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdStr}} + + {{end}} +
+
+ {{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole "IsPull" .Issue.IsPull}} + {{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" . "delete" true "issue" true "diff" false "IsCommentPoster" (and $.IsSigned (eq $.SignedUserID .PosterID))}} +
+
+
+
+ {{if .RenderedContent}} + {{.RenderedContent}} + {{else}} + {{ctx.Locale.Tr "repo.issues.no_content"}} + {{end}} +
+
{{.Content}}
+
+ {{if .Attachments}} + {{template "repo/issue/view_content/attachments" dict "Attachments" .Attachments "RenderedContent" .RenderedContent}} + {{end}} + {{if not $.Repository.IsArchived}} + {{template "repo/issue/view_content/body_actions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} + {{end}} +
+ {{$reactions := .Reactions.GroupByType}} + {{if $reactions}} + {{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} + {{end}} +
+
+ {{else if eq .Type 1}} +
+ {{svg "octicon-dot-fill"}} + {{if not .OriginalAuthor}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + {{end}} + + {{template "repo/issue/view_content/comments_authorlink" dict "ctxData" $ "comment" .}} + {{if .Issue.IsPull}} + {{ctx.Locale.Tr "repo.pulls.reopened_at" $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.reopened_at" $createdStr}} + {{end}} + +
+ {{else if eq .Type 2}} +
+ {{svg "octicon-circle-slash"}} + {{if not .OriginalAuthor}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + {{end}} + + {{template "repo/issue/view_content/comments_authorlink" dict "ctxData" $ "comment" .}} + {{if .Issue.IsPull}} + {{ctx.Locale.Tr "repo.pulls.closed_at" $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.closed_at" $createdStr}} + {{end}} + +
+ {{else if eq .Type 28}} +
+ {{svg "octicon-git-merge"}} + {{if not .OriginalAuthor}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + {{end}} + + {{template "repo/issue/view_content/comments_authorlink" dict "ctxData" $ "comment" .}} + {{$link := printf "%s/commit/%s" $.Repository.Link ($.Issue.PullRequest.MergedCommitID|PathEscape)}} + {{if eq $.Issue.PullRequest.Status 3}} + {{ctx.Locale.Tr "repo.issues.comment_manually_pull_merged_at" (HTMLFormat `%[2]s` $link (ShortSha $.Issue.PullRequest.MergedCommitID)) (HTMLFormat "%[1]s" $.BaseTarget) $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.comment_pull_merged_at" (HTMLFormat `%[2]s` $link (ShortSha $.Issue.PullRequest.MergedCommitID)) (HTMLFormat "%[1]s" $.BaseTarget) $createdStr}} + {{end}} + +
+ {{else if eq .Type 3 5 6}} + {{$refFrom:= ""}} + {{if ne .RefRepoID .Issue.RepoID}} + {{$refFrom = ctx.Locale.Tr "repo.issues.ref_from" .RefRepo.FullName}} + {{end}} + {{$refTr := "issue"}} + {{if .Issue.IsPull}} + {{$refTr = "pull"}} + {{else if eq .RefAction 1}} + {{$refTr = "closing"}} + {{else if eq .RefAction 2}} + {{$refTr = "reopening"}} + {{end}} +
+ {{svg "octicon-bookmark"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + {{if eq .RefAction 3}}{{end}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr (printf "repo.issues.ref_%s_from" $refTr) $createdStr (.RefCommentLink ctx) $refFrom}} + + {{if eq .RefAction 3}}{{end}} + + +
+ {{else if eq .Type 4}} +
+ {{svg "octicon-bookmark"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{if .Issue.IsPull}} + {{ctx.Locale.Tr "repo.pulls.commit_ref_at" $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.commit_ref_at" $createdStr}} + {{end}} + +
+ {{svg "octicon-git-commit"}} + {{.Content | SanitizeHTML}} +
+
+ {{else if eq .Type 7}} + {{if or .AddedLabels .RemovedLabels}} +
+ {{svg "octicon-tag"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{template "repo/issue/view_content/labels_event" dict "Added" .AddedLabels "Removed" .RemovedLabels "RepoLink" $.RepoLink "IsPull" .Issue.IsPull "Time" $createdStr}} + +
+ {{end}} + {{else if eq .Type 8}} +
+ {{svg "octicon-milestone"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{$newMilestoneDisplayHtml := ""}} + {{if gt .MilestoneID 0}} + {{if .Milestone.IsGhost}} + {{$newMilestoneDisplayHtml = .Milestone.Name}} + {{else}} + {{$newMilestoneDisplayHtml = HTMLFormat `%s` $.RepoLink .MilestoneID .Milestone.Name}} + {{end}} + {{end}} + {{$oldMilestoneDisplayHtml := ""}} + {{if gt .OldMilestoneID 0}} + {{if .OldMilestone.IsGhost}} + {{$oldMilestoneDisplayHtml = .OldMilestone.Name}} + {{else}} + {{$oldMilestoneDisplayHtml = HTMLFormat `%s` $.RepoLink .OldMilestoneID .OldMilestone.Name}} + {{end}} + {{end}} + {{if gt .OldMilestoneID 0}} + {{if gt .MilestoneID 0}} + {{ctx.Locale.Tr "repo.issues.change_milestone_at" $oldMilestoneDisplayHtml $newMilestoneDisplayHtml $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.remove_milestone_at" $oldMilestoneDisplayHtml $createdStr}} + {{end}} + {{else}} + {{ctx.Locale.Tr "repo.issues.add_milestone_at" $newMilestoneDisplayHtml $createdStr}} + {{end}} + +
+ {{else if and (eq .Type 9) (gt .AssigneeID 0)}} +
+ {{svg "octicon-person"}} + {{template "shared/user/avatarlink" dict "user" .Assignee}} + + {{template "shared/user/authorlink" .Assignee}} + {{if .RemovedAssignee}} + {{if eq .Poster.ID .Assignee.ID}} + {{ctx.Locale.Tr "repo.issues.remove_self_assignment" $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.remove_assignee_at" (RenderUser $.Context .Poster) $createdStr}} + {{end}} + {{else}} + {{if eq .Poster.ID .AssigneeID}} + {{ctx.Locale.Tr "repo.issues.self_assign_at" $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.add_assignee_at" (RenderUser $.Context .Poster) $createdStr}} + {{end}} + {{end}} + +
+ {{else if eq .Type 10}} +
+ {{svg "octicon-pencil"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.change_title_at" (RenderRefIssueTitle $.Context .OldTitle) (RenderRefIssueTitle $.Context .NewTitle) $createdStr}} + +
+ {{else if eq .Type 11}} +
+ {{svg "octicon-git-branch"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.delete_branch_at" .OldRef $createdStr}} + +
+ {{else if eq .Type 12}} +
+ {{svg "octicon-clock"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.start_tracking_history" $createdStr}} + +
+ {{else if eq .Type 13}} +
+ {{svg "octicon-clock"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.stop_tracking_history" $createdStr}} + + {{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}} +
+ {{svg "octicon-clock"}} + {{if .RenderedContent}} + {{/* compatibility with time comments made before v1.21 */}} + {{.RenderedContent}} + {{else}} + {{.Content|Sec2Time}} + {{end}} +
+
+ {{else if eq .Type 14}} +
+ {{svg "octicon-clock"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.add_time_history" $createdStr}} + + {{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}} +
+ {{svg "octicon-clock"}} + {{if .RenderedContent}} + {{/* compatibility with time comments made before v1.21 */}} + {{.RenderedContent}} + {{else}} + {{.Content|Sec2Time}} + {{end}} +
+
+ {{else if eq .Type 15}} +
+ {{svg "octicon-clock"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.cancel_tracking_history" $createdStr}} + +
+ {{else if eq .Type 16}} +
+ {{svg "octicon-clock"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{$dueDate := DateUtils.AbsoluteLong (.Content|DateUtils.ParseLegacy)}} + {{ctx.Locale.Tr "repo.issues.due_date_added" $dueDate $createdStr}} + +
+ {{else if eq .Type 17}} +
+ {{svg "octicon-clock"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{$parsedDeadline := StringUtils.Split .Content "|"}} + {{if eq (len $parsedDeadline) 2}} + {{$to := DateUtils.AbsoluteLong ((index $parsedDeadline 0)|DateUtils.ParseLegacy)}} + {{$from := DateUtils.AbsoluteLong ((index $parsedDeadline 1)|DateUtils.ParseLegacy)}} + {{ctx.Locale.Tr "repo.issues.due_date_modified" $to $from $createdStr}} + {{end}} + +
+ {{else if eq .Type 18}} +
+ {{svg "octicon-clock"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{$dueDate := DateUtils.AbsoluteLong (.Content|DateUtils.ParseLegacy)}} + {{ctx.Locale.Tr "repo.issues.due_date_remove" $dueDate $createdStr}} + +
+ {{else if eq .Type 19}} +
+ {{svg "octicon-package-dependents"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.dependency.added_dependency" $createdStr}} + + {{if .DependentIssue}} + + {{end}} +
+ {{else if eq .Type 20}} +
+ {{svg "octicon-package-dependents"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.dependency.removed_dependency" $createdStr}} + + {{if .DependentIssue}} + + {{end}} +
+ {{else if eq .Type 22}} +
+
+ {{if not .OriginalAuthor}} + {{/* Some timeline avatars need a offset to correctly align with their speech bubble. + The condition depends on whether the comment has contents/attachments or reviews */}} + + {{ctx.AvatarUtils.Avatar .Poster 40}} + + {{end}} + {{svg (printf "octicon-%s" .Review.Type.Icon)}} + + {{template "repo/issue/view_content/comments_authorlink" dict "ctxData" $ "comment" .}} + {{if eq .Review.Type 1}} + {{ctx.Locale.Tr "repo.issues.review.approve" $createdStr}} + {{else if eq .Review.Type 2}} + {{ctx.Locale.Tr "repo.issues.review.comment" $createdStr}} + {{else if eq .Review.Type 3}} + {{ctx.Locale.Tr "repo.issues.review.reject" $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.review.comment" $createdStr}} + {{end}} + {{if .Review.Dismissed}} +
{{ctx.Locale.Tr "repo.issues.review.dismissed_label"}}
+ {{end}} +
+
+ {{if or .Content .Attachments}} +
+
+
+
+ {{if gt .Poster.ID 0}} + + {{ctx.AvatarUtils.Avatar .Poster 24}} + + {{end}} + + {{if .OriginalAuthor}} + + {{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}} + {{.OriginalAuthor}} + + {{if $.Repository.OriginalURL}} + ({{ctx.Locale.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname}}){{end}} + {{else}} + {{template "shared/user/authorlink" .Poster}} + {{end}} + + {{ctx.Locale.Tr "repo.issues.review.left_comment"}} + +
+
+ {{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole "IsPull" .Issue.IsPull}} + {{if not $.Repository.IsArchived}} + {{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" . "delete" false "issue" true "diff" false "IsCommentPoster" (and $.IsSigned (eq $.SignedUserID .PosterID))}} + {{end}} +
+
+
+
+ {{if .RenderedContent}} + {{.RenderedContent}} + {{else}} + {{ctx.Locale.Tr "repo.issues.no_content"}} + {{end}} +
+
{{.Content}}
+
+ {{if .Attachments}} + {{template "repo/issue/view_content/attachments" dict "Attachments" .Attachments "RenderedContent" .RenderedContent}} + {{end}} + {{if not $.Repository.IsArchived}} + {{template "repo/issue/view_content/body_actions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} + {{end}} +
+ {{$reactions := .Reactions.GroupByType}} + {{if $reactions}} + {{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} + {{end}} +
+
+ {{end}} + + {{if .Review.CodeComments}} +
+ {{range $filename, $lines := .Review.CodeComments}} + {{range $line, $comms := $lines}} + {{template "repo/issue/view_content/conversation" dict "." $ "comments" $comms}} + {{end}} + {{end}} +
+ {{end}} +
+ {{else if eq .Type 23}} +
+ {{svg "octicon-lock"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + {{if .Content}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.lock_with_reason" .Content $createdStr}} + + {{else}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.lock_no_reason" $createdStr}} + + {{end}} +
+ {{else if eq .Type 24}} +
+ {{svg "octicon-key"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.unlock_comment" $createdStr}} + +
+ {{else if eq .Type 25}} +
+ {{svg "octicon-git-branch"}} + {{if not .OriginalAuthor}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + {{end}} + + {{template "repo/issue/view_content/comments_authorlink" dict "ctxData" $ "comment" .}} + {{ctx.Locale.Tr "repo.pulls.change_target_branch_at" .OldRef .NewRef $createdStr}} + +
+ {{else if eq .Type 26}} +
+ {{svg "octicon-clock"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + + {{ctx.Locale.Tr "repo.issues.del_time_history" $createdStr}} + +
+ {{svg "octicon-clock"}} + {{if .RenderedContent}} + {{/* compatibility with time comments made before v1.21 */}} + {{.RenderedContent}} + {{else}} + - {{.Content|Sec2Time}} + {{end}} +
+
+ {{else if eq .Type 27}} + {{if or .AddedRequestReview .RemovedRequestReview}} +
+ {{svg "octicon-eye"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{if and (eq (len .RemovedRequestReview) 1) (eq (len .AddedRequestReview) 0) (eq ((index .RemovedRequestReview 0).ID) .PosterID) (eq ((index .RemovedRequestReview 0).Type) "user")}} + {{ctx.Locale.Tr "repo.issues.review.remove_review_request_self" $createdStr}} + {{else if and .AddedRequestReview (not .RemovedRequestReview)}} + {{ctx.Locale.TrN (len .AddedRequestReview) "repo.issues.review.add_review_request" "repo.issues.review.add_review_requests" (RenderReviewRequest $.Context .AddedRequestReview) $createdStr}} + {{else if and (not .AddedRequestReview) .RemovedRequestReview}} + {{ctx.Locale.TrN (len .RemovedRequestReview) "repo.issues.review.remove_review_request" "repo.issues.review.remove_review_requests" (RenderReviewRequest $.Context .RemovedRequestReview) $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.review.add_remove_review_requests" (RenderReviewRequest $.Context .AddedRequestReview) (RenderReviewRequest $.Context .RemovedRequestReview) $createdStr}} + {{end}} + +
+ {{end}} + {{else if and (eq .Type 29) (or (gt .CommitsNum 0) .IsForcePush)}} + + {{if and .Issue.IsClosed (gt .ID $.LatestCloseCommentID)}} + {{continue}} + {{end}} +
+ {{svg "octicon-repo-push"}} + + {{if .IsForcePush}} + + + {{ + template "shared/user/authorlink" .Poster}} + {{ctx.Locale.Tr "repo.issues.force_push_codes" $.Issue.PullRequest.HeadBranch (ShortSha .OldCommit) ($.Issue.Repo.CommitLink .OldCommit) (ShortSha .NewCommit) ($.Issue.Repo.CommitLink .NewCommit) $createdStr "ui sha" + (ExecuteTemplate ctx "repo/commit_statuses" (dict "Status" (index .Commits 0).Status "Statuses" (index .Commits 0).Statuses)) + (ExecuteTemplate ctx "repo/commit_statuses" (dict "Status" (index .Commits 1).Status "Statuses" (index .Commits 1).Statuses)) + }} + + {{if $.Issue.PullRequest.BaseRepo.Name}} + + {{ctx.Locale.Tr "repo.issues.force_push_compare"}} + + {{end}} + + {{else}} + {{template "shared/user/authorlink" .Poster}} + {{ctx.Locale.TrN (len .Commits) "repo.issues.push_commit_1" "repo.issues.push_commits_n" (len .Commits) $createdStr}} + {{end}} + +
+ {{if not .IsForcePush}} + {{template "repo/commits_list_small" dict "comment" . "root" $}} + {{end}} + {{else if eq .Type 30}} + {{if not $.UnitProjectsGlobalDisabled}} +
+ {{svg "octicon-project"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{$oldProjectDisplayHtml := ""}} + {{if .OldProject}} + {{if .OldProject.IsGhost}} + {{$tooltip := ctx.Locale.Tr "projects.deleted.display_name"}} + {{$oldProjectDisplayHtml = HTMLFormat `%s` $tooltip .OldProject.Title}} + {{else}} + {{$tooltip := ctx.Locale.Tr (printf "projects.type-%d.display_name" .OldProject.Type)}} + {{$oldProjectDisplayHtml = HTMLFormat `%s` (.OldProject.Link ctx) $tooltip .OldProject.Title}} + {{end}} + {{end}} + {{$newProjectDisplayHtml := ""}} + {{if .Project}} + {{if .Project.IsGhost}} + {{$tooltip := ctx.Locale.Tr "projects.deleted.display_name"}} + {{$newProjectDisplayHtml = HTMLFormat `%s` $tooltip .Project.Title}} + {{else}} + {{$tooltip := ctx.Locale.Tr (printf "projects.type-%d.display_name" .Project.Type)}} + {{$newProjectDisplayHtml = HTMLFormat `%s` (.Project.Link ctx) $tooltip .Project.Title}} + {{end}} + {{end}} + {{if .OldProject}} + {{if .Project}} + {{ctx.Locale.Tr "repo.issues.change_project_at" $oldProjectDisplayHtml $newProjectDisplayHtml $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.remove_project_at" $oldProjectDisplayHtml $createdStr}} + {{end}} + {{else}} + {{ctx.Locale.Tr "repo.issues.add_project_at" $newProjectDisplayHtml $createdStr}} + {{end}} + +
+ {{end}} + {{else if eq .Type 32}} +
+
+ + {{ctx.AvatarUtils.Avatar .Poster 40}} + + {{svg "octicon-x" 16}} + + {{template "shared/user/authorlink" .Poster}} + {{$reviewerName := ""}} + {{if eq .Review.OriginalAuthor ""}} + {{$reviewerName = .Review.Reviewer.Name}} + {{else}} + {{$reviewerName = .Review.OriginalAuthor}} + {{end}} + {{ctx.Locale.Tr "repo.issues.review.dismissed" $reviewerName $createdStr}} + +
+ {{if .Content}} +
+
+
+ {{if gt .Poster.ID 0}} + + {{ctx.AvatarUtils.Avatar .Poster 24}} + + {{end}} + + {{ctx.Locale.Tr "action.review_dismissed_reason"}} + +
+
+
+ {{if .RenderedContent}} + {{.RenderedContent}} + {{else}} + {{ctx.Locale.Tr "repo.issues.no_content"}} + {{end}} +
+
+
+
+ {{end}} +
+ {{else if eq .Type 33}} +
+ {{svg "octicon-git-branch"}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{if and .OldRef .NewRef}} + {{ctx.Locale.Tr "repo.issues.change_ref_at" .OldRef .NewRef $createdStr}} + {{else if .OldRef}} + {{ctx.Locale.Tr "repo.issues.remove_ref_at" .OldRef $createdStr}} + {{else}} + {{ctx.Locale.Tr "repo.issues.add_ref_at" .NewRef $createdStr}} + {{end}} + +
+ {{else if or (eq .Type 34) (eq .Type 35)}} +
+ {{svg "octicon-git-merge" 16}} + + {{template "repo/issue/view_content/comments_authorlink" dict "ctxData" $ "comment" .}} + {{if eq .Type 34}}{{ctx.Locale.Tr "repo.pulls.auto_merge_newly_scheduled_comment" $createdStr}} + {{else}}{{ctx.Locale.Tr "repo.pulls.auto_merge_canceled_schedule_comment" $createdStr}}{{end}} + +
+ {{else if or (eq .Type 36) (eq .Type 37)}} +
+ {{svg "octicon-pin" 16}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + {{template "shared/user/authorlink" .Poster}} + {{if eq .Type 36}}{{ctx.Locale.Tr "repo.issues.pin_comment" $createdStr}} + {{else}}{{ctx.Locale.Tr "repo.issues.unpin_comment" $createdStr}}{{end}} + +
+ {{else if eq .Type 38}} +
+ {{svg "octicon-list-unordered" 16}} + {{template "shared/user/avatarlink" dict "user" .Poster}} + + + {{template "shared/user/authorlink" .Poster}} + {{$createdStr}} + +
    + + + {{if and .Aggregator.PrevClosed (not .Aggregator.IsClosed)}} +
  • + {{svg "octicon-dot-fill"}} + {{if .Issue.IsPull}} + {{ctx.Locale.Tr "repo.pulls.reopened_at" ""}} + {{else}} + {{ctx.Locale.Tr "repo.issues.reopened_at" ""}} + {{end}} +
  • + {{else if and (not .Aggregator.PrevClosed) .Aggregator.IsClosed}} + {{svg "octicon-circle-slash"}} +
  • + {{if .Issue.IsPull}} + {{ctx.Locale.Tr "repo.pulls.closed_at" ""}} + {{else}} + {{ctx.Locale.Tr "repo.issues.closed_at" ""}} + {{end}} +
  • + {{end}} + + + {{if or .AddedLabels .RemovedLabels}} +
  • + {{svg "octicon-tag" 20}} + {{template "repo/issue/view_content/labels_event" dict "Added" .AddedLabels "Removed" .RemovedLabels "RepoLink" $.RepoLink "IsPull" .Issue.IsPull "Time" ""}} +
  • + {{end}} + + {{if or .AddedRequestReview .RemovedRequestReview}} +
  • + {{svg "octicon-eye" 20}} + + + {{if and (eq (len .RemovedRequestReview) 1) (eq (len .AddedRequestReview) 0) (eq ((index .RemovedRequestReview 0).ID) .PosterID) (eq ((index .RemovedRequestReview 0).Type) "user")}} + {{ctx.Locale.Tr "repo.issues.review.remove_review_request_self" ""}} + {{else if and .AddedRequestReview (not .RemovedRequestReview)}} + {{ctx.Locale.TrN (len .AddedRequestReview) "repo.issues.review.add_review_request" "repo.issues.review.add_review_requests" (RenderReviewRequest $.Context .AddedRequestReview) ""}} + {{else if and (not .AddedRequestReview) .RemovedRequestReview}} + {{ctx.Locale.TrN (len .RemovedRequestReview) "repo.issues.review.remove_review_request" "repo.issues.review.remove_review_requests" (RenderReviewRequest $.Context .RemovedRequestReview) ""}} + {{else}} + {{ctx.Locale.Tr "repo.issues.review.add_remove_review_requests" (RenderReviewRequest $.Context .AddedRequestReview) (RenderReviewRequest $.Context .RemovedRequestReview) ""}} + {{end}} + + +
  • + {{end}} +
+
+
+ {{end}} + {{end}} +{{end}} diff --git a/templates/repo/issue/view_content/labels_event.tmpl b/templates/repo/issue/view_content/labels_event.tmpl new file mode 100644 index 00000000..464fd1cf --- /dev/null +++ b/templates/repo/issue/view_content/labels_event.tmpl @@ -0,0 +1,26 @@ +{{- /* "added the … label" with theme labels. Forgejo's RenderLabels writes label colours inline with !important, which +no stylesheet can override, so the labels are assembled here for the translation. Keep their markup in step with +components/repository/label/label. */ -}} +{{$kind := "issues"}}{{if .IsPull}}{{$kind = "pulls"}}{{end}} +{{$added := ""}}{{$removed := ""}} +{{range $key, $labels := dict "added" .Added "removed" .Removed}} + {{$list := HTMLFormat ``}} + {{range $labels}} + {{$label := RenderLabel ctx .}} + {{if not .ExclusiveScope}} + {{$archived := ""}}{{$description := .Description}} + {{if .IsArchived}}{{$archived = " archived-label"}}{{$description = print "(" (ctx.Locale.Tr "archived") ") " .Description}}{{end}} + {{$label = HTMLFormat `
%s
` $archived .Color (ContrastColor .Color) $description $description (RenderEmoji ctx .Name)}} + {{end}} + {{$list = HTMLFormat `%s%s ` $list $.RepoLink $kind .ID $label}} + {{end}} + {{$list = HTMLFormat `%s
` $list}} + {{if eq $key "added"}}{{$added = $list}}{{else}}{{$removed = $list}}{{end}} +{{end}} +{{if and .Added (not .Removed)}} + {{ctx.Locale.TrN (len .Added) "repo.issues.add_label" "repo.issues.add_labels" $added .Time}} +{{else if and (not .Added) .Removed}} + {{ctx.Locale.TrN (len .Removed) "repo.issues.remove_label" "repo.issues.remove_labels" $removed .Time}} +{{else}} + {{ctx.Locale.Tr "repo.issues.add_remove_labels" $added $removed .Time}} +{{end}} diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl new file mode 100644 index 00000000..e3115c22 --- /dev/null +++ b/templates/repo/issue/view_content/pull.tmpl @@ -0,0 +1,434 @@ +{{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}} +{{$prConfig := $prUnit.PullRequestsConfig}} +{{$fastForwardStyleAllowed := and $prConfig.AllowFastForwardOnly (eq .Issue.PullRequest.CommitsBehind 0)}} +{{$manualMergeStyleAllowed := $prConfig.AllowManualMerge}} +{{$hasUnsignedMergeStyle := or $fastForwardStyleAllowed $manualMergeStyleAllowed}} +{{$signingBlocksAllMergeStyles := and .AllowMerge .RequireSigned (not .WillSign) (not $hasUnsignedMergeStyle)}} +{{$hasMergeForm := and .AllowMerge (or $prConfig.AllowMerge $prConfig.AllowRebase $prConfig.AllowRebaseMerge $prConfig.AllowSquash $prConfig.AllowFastForwardOnly $prConfig.AllowManualMerge)}} +{{if or (not .Issue.PullRequest.HasMerged) .IsPullBranchDeletable .SomePullRequestRunsNeedApproval}} +
+
{{svg "octicon-git-merge" 40}}
+
+ {{if .LatestCommitStatus}} +
+ {{template "repo/pulls/status" (dict + "CommitStatus" .LatestCommitStatus + "CommitStatuses" .LatestCommitStatuses + "MissingRequiredChecks" .MissingRequiredChecks + "ShowHideChecks" true + "is_context_required" .is_context_required + )}} +
+ {{end}} + {{$showGeneralMergeForm := false}} +
+ {{if .Issue.PullRequest.HasMerged}} + {{if .IsPullBranchDeletable}} +
+
+

+ {{ctx.Locale.Tr "repo.pulls.merged_success"}} +

+ +
+
+ +
+
+ {{end}} + {{template "repo/pulls/trust" .}} + {{else if .Issue.IsClosed}} +
+
+

{{ctx.Locale.Tr "repo.pulls.closed"}}

+ +
+ {{if and .IsPullBranchDeletable (not .IsPullRequestBroken)}} +
+ +
+ {{end}} +
+ {{template "repo/pulls/trust" .}} + {{else if .IsPullFilesConflicted}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.files_conflicted"}} +
+
    + {{range .ConflictedFiles}} +
  • {{.}}
  • + {{end}} +
+ {{template "repo/pulls/trust" .}} + {{else if .IsPullRequestBroken}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.data_broken"}} +
+ {{else if .IsPullWorkInProgress}} +
+
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.cannot_merge_work_in_progress"}} +
+ {{if or .HasIssuesOrPullsWritePermission .IsIssuePoster}} + + {{end}} +
+ {{template "repo/pulls/trust" .}} + {{template "repo/issue/view_content/update_branch_by_merge" $}} + {{else if .Issue.PullRequest.IsChecking}} +
+ {{svg "octicon-sync"}} + {{ctx.Locale.Tr "repo.pulls.is_checking"}} +
+ {{else if .Issue.PullRequest.IsAncestor}} +
+ {{svg "octicon-alert"}} + {{ctx.Locale.Tr "repo.pulls.is_ancestor"}} +
+ {{else if or .Issue.PullRequest.CanAutoMerge .Issue.PullRequest.IsEmpty}} + {{if .IsBlockedByApprovals}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.blocked_by_approvals" .GrantedApprovals .ProtectedBranch.RequiredApprovals}} +
+ {{else if .IsBlockedByRejection}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.blocked_by_rejection"}} +
+ {{else if .IsBlockedByOfficialReviewRequests}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.blocked_by_official_review_requests"}} +
+ {{else if .IsBlockedByOutdatedBranch}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.blocked_by_outdated_branch"}} +
+ {{else if .IsBlockedByChangedProtectedFiles}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}} +
+
    + {{range .ChangedProtectedFiles}} +
  • {{.}}
  • + {{end}} +
+ {{else if and .EnableStatusCheck (or .RequiredStatusCheckState.IsError .RequiredStatusCheckState.IsFailure)}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.required_status_check_failed"}} +
+ {{else if and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess)}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.required_status_check_missing"}} +
+ {{else if $signingBlocksAllMergeStyles}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.require_signed_wont_sign"}} +
+
+ {{svg "octicon-unlock"}} + {{ctx.Locale.Tr (printf "repo.signing.wont_sign.%s" .WontSignReason)}} +
+ {{end}} + + {{$notAllOverridableChecksOk := or .IsBlockedByApprovals .IsBlockedByRejection .IsBlockedByOfficialReviewRequests .IsBlockedByOutdatedBranch .IsBlockedByChangedProtectedFiles (and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess))}} + + {{/* admin can merge without checks, writer can merge when checks succeed */}} + {{$canMergeNow := and (or (and $.IsRepoAdmin (not .ProtectedBranch.ApplyToAdmins)) (not $notAllOverridableChecksOk)) (or (not .AllowMerge) (not $signingBlocksAllMergeStyles))}} + {{/* admin and writer both can make an auto merge schedule */}} + + {{if $canMergeNow}} + {{if $notAllOverridableChecksOk}} +
+ {{svg "octicon-dot-fill"}} + {{ctx.Locale.Tr "repo.pulls.required_status_check_administrator"}} +
+ {{else if $hasMergeForm}} + {{/* GitHub's ready-to-merge header: a title with the signing note beneath it. */}} +
+ {{svg "octicon-check"}} +
+

{{ctx.Locale.Tr "repo.pulls.can_auto_merge_desc"}}

+ {{if .WillSign}} +
+ {{svg "octicon-lock" 16 "text green"}} + {{ctx.Locale.Tr "repo.signing.will_sign" .SigningKey}} +
+ {{else if .IsSigned}} +
+ {{svg "octicon-unlock"}} + {{ctx.Locale.Tr (printf "repo.signing.wont_sign.%s" .WontSignReason)}} +
+ {{end}} +
+
+ {{else}} +
+ {{svg "octicon-check"}} + {{ctx.Locale.Tr "repo.pulls.can_auto_merge_desc"}} +
+ {{end}} + {{if or $notAllOverridableChecksOk (not $hasMergeForm)}} + {{if .WillSign}} +
+ {{svg "octicon-lock" 16 "text green"}} + {{ctx.Locale.Tr "repo.signing.will_sign" .SigningKey}} +
+ {{else if .IsSigned}} +
+ {{svg "octicon-unlock"}} + {{ctx.Locale.Tr (printf "repo.signing.wont_sign.%s" .WontSignReason)}} +
+ {{end}} + {{end}} + {{end}} + {{template "repo/pulls/trust" .}} + {{template "repo/issue/view_content/update_branch_by_merge" $}} + {{if .Issue.PullRequest.IsEmpty}} +
+ +
+ {{svg "octicon-alert"}} + {{ctx.Locale.Tr "repo.pulls.is_empty"}} +
+ {{end}} + + {{if .AllowMerge}} {{/* user is allowed to merge */}} + {{if or $prConfig.AllowMerge $prConfig.AllowRebase $prConfig.AllowRebaseMerge $prConfig.AllowSquash $prConfig.AllowFastForwardOnly $prConfig.AllowManualMerge}} + {{$hasPendingPullRequestMergeTip := ""}} + {{if .HasPendingPullRequestMerge}} + {{$createdPRMergeStr := DateUtils.TimeSince .PendingPullRequestMerge.CreatedUnix}} + {{$hasPendingPullRequestMergeTip = ctx.Locale.Tr "repo.pulls.auto_merge_has_pending_schedule" .PendingPullRequestMerge.Doer.Name $createdPRMergeStr}} + {{end}} +
+ + + {{$showGeneralMergeForm = true}} + {{else}} + {{/* no merge style was set in repo setting: not or ($prConfig.AllowMerge ...) */}} +
+
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.no_merge_desc"}} +
+
+ {{svg "octicon-info"}} + {{ctx.Locale.Tr "repo.pulls.no_merge_helper"}} +
+ {{end}} {{/* end if the repo was set to use any merge style */}} + {{else}} + {{/* user is not allowed to merge */}} +
+
+ {{svg "octicon-info"}} + {{ctx.Locale.Tr "repo.pulls.no_merge_access"}} +
+ {{end}} {{/* end if user is allowed to merge or not */}} + {{else}} + {{/* Merge conflict without specific file. Suggest manual merge, only if all reviews and status checks OK. */}} + {{if .IsBlockedByApprovals}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.blocked_by_approvals" .GrantedApprovals .ProtectedBranch.RequiredApprovals}} +
+ {{else if .IsBlockedByRejection}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.blocked_by_rejection"}} +
+ {{else if .IsBlockedByOfficialReviewRequests}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.blocked_by_official_review_requests"}} +
+ {{else if .IsBlockedByOutdatedBranch}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.blocked_by_outdated_branch"}} +
+ {{else if .IsBlockedByChangedProtectedFiles}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.TrN $.ChangedProtectedFilesNum "repo.pulls.blocked_by_changed_protected_files_1" "repo.pulls.blocked_by_changed_protected_files_n"}} +
+
    + {{range .ChangedProtectedFiles}} +
  • {{.}}
  • + {{end}} +
+ {{else if and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess)}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.required_status_check_failed"}} +
+ {{else if $signingBlocksAllMergeStyles}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.require_signed_wont_sign"}} +
+ {{else}} +
+ {{svg "octicon-x"}} + {{ctx.Locale.Tr "repo.pulls.cannot_auto_merge_desc"}} +
+
+ {{svg "octicon-info"}} + {{ctx.Locale.Tr "repo.pulls.cannot_auto_merge_helper"}} +
+ {{end}} + {{end}}{{/* end if: pull request status */}} + + {{/* + Manually Merged is not a well-known feature, it is used to mark a non-mergeable PR (already merged, conflicted) as merged + To test it: + * Enable "Manually Merged" feature in the Repository Settings + * Create a pull request, either: + * - Merge the pull request branch locally and push the merged commit to Gitea + * - Make some conflicts between the base branch and the pull request branch + * Then the Manually Merged form will be shown in the merge form + */}} + {{if and $.StillCanManualMerge (not $showGeneralMergeForm)}} +
+
+
+
+ +
+ +
+
+ {{end}} + + {{$showMergeInstructions := and .Issue.PullRequest.HeadRepo (not .Issue.PullRequest.HasMerged) (not .Issue.IsClosed)}} + {{if $showGeneralMergeForm}} + {{/* The merge button and the command line instructions close the box together. */}} + {{if $showMergeInstructions}}
{{end}} +
+
+ {{if $showMergeInstructions}} + {{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "ShowMergeInstructions" .ShowMergeInstructions "AutodetectManualMerge" .AutodetectManualMerge "DefaultMergeMessage" .DefaultMergeMessage "DefaultMergeBody" .DefaultMergeBody "IsPullFilesConflicted" .IsPullFilesConflicted "NoDivider" true}} + {{end}} +
+ {{else if $showMergeInstructions}} + {{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "ShowMergeInstructions" .ShowMergeInstructions "AutodetectManualMerge" .AutodetectManualMerge "DefaultMergeMessage" .DefaultMergeMessage "DefaultMergeBody" .DefaultMergeBody "IsPullFilesConflicted" .IsPullFilesConflicted}} + {{end}} +
+
+
+{{end}} diff --git a/templates/repo/issue/view_content/pull_merge_instruction.tmpl b/templates/repo/issue/view_content/pull_merge_instruction.tmpl new file mode 100644 index 00000000..19c0071b --- /dev/null +++ b/templates/repo/issue/view_content/pull_merge_instruction.tmpl @@ -0,0 +1,86 @@ +{{if not .NoDivider}}
{{end}} +
+ {{ctx.Locale.Tr "repo.pulls.cmd_instruction_hint"}} + {{if .IsPullFilesConflicted}} + {{$titleID := printf "manual-merge-title-%d" .PullRequest.ID}} + {{$bodyID := printf "manual-merge-body-%d" .PullRequest.ID}} + {{$copySourceID := printf "manual-merge-message-%d" .PullRequest.ID}} + {{$fullMessage := .DefaultMergeMessage}} + {{if .DefaultMergeBody}} + {{$fullMessage = printf "%s\n\n%s" .DefaultMergeMessage .DefaultMergeBody}} + {{end}} +
+

{{svg "octicon-info" 16}} {{ctx.Locale.Tr "pulls.manual_merge.helper"}}

+

{{ctx.Locale.Tr "pulls.manual_merge.helpder.description"}}

+
+
+
+ + +
+ {{if .DefaultMergeBody}} +
+ + +
+ {{end}} + + +
+
+
+ {{end}} +

{{ctx.Locale.Tr "repo.pulls.cmd_instruction_checkout_title"}}

{{ctx.Locale.Tr "repo.pulls.cmd_instruction_checkout_desc"}}
+ {{$localBranch := .PullRequest.HeadBranch}} + {{if ne .PullRequest.HeadRepo.ID .PullRequest.BaseRepo.ID}} + {{$localBranch = print .PullRequest.HeadRepo.OwnerName "-" .PullRequest.HeadBranch}} + {{end}} +
+ {{if eq .PullRequest.Flow 0}} +
git fetch -u {{if ne .PullRequest.HeadRepo.ID .PullRequest.BaseRepo.ID}}{{else}}origin{{end}} "{{.PullRequest.HeadBranch}}:{{$localBranch}}"
+ {{else}} +
git fetch -u origin "+refs/pull/{{.PullRequest.Index}}/head:{{$localBranch}}"
+ {{end}} +
git switch "{{$localBranch}}"
+
+ {{if .ShowMergeInstructions}} +
+

{{ctx.Locale.Tr "repo.pulls.cmd_instruction_merge_title"}}

+ {{ctx.Locale.Tr "repo.pulls.cmd_instruction_merge_desc"}} + {{if not .AutodetectManualMerge}} +

{{ctx.Locale.Tr "repo.pulls.cmd_instruction_merge_warning"}}

+ {{end}} +
+
+
+
git switch "{{.PullRequest.BaseBranch}}"
+
git merge --no-ff "{{$localBranch}}"
+
+
+
git switch "{{$localBranch}}"
+
git rebase "{{.PullRequest.BaseBranch}}"
+
git switch "{{.PullRequest.BaseBranch}}"
+
git merge --ff-only "{{$localBranch}}"
+
+
+
git switch "{{$localBranch}}"
+
git rebase "{{.PullRequest.BaseBranch}}"
+
git switch "{{.PullRequest.BaseBranch}}"
+
git merge --no-ff "{{$localBranch}}"
+
+
+
git switch "{{.PullRequest.BaseBranch}}"
+
git merge --squash "{{$localBranch}}"
+
+
+
git switch "{{.PullRequest.BaseBranch}}"
+
git merge --ff-only "{{$localBranch}}"
+
+
+
git switch "{{.PullRequest.BaseBranch}}"
+
git merge "{{$localBranch}}"
+
+
git push origin "{{.PullRequest.BaseBranch}}"
+
+ {{end}} +
diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl new file mode 100644 index 00000000..64954142 --- /dev/null +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -0,0 +1,81 @@ +{{/* GitHub's order: reviewers, assignees, labels, projects, milestone, development, notifications, participants. */}} +
+ {{if .Issue.IsPull}} + {{template "repo/issue/view_content/sidebar/pull_review" .}} + {{template "repo/issue/view_content/sidebar/pull_wip" .}} +
+ {{end}} + + {{template "repo/issue/view_content/sidebar/assignees" dict "isExistingIssue" true "." .}} +
+ + {{template "repo/issue/labels/labels_selector_field" .}} + {{template "repo/issue/labels/labels_sidebar" dict "root" $}} +
+ + {{if or .IsProjectsEnabled (and .OwnerHasProjects .IsOwnerProjectsEnabled)}} + {{template "repo/issue/view_content/sidebar/projects" .}} +
+ {{end}} + + {{template "repo/issue/view_content/sidebar/milestones" .}} +
+ + {{if .Repository.IsDependenciesEnabled $.Context}} + {{template "repo/issue/view_content/sidebar/dependencies" .}} +
+ {{end}} + + {{/* Ends with its own divider on issues. */}} + {{template "repo/issue/view_content/sidebar/branch_selector_field" .}} + + {{if and $.IssueWatch (not .Repository.IsArchived)}} + {{template "repo/issue/view_content/sidebar/watch" .}} + {{if .Participants}}
{{end}} + {{end}} + + {{if .Participants}} + {{template "repo/issue/view_content/sidebar/participants" .}} + {{end}} + + {{if .Repository.IsTimetrackerEnabled $.Context}} + {{template "repo/issue/view_content/sidebar/timetracking" .}} + {{end}} + +
+ {{template "repo/issue/view_content/sidebar/due_deadline" .}} + +
+ {{template "repo/issue/view_content/sidebar/reference" .}} + + {{if and .IsRepoAdmin (not .Repository.IsArchived)}} +
+ + {{template "repo/issue/view_content/sidebar/actions" .}} + {{end}} + + {{if and + .Issue.IsPull + (not .Issue.IsClosed) + .Issue.PullRequest.HeadRepo + (not (eq .Issue.PullRequest.HeadRepo.FullName .Issue.PullRequest.BaseRepo.FullName)) + }} + {{if and + .IsIssuePoster + .CanWriteToHeadRepo + }} +
+ {{template "repo/issue/view_content/sidebar/pull_maintainer_edits" .}} + {{else if and + (not .IsIssuePoster) + .CanWriteCode + }} +
+ {{if .Issue.PullRequest.AllowMaintainerEdit}} + {{svg "octicon-check"}} {{ctx.Locale.Tr "repo.pulls.maintainers_can_edit"}} + {{else}} + {{svg "octicon-x"}} {{ctx.Locale.Tr "repo.pulls.maintainers_cannot_edit"}} + {{end}} + {{end}} + {{end}} +
diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 981f929b..d50f2298 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -54,7 +54,7 @@ {{else if not $release.IsTag}} {{end}} - {{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "tw-flex"}} + {{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "tw-flex" "StatusLabel" true}}
{{if and $release.Sha1 ($.Permission.CanRead $.UnitTypeCode)}}{{template "repo/branch_dropdown" dict "root" $ "release" $release}}{{end}} diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl new file mode 100644 index 00000000..a76d2011 --- /dev/null +++ b/templates/shared/issuelist.tmpl @@ -0,0 +1,165 @@ +
+ {{$approvalCounts := .ApprovalCounts}} + {{range .Issues}} +
+ +
+ {{if $.CanWriteIssuesOrPulls}} + + {{end}} + {{template "shared/issueicon" .}} +
+ +
+
+
+ {{RenderRefIssueTitle $.Context .Title}} + {{if .IsPull}} + {{if (index $.CommitStatuses .PullRequest.ID)}} + {{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID)}} + {{end}} + {{end}} + {{if ne $.themeList "issues"}}{{template "shared/issuelist_labels" dict "." $ "Issue" .}}{{end}} +
+ {{if or .TotalTrackedTime .Assignees .NumComments}} +
+ {{if .TotalTrackedTime}} +
+ {{svg "octicon-clock" 16}} + {{.TotalTrackedTime | Sec2Time}} +
+ {{end}} + {{if .Assignees}} +
+ {{range .Assignees}} + + {{ctx.AvatarUtils.Avatar . 20}} + + {{end}} +
+ {{end}} + {{if .NumComments}} + + {{end}} +
+ {{end}} +
+
+ + + {{- if eq $.listType "dashboard" -}} + {{.Repo.FullName}}#{{.Index}} + {{- else -}} + #{{.Index}} + {{- end -}} + + {{$timeStr := DateUtils.TimeSince .GetLastEventTimestamp}} + {{if .OriginalAuthor}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .OriginalAuthor}} + {{else if gt .Poster.ID 0}} + {{ctx.Locale.Tr .GetLastEventLabel $timeStr .Poster.HomeLink .Poster.GetDisplayName}} + {{else}} + {{ctx.Locale.Tr .GetLastEventLabelFake $timeStr .Poster.GetDisplayName}} + {{end}} + + {{if .IsPull}} + {{svg "gitea-double-chevron-right" 12}} + + {{end}} + {{if and .Milestone (ne $.listType "milestone")}} + + {{svg "octicon-milestone" 14}} + {{.Milestone.Name}} + + {{end}} + {{if .Project}} + + {{svg .Project.IconName 14}} + {{.Project.Title}} + + {{end}} + {{if .Ref}} + + {{svg "octicon-git-branch" 14}} + {{index $.IssueRefEndNames .ID}} + + {{end}} + {{$tasks := .GetTasks}} + {{if gt $tasks 0}} + {{$tasksDone := .GetTasksDone}} + + {{svg "octicon-checklist" 14}}{{$tasksDone}} / {{$tasks}} + + + {{end}} + {{if ne .DeadlineUnix 0}} + + {{svg "octicon-calendar" 14}} + {{DateUtils.AbsoluteShort .DeadlineUnix}} + + {{end}} + {{if .IsPull}} + {{$approveOfficial := call $approvalCounts .ID "approve"}} + {{$rejectOfficial := call $approvalCounts .ID "reject"}} + {{$waitingOfficial := call $approvalCounts .ID "waiting"}} + {{if gt $approveOfficial 0}} + + {{svg "octicon-check" 14 "text green"}} + {{ctx.Locale.TrN $approveOfficial "repo.pulls.approve_count_1" "repo.pulls.approve_count_n" $approveOfficial}} + + {{end}} + {{if gt $rejectOfficial 0}} + + {{svg "octicon-diff" 14 "text red"}} + {{ctx.Locale.TrN $rejectOfficial "repo.pulls.reject_count_1" "repo.pulls.reject_count_n" $rejectOfficial}} + + {{end}} + {{if gt $waitingOfficial 0}} + + {{svg "octicon-eye" 14 "text blue"}} + {{ctx.Locale.TrN $waitingOfficial "repo.pulls.waiting_count_1" "repo.pulls.waiting_count_n" $waitingOfficial}} + + {{end}} + {{if and (not .PullRequest.HasMerged) .PullRequest.ConflictedFiles}} + + {{svg "octicon-x" 14 "text red"}} + {{ctx.Locale.TrN (len .PullRequest.ConflictedFiles) "repo.pulls.num_conflicting_files_1" "repo.pulls.num_conflicting_files_n" (len .PullRequest.ConflictedFiles)}} + + {{end}} + {{end}} + {{if or (eq $.SortType "recentupdate") (eq $.SortType "leastupdate")}} + + {{svg "octicon-history" 14}} + {{ctx.Locale.Tr "issues.updated" (DateUtils.TimeSince .UpdatedUnix)}} + + {{end}} +
+ {{/* GitHub lists an issue's labels below its title and metadata. */}} + {{if and (eq $.themeList "issues") .Labels}}{{template "shared/issuelist_labels" dict "." $ "Issue" .}}{{end}} +
+
+ {{else}} +
+ {{if eq $.themeList "pulls"}}{{svg "octicon-git-pull-request" 24}}{{else if eq $.themeList "issues"}}{{svg "octicon-issue-opened" 24}}{{end}} +

{{ctx.Locale.Tr "issues.search.no_results.title"}}

+

{{ctx.Locale.Tr "issues.search.no_results.hint"}}

+
+ {{end}} + {{if .IssueIndexerUnavailable}} +
+

{{ctx.Locale.Tr "search.keyword_search_unavailable"}}

+
+ {{end}} +
+{{template "base/paginate" .}} diff --git a/templates/shared/issuelist_labels.tmpl b/templates/shared/issuelist_labels.tmpl new file mode 100644 index 00000000..e9a243f5 --- /dev/null +++ b/templates/shared/issuelist_labels.tmpl @@ -0,0 +1,5 @@ + + {{range .Issue.Labels}} + {{template "components/repository/label/label" .}} + {{end}} + diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index 7cd9c347..8d18c962 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -1,4 +1,5 @@ {{template "base/head" .}} +{{$themeList := "issues"}}{{if .PageIsPulls}}{{$themeList = "pulls"}}{{end}} {{/* The dashboard's issue and pull request lists use the repository list's layout and classes ("repository issue-list") so they share its styles; nothing repository-specific is rendered. @@ -45,15 +46,15 @@
-
+
+ - {{template "shared/issuelist" dict "." . "listType" "dashboard"}} + {{template "shared/issuelist" dict "." . "listType" "dashboard" "themeList" $themeList}} - {{template "base/footer" .}} diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 18b026fd..d40ca22b 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -50,15 +50,15 @@
{{svg "octicon-milestone" 16}} - {{ctx.Locale.PrettyNumber .MilestoneStats.OpenCount}} {{ctx.Locale.Tr "repo.issues.open_title"}} + {{ctx.Locale.Tr "repo.issues.open_title"}} {{ctx.Locale.PrettyNumber .MilestoneStats.OpenCount}} {{svg "octicon-check" 16}} - {{ctx.Locale.PrettyNumber .MilestoneStats.ClosedCount}} {{ctx.Locale.Tr "repo.issues.closed_title"}} + {{ctx.Locale.Tr "repo.issues.closed_title"}} {{ctx.Locale.PrettyNumber .MilestoneStats.ClosedCount}}
-
+
+
{{range .Milestones}}