@@ -91,11 +91,9 @@ func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision s | |||
return nil, runErr | |||
} | |||
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) | |||
var err error | |||
objectFormat, err := git.GetObjectFormatOfRepo(ctx, repo.RepoPath()) | |||
if err != nil { | |||
return nil, err | |||
} | |||
changes.Updates, err = parseGitLsTreeOutput(objectFormat, stdout) | |||
return &changes, err | |||
} | |||
@@ -174,10 +172,8 @@ func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revisio | |||
return nil, err | |||
} | |||
objectFormat, err := git.GetObjectFormatOfRepo(ctx, repo.RepoPath()) | |||
if err != nil { | |||
return nil, err | |||
} | |||
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) | |||
changes.Updates, err = parseGitLsTreeOutput(objectFormat, lsTreeStdout) | |||
return &changes, err | |||
} |
@@ -104,7 +104,8 @@ func SpecializedMarkdown() goldmark.Markdown { | |||
} | |||
// include language-x class as part of commonmark spec | |||
_, err = w.WriteString(`<code class="chroma language-` + string(language) + `">`) | |||
// the "display" class is used by "js/markup/math.js" to render the code element as a block | |||
_, err = w.WriteString(`<code class="chroma language-` + string(language) + ` display">`) | |||
if err != nil { | |||
return | |||
} |
@@ -142,10 +142,18 @@ func (r *Writer) resolveLink(kind, link string) string { | |||
// so we need to try to guess the link kind again here | |||
kind = org.RegularLink{URL: link}.Kind() | |||
} | |||
base := r.Ctx.Links.Base | |||
if r.Ctx.IsWiki { | |||
base = r.Ctx.Links.WikiLink() | |||
} else if r.Ctx.Links.HasBranchInfo() { | |||
base = r.Ctx.Links.SrcLink() | |||
} | |||
if kind == "image" || kind == "video" { | |||
base = r.Ctx.Links.ResolveMediaLink(r.Ctx.IsWiki) | |||
} | |||
link = util.URLJoin(base, link) | |||
} | |||
return link |
@@ -19,24 +19,50 @@ const AppURL = "http://localhost:3000/" | |||
func TestRender_StandardLinks(t *testing.T) { | |||
setting.AppURL = AppURL | |||
test := func(input, expected string) { | |||
test := func(input, expected string, isWiki bool) { | |||
buffer, err := RenderString(&markup.RenderContext{ | |||
Ctx: git.DefaultContext, | |||
Links: markup.Links{ | |||
Base: "/relative-path", | |||
BranchPath: "branch/main", | |||
}, | |||
IsWiki: isWiki, | |||
}, input) | |||
assert.NoError(t, err) | |||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) | |||
} | |||
test("[[https://google.com/]]", | |||
`<p><a href="https://google.com/">https://google.com/</a></p>`) | |||
`<p><a href="https://google.com/">https://google.com/</a></p>`, false) | |||
test("[[WikiPage][The WikiPage Desc]]", | |||
`<p><a href="/relative-path/WikiPage">The WikiPage Desc</a></p>`) | |||
`<p><a href="/relative-path/wiki/WikiPage">The WikiPage Desc</a></p>`, true) | |||
test("[[ImageLink.svg][The Image Desc]]", | |||
`<p><a href="/relative-path/media/branch/main/ImageLink.svg">The Image Desc</a></p>`) | |||
`<p><a href="/relative-path/media/branch/main/ImageLink.svg">The Image Desc</a></p>`, false) | |||
} | |||
func TestRender_InternalLinks(t *testing.T) { | |||
setting.AppURL = AppURL | |||
test := func(input, expected string) { | |||
buffer, err := RenderString(&markup.RenderContext{ | |||
Ctx: git.DefaultContext, | |||
Links: markup.Links{ | |||
Base: "/relative-path", | |||
BranchPath: "branch/main", | |||
}, | |||
}, input) | |||
assert.NoError(t, err) | |||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) | |||
} | |||
test("[[file:test.org][Test]]", | |||
`<p><a href="/relative-path/src/branch/main/test.org">Test</a></p>`) | |||
test("[[./test.org][Test]]", | |||
`<p><a href="/relative-path/src/branch/main/test.org">Test</a></p>`) | |||
test("[[test.org][Test]]", | |||
`<p><a href="/relative-path/src/branch/main/test.org">Test</a></p>`) | |||
test("[[path/to/test.org][Test]]", | |||
`<p><a href="/relative-path/src/branch/main/path/to/test.org">Test</a></p>`) | |||
} | |||
func TestRender_Media(t *testing.T) { |
@@ -148,12 +148,7 @@ func RestoreBranchPost(ctx *context.Context) { | |||
return | |||
} | |||
objectFormat, err := git.GetObjectFormatOfRepo(ctx, ctx.Repo.Repository.RepoPath()) | |||
if err != nil { | |||
log.Error("RestoreBranch: CreateBranch: %w", err) | |||
ctx.Flash.Error(ctx.Tr("repo.branch.restore_failed", deletedBranch.Name)) | |||
return | |||
} | |||
objectFormat := git.ObjectFormatFromName(ctx.Repo.Repository.ObjectFormatName) | |||
// Don't return error below this | |||
if err := repo_service.PushUpdate( |
@@ -656,12 +656,7 @@ func TestWebhook(ctx *context.Context) { | |||
commit := ctx.Repo.Commit | |||
if commit == nil { | |||
ghost := user_model.NewGhostUser() | |||
objectFormat, err := git.GetObjectFormatOfRepo(ctx, ctx.Repo.Repository.RepoPath()) | |||
if err != nil { | |||
ctx.Flash.Error("GetObjectFormatOfRepo: " + err.Error()) | |||
ctx.Status(http.StatusInternalServerError) | |||
return | |||
} | |||
objectFormat := git.ObjectFormatFromName(ctx.Repo.Repository.ObjectFormatName) | |||
commit = &git.Commit{ | |||
ID: objectFormat.EmptyObjectID(), | |||
Author: ghost.NewGitSig(), |
@@ -479,10 +479,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { | |||
log.Error("SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v", m.Repo, result.refName, err) | |||
continue | |||
} | |||
objectFormat, err := git.GetObjectFormatOfRepo(ctx, m.Repo.RepoPath()) | |||
if err != nil { | |||
log.Error("SyncMirrors [repo: %-v]: unable to GetHashTypeOfRepo: %v", m.Repo, err) | |||
} | |||
objectFormat := git.ObjectFormatFromName(m.Repo.ObjectFormatName) | |||
notify_service.SyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{ | |||
RefFullName: result.refName, | |||
OldCommitID: objectFormat.EmptyObjectID().String(), |
@@ -337,7 +337,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, | |||
} | |||
if err == nil { | |||
for _, pr := range prs { | |||
objectFormat, _ := git.GetObjectFormatOfRepo(ctx, pr.BaseRepo.RepoPath()) | |||
objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName) | |||
if newCommitID != "" && newCommitID != objectFormat.EmptyObjectID().String() { | |||
changed, err := checkIfPRContentChanged(ctx, pr, oldCommitID, newCommitID) | |||
if err != nil { |
@@ -326,10 +326,7 @@ func DeleteReleaseByID(ctx context.Context, repo *repo_model.Repository, rel *re | |||
} | |||
refName := git.RefNameFromTag(rel.TagName) | |||
objectFormat, err := git.GetObjectFormatOfRepo(ctx, repo.RepoPath()) | |||
if err != nil { | |||
return err | |||
} | |||
objectFormat := git.ObjectFormatFromName(repo.ObjectFormatName) | |||
notify_service.PushCommits( | |||
ctx, doer, repo, | |||
&repository.PushUpdateOptions{ |
@@ -1420,6 +1420,7 @@ | |||
.repository .data-table tr { | |||
border-top: 0; | |||
background: none !important; | |||
} | |||
.repository .data-table td, | |||
@@ -1432,6 +1433,21 @@ | |||
border: 1px solid var(--color-secondary); | |||
} | |||
/* the border css competes with .markup where all tables have outer border which would add a double | |||
border here, remove only the outer borders from this table */ | |||
.repository .data-table tr:first-child :is(td,th) { | |||
border-top: none !important; | |||
} | |||
.repository .data-table tr:last-child :is(td,th) { | |||
border-bottom: none !important; | |||
} | |||
.repository .data-table tr :is(td,th):first-child { | |||
border-left: none !important; | |||
} | |||
.repository .data-table tr :is(td,th):last-child { | |||
border-right: none !important; | |||
} | |||
.repository .data-table td { | |||
white-space: pre-line; | |||
} | |||
@@ -1469,7 +1485,7 @@ | |||
min-width: 50px; | |||
font-family: monospace; | |||
line-height: 20px; | |||
color: var(--color-secondary-dark-2); | |||
color: var(--color-text-light-1); | |||
white-space: nowrap; | |||
vertical-align: top; | |||
cursor: pointer; |
@@ -1,8 +1,9 @@ | |||
import $ from 'jquery'; | |||
import {svg} from '../svg.js'; | |||
import {showErrorToast} from '../modules/toast.js'; | |||
import {GET, POST} from '../modules/fetch.js'; | |||
const {appSubUrl, csrfToken} = window.config; | |||
const {appSubUrl} = window.config; | |||
let i18nTextEdited; | |||
let i18nTextOptions; | |||
let i18nTextDeleteFromHistory; | |||
@@ -31,19 +32,27 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH | |||
$dialog.find('.dialog-header-options').dropdown({ | |||
showOnFocus: false, | |||
allowReselection: true, | |||
onChange(_value, _text, $item) { | |||
async onChange(_value, _text, $item) { | |||
const optionItem = $item.data('option-item'); | |||
if (optionItem === 'delete') { | |||
if (window.confirm(i18nTextDeleteFromHistoryConfirm)) { | |||
$.post(`${issueBaseUrl}/content-history/soft-delete?comment_id=${commentId}&history_id=${historyId}`, { | |||
_csrf: csrfToken, | |||
}).done((resp) => { | |||
try { | |||
const params = new URLSearchParams(); | |||
params.append('comment_id', commentId); | |||
params.append('history_id', historyId); | |||
const response = await POST(`${issueBaseUrl}/content-history/soft-delete?${params.toString()}`); | |||
const resp = await response.json(); | |||
if (resp.ok) { | |||
$dialog.modal('hide'); | |||
} else { | |||
showErrorToast(resp.message); | |||
} | |||
}); | |||
} catch (error) { | |||
console.error('Error:', error); | |||
showErrorToast('An error occurred while deleting the history.'); | |||
} | |||
} | |||
} else { // required by eslint | |||
showErrorToast(`unknown option item: ${optionItem}`); | |||
@@ -54,19 +63,24 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH | |||
} | |||
}); | |||
$dialog.modal({ | |||
onShow() { | |||
$.ajax({ | |||
url: `${issueBaseUrl}/content-history/detail?comment_id=${commentId}&history_id=${historyId}`, | |||
data: { | |||
_csrf: csrfToken, | |||
}, | |||
}).done((resp) => { | |||
async onShow() { | |||
try { | |||
const params = new URLSearchParams(); | |||
params.append('comment_id', commentId); | |||
params.append('history_id', historyId); | |||
const url = `${issueBaseUrl}/content-history/detail?${params.toString()}`; | |||
const response = await GET(url); | |||
const resp = await response.json(); | |||
$dialog.find('.comment-diff-data').removeClass('is-loading').html(resp.diffHtml); | |||
// there is only one option "item[data-option-item=delete]", so the dropdown can be entirely shown/hidden. | |||
if (resp.canSoftDelete) { | |||
$dialog.find('.dialog-header-options').removeClass('gt-hidden'); | |||
} | |||
}); | |||
} catch (error) { | |||
console.error('Error:', error); | |||
} | |||
}, | |||
onHidden() { | |||
$dialog.remove(); | |||
@@ -103,7 +117,7 @@ function showContentHistoryMenu(issueBaseUrl, $item, commentId) { | |||
}); | |||
} | |||
export function initRepoIssueContentHistory() { | |||
export async function initRepoIssueContentHistory() { | |||
const issueIndex = $('#issueIndex').val(); | |||
if (!issueIndex) return; | |||
@@ -114,12 +128,10 @@ export function initRepoIssueContentHistory() { | |||
const repoLink = $('#repolink').val(); | |||
const issueBaseUrl = `${appSubUrl}/${repoLink}/issues/${issueIndex}`; | |||
$.ajax({ | |||
url: `${issueBaseUrl}/content-history/overview`, | |||
data: { | |||
_csrf: csrfToken, | |||
}, | |||
}).done((resp) => { | |||
try { | |||
const response = await GET(`${issueBaseUrl}/content-history/overview`); | |||
const resp = await response.json(); | |||
i18nTextEdited = resp.i18n.textEdited; | |||
i18nTextDeleteFromHistory = resp.i18n.textDeleteFromHistory; | |||
i18nTextDeleteFromHistoryConfirm = resp.i18n.textDeleteFromHistoryConfirm; | |||
@@ -133,5 +145,7 @@ export function initRepoIssueContentHistory() { | |||
const $itemComment = $(`#issuecomment-${commentId}`); | |||
showContentHistoryMenu(issueBaseUrl, $itemComment, commentId); | |||
} | |||
}); | |||
} catch (error) { | |||
console.error('Error:', error); | |||
} | |||
} |