From 751997ad34fdd52b9f3956b14395560b059c9ac1 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 1 Apr 2024 21:11:30 +0800 Subject: [PATCH 001/247] Refactor file view & render (#30227) The old code is inconsistent and fragile, and the UI isn't right. --- routers/web/repo/blame.go | 10 +++++++++- routers/web/repo/setting/lfs.go | 17 ++++++++--------- routers/web/repo/view.go | 12 +++++++----- templates/repo/blame.tmpl | 4 ++++ templates/repo/settings/lfs_file.tmpl | 10 ++++------ templates/repo/view_file.tmpl | 16 ++++------------ templates/shared/filetoolarge.tmpl | 4 ++++ 7 files changed, 40 insertions(+), 33 deletions(-) create mode 100644 templates/shared/filetoolarge.tmpl diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 935e6d78fc..1887e4d95d 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -87,9 +88,16 @@ func RefBlame(ctx *context.Context) { ctx.Data["IsBlame"] = true - ctx.Data["FileSize"] = blob.Size() + fileSize := blob.Size() + ctx.Data["FileSize"] = fileSize ctx.Data["FileName"] = blob.Name() + if fileSize >= setting.UI.MaxDisplayFileSize { + ctx.Data["IsFileTooLarge"] = true + ctx.HTML(http.StatusOK, tplRepoHome) + return + } + ctx.Data["NumLines"], err = blob.GetBlobLineCount() ctx.Data["NumLinesSet"] = true diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go index 32049cf0a4..6dddade066 100644 --- a/routers/web/repo/setting/lfs.go +++ b/routers/web/repo/setting/lfs.go @@ -287,22 +287,19 @@ func LFSFileGet(ctx *context.Context) { st := typesniffer.DetectContentType(buf) ctx.Data["IsTextFile"] = st.IsText() - isRepresentableAsText := st.IsRepresentableAsText() - - fileSize := meta.Size ctx.Data["FileSize"] = meta.Size ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s/%s.git/info/lfs/objects/%s/%s", setting.AppURL, url.PathEscape(ctx.Repo.Repository.OwnerName), url.PathEscape(ctx.Repo.Repository.Name), url.PathEscape(meta.Oid), "direct") switch { - case isRepresentableAsText: - if st.IsSvgImage() { - ctx.Data["IsImageFile"] = true - } - - if fileSize >= setting.UI.MaxDisplayFileSize { + case st.IsRepresentableAsText(): + if meta.Size >= setting.UI.MaxDisplayFileSize { ctx.Data["IsFileTooLarge"] = true break } + if st.IsSvgImage() { + ctx.Data["IsImageFile"] = true + } + rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{}) // Building code view blocks with line number on server side. @@ -338,6 +335,8 @@ func LFSFileGet(ctx *context.Context) { ctx.Data["IsAudioFile"] = true case st.IsImage() && (setting.UI.SVG.Enabled || !st.IsSvgImage()): ctx.Data["IsImageFile"] = true + default: + // TODO: the logic is not the same as "renderFile" in "view.go" } ctx.HTML(http.StatusOK, tplSettingsLFSFile) } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 93e0f5bcbd..8aa9dbb1be 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -482,17 +482,17 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) { switch { case isRepresentableAsText: + if fInfo.fileSize >= setting.UI.MaxDisplayFileSize { + ctx.Data["IsFileTooLarge"] = true + break + } + if fInfo.st.IsSvgImage() { ctx.Data["IsImageFile"] = true ctx.Data["CanCopyContent"] = true ctx.Data["HasSourceRenderedToggle"] = true } - if fInfo.fileSize >= setting.UI.MaxDisplayFileSize { - ctx.Data["IsFileTooLarge"] = true - break - } - rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{}) shouldRenderSource := ctx.FormString("display") == "source" @@ -606,6 +606,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) { break } + // TODO: this logic seems strange, it duplicates with "isRepresentableAsText=true", it is not the same as "LFSFileGet" in "lfs.go" + // maybe for this case, the file is a binary file, and shouldn't be rendered? if markupType := markup.Type(blob.Name()); markupType != "" { rd := io.MultiReader(bytes.NewReader(buf), dataRc) ctx.Data["IsMarkup"] = true diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index 1a148a2d1c..30d1a3d78d 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -30,6 +30,9 @@
+ {{if .IsFileTooLarge}} + {{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}} + {{else}} {{range $row := .BlameRows}} @@ -75,6 +78,7 @@ {{end}}
+ {{end}}{{/* end if .IsFileTooLarge */}}
{{if $.Permission.CanRead $.UnitTypeIssues}} {{ctx.Locale.Tr "repo.issues.context.reference_issue"}} diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl index 43afba96c3..cb65236f23 100644 --- a/templates/repo/settings/lfs_file.tmpl +++ b/templates/repo/settings/lfs_file.tmpl @@ -14,7 +14,9 @@
{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}}
- {{if .IsMarkup}} + {{if .IsFileTooLarge}} + {{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}} + {{else if .IsMarkup}} {{if .FileContent}}{{.FileContent | SafeHTML}}{{end}} {{else if .IsPlainText}}
{{if .FileContent}}{{.FileContent | SafeHTML}}{{end}}
@@ -33,19 +35,15 @@ {{else if .IsPDFFile}}
{{else}} - {{ctx.Locale.Tr "repo.file_view_raw"}} + {{ctx.Locale.Tr "repo.file_view_raw"}} {{end}}
{{else if .FileSize}} - {{if .IsFileTooLarge}} - - {{else}} - {{end}}
{{ctx.Locale.Tr "repo.file_too_large"}}{{.LineNums}}
    {{.FileContent}}
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index b7c1b9eeae..9c5bd9094d 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -89,7 +89,9 @@ {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}} {{end}}
- {{if .IsMarkup}} + {{if .IsFileTooLarge}} + {{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}} + {{else if .IsMarkup}} {{if .FileContent}}{{.FileContent}}{{end}} {{else if .IsPlainText}}
{{if .FileContent}}{{.FileContent}}{{end}}
@@ -108,19 +110,10 @@ {{else if .IsPDFFile}}
{{else}} - {{ctx.Locale.Tr "repo.file_view_raw"}} + {{ctx.Locale.Tr "repo.file_view_raw"}} {{end}}
{{else if .FileSize}} - {{if .IsFileTooLarge}} - - - - - - -
{{ctx.Locale.Tr "repo.file_too_large"}}
- {{else}} {{range $idx, $code := .FileContent}} @@ -142,7 +135,6 @@ {{ctx.Locale.Tr "repo.view_git_blame"}}{{ctx.Locale.Tr "repo.file_copy_permalink"}} - {{end}} {{end}} diff --git a/templates/shared/filetoolarge.tmpl b/templates/shared/filetoolarge.tmpl new file mode 100644 index 0000000000..8842fb1b91 --- /dev/null +++ b/templates/shared/filetoolarge.tmpl @@ -0,0 +1,4 @@ +
+ {{ctx.Locale.Tr "repo.file_too_large"}} + {{if .RawFileLink}}{{ctx.Locale.Tr "repo.file_view_raw"}}{{end}} +
From 1ef2eb50d82d07b1e4ff312ef58953d1bba2437a Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Mon, 1 Apr 2024 21:48:14 +0800 Subject: [PATCH 002/247] Remove scheduled action tasks if the repo is archived (#30224) Fix #30220 --- routers/api/v1/repo/repo.go | 10 ++++++++++ routers/web/repo/setting/setting.go | 12 ++++++++++++ services/actions/notifier_helper.go | 4 ++-- services/actions/schedule_tasks.go | 5 +++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 80504b9c33..822e368fa8 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -12,6 +12,7 @@ import ( "strings" "time" + actions_model "code.gitea.io/gitea/models/actions" activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" @@ -31,6 +32,7 @@ import ( "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + actions_service "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/issue" @@ -1035,6 +1037,9 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) return err } + if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil { + log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) } else { if err := repo_model.SetArchiveRepoState(ctx, repo, *opts.Archived); err != nil { @@ -1042,6 +1047,11 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) return err } + if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) { + if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil { + log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } + } log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) } } diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index e045e3b8dc..00a5282f34 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -13,6 +13,7 @@ import ( "time" "code.gitea.io/gitea/models" + actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" @@ -29,6 +30,7 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" + actions_service "code.gitea.io/gitea/services/actions" asymkey_service "code.gitea.io/gitea/services/asymkey" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -897,6 +899,10 @@ func SettingsPost(ctx *context.Context) { return } + if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil { + log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } + ctx.Flash.Success(ctx.Tr("repo.settings.archive.success")) log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) @@ -915,6 +921,12 @@ func SettingsPost(ctx *context.Context) { return } + if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) { + if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil { + log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err) + } + } + ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success")) log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 66a19844c2..8c98f56af5 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -117,7 +117,7 @@ func notify(ctx context.Context, input *notifyInput) error { log.Debug("ignore executing %v for event %v whose doer is %v", getMethod(ctx), input.Event, input.Doer.Name) return nil } - if input.Repo.IsEmpty { + if input.Repo.IsEmpty || input.Repo.IsArchived { return nil } if unit_model.TypeActions.UnitGlobalDisabled() { @@ -501,7 +501,7 @@ func handleSchedules( // DetectAndHandleSchedules detects the schedule workflows on the default branch and create schedule tasks func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) error { - if repo.IsEmpty { + if repo.IsEmpty || repo.IsArchived { return nil } diff --git a/services/actions/schedule_tasks.go b/services/actions/schedule_tasks.go index 59862fd0d8..e4e56e5122 100644 --- a/services/actions/schedule_tasks.go +++ b/services/actions/schedule_tasks.go @@ -66,6 +66,11 @@ func startTasks(ctx context.Context) error { } } + if row.Repo.IsArchived { + // Skip if the repo is archived + continue + } + cfg, err := row.Repo.GetUnit(ctx, unit.TypeActions) if err != nil { if repo_model.IsErrUnitTypeNotExist(err) { From ca297a90fb1fec5b270fad1a3e575916510e7385 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 2 Apr 2024 02:16:38 +0800 Subject: [PATCH 003/247] Refactor dropzone (#30232) Simplify code and use `.files` elements --- web_src/js/features/repo-legacy.js | 50 +++++++++++++----------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 34320de1de..4c7dd36920 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -358,11 +358,11 @@ async function onEditContent(event) { input.name = 'files'; input.type = 'hidden'; input.value = data.uuid; - dropzone.querySelector('.files').insertAdjacentHTML('beforeend', input.outerHTML); + dropzone.querySelector('.files').append(input); }); this.on('removedfile', async (file) => { - if (disableRemovedfileEvent) return; document.getElementById(file.uuid)?.remove(); + if (disableRemovedfileEvent) return; if (dropzone.getAttribute('data-remove-url') && !fileUuidDict[file.uuid].submitted) { try { await POST(dropzone.getAttribute('data-remove-url'), {data: new URLSearchParams({file: file.uuid})}); @@ -384,6 +384,7 @@ async function onEditContent(event) { disableRemovedfileEvent = true; dz.removeAllFiles(true); dropzone.querySelector('.files').innerHTML = ''; + for (const el of dropzone.querySelectorAll('.dz-preview')) el.remove(); fileUuidDict = {}; disableRemovedfileEvent = false; @@ -392,7 +393,6 @@ async function onEditContent(event) { dz.emit('addedfile', attachment); dz.emit('thumbnail', attachment, imgSrc); dz.emit('complete', attachment); - dz.files.push(attachment); fileUuidDict[attachment.uuid] = {submitted: true}; dropzone.querySelector(`img[src='${imgSrc}']`).style.maxWidth = '100%'; const input = document.createElement('input'); @@ -400,7 +400,10 @@ async function onEditContent(event) { input.name = 'files'; input.type = 'hidden'; input.value = attachment.uuid; - dropzone.querySelector('.files').insertAdjacentHTML('beforeend', input.outerHTML); + dropzone.querySelector('.files').append(input); + } + if (!dropzone.querySelector('.dz-preview')) { + dropzone.classList.remove('dz-started'); } } catch (error) { console.error(error); @@ -412,24 +415,24 @@ async function onEditContent(event) { return dz; }; - const cancelAndReset = (dz) => { + const cancelAndReset = (e) => { + e.preventDefault(); showElem(renderContent); hideElem(editContentZone); - if (dz) { - dz.emit('reload'); - } + comboMarkdownEditor.attachedDropzoneInst?.emit('reload'); }; - const saveAndRefresh = async (dz) => { + const saveAndRefresh = async (e) => { + e.preventDefault(); showElem(renderContent); hideElem(editContentZone); - + const dropzoneInst = comboMarkdownEditor.attachedDropzoneInst; try { const params = new URLSearchParams({ content: comboMarkdownEditor.value(), context: editContentZone.getAttribute('data-context'), }); - for (const file of dz.files) params.append('files[]', file.uuid); + for (const fileInput of dropzoneInst?.element.querySelectorAll('.files [name=files]')) params.append('files[]', fileInput.value); const response = await POST(editContentZone.getAttribute('data-update-url'), {data: params}); const data = await response.json(); @@ -452,10 +455,8 @@ async function onEditContent(event) { } else { content.querySelector('.dropzone-attachments').outerHTML = data.attachments; } - if (dz) { - dz.emit('submit'); - dz.emit('reload'); - } + dropzoneInst?.emit('submit'); + dropzoneInst?.emit('reload'); initMarkupContent(); initCommentContent(); } catch (error) { @@ -463,22 +464,13 @@ async function onEditContent(event) { } }; - if (!editContentZone.innerHTML) { + comboMarkdownEditor = getComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); + if (!comboMarkdownEditor) { editContentZone.innerHTML = document.getElementById('issue-comment-editor-template').innerHTML; comboMarkdownEditor = await initComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); - - const dropzone = editContentZone.querySelector('.dropzone'); - const dz = await setupDropzone(dropzone); - editContentZone.querySelector('.cancel.button').addEventListener('click', (e) => { - e.preventDefault(); - cancelAndReset(dz); - }); - editContentZone.querySelector('.save.button').addEventListener('click', (e) => { - e.preventDefault(); - saveAndRefresh(dz); - }); - } else { - comboMarkdownEditor = getComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); + comboMarkdownEditor.attachedDropzoneInst = await setupDropzone(editContentZone.querySelector('.dropzone')); + editContentZone.querySelector('.cancel.button').addEventListener('click', cancelAndReset); + editContentZone.querySelector('.save.button').addEventListener('click', saveAndRefresh); } // Show write/preview tab and copy raw content as needed From 0db554fa634737af59613768b2e01bfe3e239e68 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 2 Apr 2024 04:23:17 +0800 Subject: [PATCH 004/247] Refactor commit signature parser (#30228) To make it more flexible and support SSH signature. The existing tests are not changed, there are also tests covering `parseTagRef` which also calls `parsePayloadSignature` now. Add some new tests to `Test_parseTagData` --- modules/git/commit.go | 6 +- modules/git/commit_convert_gogit.go | 4 +- modules/git/commit_reader.go | 2 +- modules/git/repo_tag.go | 10 ++- modules/git/repo_tag_test.go | 2 +- modules/git/tag.go | 104 +++++++++++++++------------ modules/git/tag_test.go | 106 +++++++++++++++++----------- 7 files changed, 135 insertions(+), 99 deletions(-) diff --git a/modules/git/commit.go b/modules/git/commit.go index ef2676762c..5f442b0e1a 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -26,14 +26,14 @@ type Commit struct { Author *Signature Committer *Signature CommitMessage string - Signature *CommitGPGSignature + Signature *CommitSignature Parents []ObjectID // ID strings submoduleCache *ObjectCache } -// CommitGPGSignature represents a git commit signature part. -type CommitGPGSignature struct { +// CommitSignature represents a git commit signature part. +type CommitSignature struct { Signature string Payload string // TODO check if can be reconstruct from the rest of commit information to not have duplicate data } diff --git a/modules/git/commit_convert_gogit.go b/modules/git/commit_convert_gogit.go index 33ef2f4487..d7b945ed6b 100644 --- a/modules/git/commit_convert_gogit.go +++ b/modules/git/commit_convert_gogit.go @@ -13,7 +13,7 @@ import ( "github.com/go-git/go-git/v5/plumbing/object" ) -func convertPGPSignature(c *object.Commit) *CommitGPGSignature { +func convertPGPSignature(c *object.Commit) *CommitSignature { if c.PGPSignature == "" { return nil } @@ -57,7 +57,7 @@ func convertPGPSignature(c *object.Commit) *CommitGPGSignature { return nil } - return &CommitGPGSignature{ + return &CommitSignature{ Signature: c.PGPSignature, Payload: w.String(), } diff --git a/modules/git/commit_reader.go b/modules/git/commit_reader.go index 56c41dc473..f1f4a0e588 100644 --- a/modules/git/commit_reader.go +++ b/modules/git/commit_reader.go @@ -99,7 +99,7 @@ readLoop: } } commit.CommitMessage = messageSB.String() - commit.Signature = &CommitGPGSignature{ + commit.Signature = &CommitSignature{ Signature: signatureSB.String(), Payload: payloadSB.String(), } diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index e8c5ce6fb8..2026a4c9f5 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -185,17 +185,15 @@ func parseTagRef(ref map[string]string) (tag *Tag, err error) { tag.Tagger = parseSignatureFromCommitLine(ref["creator"]) tag.Message = ref["contents"] - // strip PGP signature if present in contents field - pgpStart := strings.Index(tag.Message, beginpgp) - if pgpStart >= 0 { - tag.Message = tag.Message[0:pgpStart] - } + + // strip any signature if present in contents field + _, tag.Message, _ = parsePayloadSignature(util.UnsafeStringToBytes(tag.Message), 0) // annotated tag with GPG signature if tag.Type == "tag" && ref["contents:signature"] != "" { payload := fmt.Sprintf("object %s\ntype commit\ntag %s\ntagger %s\n\n%s\n", tag.Object, tag.Name, ref["creator"], strings.TrimSpace(tag.Message)) - tag.Signature = &CommitGPGSignature{ + tag.Signature = &CommitSignature{ Signature: ref["contents:signature"], Payload: payload, } diff --git a/modules/git/repo_tag_test.go b/modules/git/repo_tag_test.go index 785c3442a7..0117cb902d 100644 --- a/modules/git/repo_tag_test.go +++ b/modules/git/repo_tag_test.go @@ -315,7 +315,7 @@ qbHDASXl Type: "tag", Tagger: parseSignatureFromCommitLine("Foo Bar 1565789218 +0300"), Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md", - Signature: &CommitGPGSignature{ + Signature: &CommitSignature{ Signature: `-----BEGIN PGP SIGNATURE----- aBCGzBAABCgAdFiEEyWRwv/q1Q6IjSv+D4IPOwzt33PoFAmI8jbIACgkQ4IPOwzt3 diff --git a/modules/git/tag.go b/modules/git/tag.go index 94e5cd7c63..f7666aa89b 100644 --- a/modules/git/tag.go +++ b/modules/git/tag.go @@ -6,16 +6,10 @@ package git import ( "bytes" "sort" - "strings" "code.gitea.io/gitea/modules/util" ) -const ( - beginpgp = "\n-----BEGIN PGP SIGNATURE-----\n" - endpgp = "\n-----END PGP SIGNATURE-----" -) - // Tag represents a Git tag. type Tag struct { Name string @@ -24,7 +18,7 @@ type Tag struct { Type string Tagger *Signature Message string - Signature *CommitGPGSignature + Signature *CommitSignature } // Commit return the commit of the tag reference @@ -32,6 +26,36 @@ func (tag *Tag) Commit(gitRepo *Repository) (*Commit, error) { return gitRepo.getCommit(tag.Object) } +func parsePayloadSignature(data []byte, messageStart int) (payload, msg, sign string) { + pos := messageStart + signStart, signEnd := -1, -1 + for { + eol := bytes.IndexByte(data[pos:], '\n') + if eol < 0 { + break + } + line := data[pos : pos+eol] + signType, hasPrefix := bytes.CutPrefix(line, []byte("-----BEGIN ")) + signType, hasSuffix := bytes.CutSuffix(signType, []byte(" SIGNATURE-----")) + if hasPrefix && hasSuffix { + signEndBytes := append([]byte("\n-----END "), signType...) + signEndBytes = append(signEndBytes, []byte(" SIGNATURE-----")...) + signEnd = bytes.Index(data[pos:], signEndBytes) + if signEnd != -1 { + signStart = pos + signEnd = pos + signEnd + len(signEndBytes) + } + } + pos += eol + 1 + } + + if signStart != -1 && signEnd != -1 { + msgEnd := max(messageStart, signStart-1) + return string(data[:msgEnd]), string(data[messageStart:msgEnd]), string(data[signStart:signEnd]) + } + return string(data), string(data[messageStart:]), "" +} + // Parse commit information from the (uncompressed) raw // data from the commit object. // \n\n separate headers from message @@ -40,47 +64,37 @@ func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) { tag.ID = objectFormat.EmptyObjectID() tag.Object = objectFormat.EmptyObjectID() tag.Tagger = &Signature{} - // we now have the contents of the commit object. Let's investigate... - nextline := 0 -l: + + pos := 0 for { - eol := bytes.IndexByte(data[nextline:], '\n') - switch { - case eol > 0: - line := data[nextline : nextline+eol] - spacepos := bytes.IndexByte(line, ' ') - reftype := line[:spacepos] - switch string(reftype) { - case "object": - id, err := NewIDFromString(string(line[spacepos+1:])) - if err != nil { - return nil, err - } - tag.Object = id - case "type": - // A commit can have one or more parents - tag.Type = string(line[spacepos+1:]) - case "tagger": - tag.Tagger = parseSignatureFromCommitLine(util.UnsafeBytesToString(line[spacepos+1:])) - } - nextline += eol + 1 - case eol == 0: - tag.Message = string(data[nextline+1:]) - break l - default: - break l + eol := bytes.IndexByte(data[pos:], '\n') + if eol == -1 { + break // shouldn't happen, but could just tolerate it } + if eol == 0 { + pos++ + break // end of headers + } + line := data[pos : pos+eol] + key, val, _ := bytes.Cut(line, []byte(" ")) + switch string(key) { + case "object": + id, err := NewIDFromString(string(val)) + if err != nil { + return nil, err + } + tag.Object = id + case "type": + tag.Type = string(val) // A commit can have one or more parents + case "tagger": + tag.Tagger = parseSignatureFromCommitLine(util.UnsafeBytesToString(val)) + } + pos += eol + 1 } - idx := strings.LastIndex(tag.Message, beginpgp) - if idx > 0 { - endSigIdx := strings.Index(tag.Message[idx:], endpgp) - if endSigIdx > 0 { - tag.Signature = &CommitGPGSignature{ - Signature: tag.Message[idx+1 : idx+endSigIdx+len(endpgp)], - Payload: string(data[:bytes.LastIndex(data, []byte(beginpgp))+1]), - } - tag.Message = tag.Message[:idx+1] - } + payload, msg, sign := parsePayloadSignature(data, pos) + tag.Message = msg + if len(sign) > 0 { + tag.Signature = &CommitSignature{Signature: sign, Payload: payload} } return tag, nil } diff --git a/modules/git/tag_test.go b/modules/git/tag_test.go index f980b0c560..ba02c28946 100644 --- a/modules/git/tag_test.go +++ b/modules/git/tag_test.go @@ -12,24 +12,28 @@ import ( func Test_parseTagData(t *testing.T) { testData := []struct { - data []byte - tag Tag + data string + expected Tag }{ - {data: []byte(`object 3b114ab800c6432ad42387ccf6bc8d4388a2885a + { + data: `object 3b114ab800c6432ad42387ccf6bc8d4388a2885a type commit tag 1.22.0 tagger Lucas Michot 1484491741 +0100 -`), tag: Tag{ - Name: "", - ID: Sha1ObjectFormat.EmptyObjectID(), - Object: &Sha1Hash{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a}, - Type: "commit", - Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0)}, - Message: "", - Signature: nil, - }}, - {data: []byte(`object 7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc +`, + expected: Tag{ + Name: "", + ID: Sha1ObjectFormat.EmptyObjectID(), + Object: MustIDFromString("3b114ab800c6432ad42387ccf6bc8d4388a2885a"), + Type: "commit", + Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0).In(time.FixedZone("", 3600))}, + Message: "", + Signature: nil, + }, + }, + { + data: `object 7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc type commit tag 1.22.1 tagger Lucas Michot 1484553735 +0100 @@ -37,37 +41,57 @@ tagger Lucas Michot 1484553735 +0100 test message o -ono`), tag: Tag{ - Name: "", - ID: Sha1ObjectFormat.EmptyObjectID(), - Object: &Sha1Hash{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc}, - Type: "commit", - Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0)}, - Message: "test message\no\n\nono", - Signature: nil, - }}, +ono`, + expected: Tag{ + Name: "", + ID: Sha1ObjectFormat.EmptyObjectID(), + Object: MustIDFromString("7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc"), + Type: "commit", + Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0).In(time.FixedZone("", 3600))}, + Message: "test message\no\n\nono", + Signature: nil, + }, + }, + { + data: `object 7cdf42c0b1cc763ab7e4c33c47a24e27c66bfaaa +type commit +tag v0 +tagger dummy user 1484491741 +0100 + +dummy message +-----BEGIN SSH SIGNATURE----- +dummy signature +-----END SSH SIGNATURE----- +`, + expected: Tag{ + Name: "", + ID: Sha1ObjectFormat.EmptyObjectID(), + Object: MustIDFromString("7cdf42c0b1cc763ab7e4c33c47a24e27c66bfaaa"), + Type: "commit", + Tagger: &Signature{Name: "dummy user", Email: "dummy-email@example.com", When: time.Unix(1484491741, 0).In(time.FixedZone("", 3600))}, + Message: "dummy message", + Signature: &CommitSignature{ + Signature: `-----BEGIN SSH SIGNATURE----- +dummy signature +-----END SSH SIGNATURE-----`, + Payload: `object 7cdf42c0b1cc763ab7e4c33c47a24e27c66bfaaa +type commit +tag v0 +tagger dummy user 1484491741 +0100 + +dummy message`, + }, + }, + }, } for _, test := range testData { - tag, err := parseTagData(Sha1ObjectFormat, test.data) + tag, err := parseTagData(Sha1ObjectFormat, []byte(test.data)) assert.NoError(t, err) - assert.EqualValues(t, test.tag.ID, tag.ID) - assert.EqualValues(t, test.tag.Object, tag.Object) - assert.EqualValues(t, test.tag.Name, tag.Name) - assert.EqualValues(t, test.tag.Message, tag.Message) - assert.EqualValues(t, test.tag.Type, tag.Type) - if test.tag.Signature != nil && assert.NotNil(t, tag.Signature) { - assert.EqualValues(t, test.tag.Signature.Signature, tag.Signature.Signature) - assert.EqualValues(t, test.tag.Signature.Payload, tag.Signature.Payload) - } else { - assert.Nil(t, tag.Signature) - } - if test.tag.Tagger != nil && assert.NotNil(t, tag.Tagger) { - assert.EqualValues(t, test.tag.Tagger.Name, tag.Tagger.Name) - assert.EqualValues(t, test.tag.Tagger.Email, tag.Tagger.Email) - assert.EqualValues(t, test.tag.Tagger.When.Unix(), tag.Tagger.When.Unix()) - } else { - assert.Nil(t, tag.Tagger) - } + assert.Equal(t, test.expected, *tag) } + + tag, err := parseTagData(Sha1ObjectFormat, []byte("type commit\n\nfoo\n-----BEGIN SSH SIGNATURE-----\ncorrupted...")) + assert.NoError(t, err) + assert.Equal(t, "foo\n-----BEGIN SSH SIGNATURE-----\ncorrupted...", tag.Message) } From 8a5c597c1d53e7652f1f3fc59e64b46a04c5e20b Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 2 Apr 2024 00:24:02 +0000 Subject: [PATCH 005/247] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 1 - options/locale/locale_de-DE.ini | 1 - options/locale/locale_el-GR.ini | 1 - options/locale/locale_es-ES.ini | 1 - options/locale/locale_fa-IR.ini | 1 - options/locale/locale_fi-FI.ini | 1 - options/locale/locale_fr-FR.ini | 1 - options/locale/locale_hu-HU.ini | 1 - options/locale/locale_it-IT.ini | 1 - options/locale/locale_ja-JP.ini | 1 - options/locale/locale_lv-LV.ini | 1 - options/locale/locale_nl-NL.ini | 1 - options/locale/locale_pl-PL.ini | 1 - options/locale/locale_pt-BR.ini | 1 - options/locale/locale_pt-PT.ini | 4 +++- options/locale/locale_ru-RU.ini | 1 - options/locale/locale_si-LK.ini | 1 - options/locale/locale_sv-SE.ini | 1 - options/locale/locale_tr-TR.ini | 1 - options/locale/locale_uk-UA.ini | 1 - options/locale/locale_zh-CN.ini | 1 - options/locale/locale_zh-TW.ini | 1 - 22 files changed, 3 insertions(+), 22 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 4abf813725..82a8fe5d45 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -2790,7 +2790,6 @@ settings=Nastavení správce dashboard.new_version_hint=Gitea %s je nyní k dispozici, právě u vás běži %s. Podívej se na blogu pro více informací. dashboard.statistic=Souhrn -dashboard.operations=Operace údržby dashboard.system_status=Status systému dashboard.operation_name=Název operace dashboard.operation_switch=Přepnout diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 4d446db86f..9a09c2922e 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -2798,7 +2798,6 @@ settings=Administratoreinstellungen dashboard.new_version_hint=Gitea %s ist jetzt verfügbar, deine derzeitige Version ist %s. Weitere Details findest du im Blog. dashboard.statistic=Übersicht -dashboard.operations=Wartungsoperationen dashboard.system_status=System-Status dashboard.operation_name=Name der Operation dashboard.operation_switch=Wechseln diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 1199d84581..6ce5ae1ce9 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -2687,7 +2687,6 @@ settings=Ρυθμίσεις Διαχειριστή dashboard.new_version_hint=Το Gitea %s είναι διαθέσιμο, τώρα εκτελείτε το %s. Ανατρέξτε στο blog για περισσότερες λεπτομέρειες. dashboard.statistic=Περίληψη -dashboard.operations=Λειτουργίες Συντήρησης dashboard.system_status=Κατάσταση Συστήματος dashboard.operation_name=Όνομα Λειτουργίας dashboard.operation_switch=Αλλαγή diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index ce50b71ec4..fc78e1d439 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -2672,7 +2672,6 @@ settings=Configuración de Admin dashboard.new_version_hint=Gitea %s ya está disponible, estás ejecutando %s. Revisa el blog para más detalles. dashboard.statistic=Resumen -dashboard.operations=Operaciones de mantenimiento dashboard.system_status=Estado del sistema dashboard.operation_name=Nombre de la operación dashboard.operation_switch=Interruptor diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 31122841a7..d19eb356d2 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -2064,7 +2064,6 @@ last_page=واپسین total=مجموع: %d dashboard.statistic=چکیده -dashboard.operations=عملیات‌های نگهداری dashboard.system_status=وضعیت سامانه dashboard.operation_name=نام عملیات dashboard.operation_switch=تعویض diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 00581f49fc..f283209908 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -1407,7 +1407,6 @@ last_page=Viimeisin total=Yhteensä: %d dashboard.statistic=Yhteenveto -dashboard.operations=Huoltotoimet dashboard.system_status=Järjestelmän tila dashboard.operation_name=Toiminnon nimi dashboard.operation_switch=Vaihda diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 062c818bd4..dc66402901 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -2712,7 +2712,6 @@ settings=Paramètres administrateur dashboard.new_version_hint=Gitea %s est maintenant disponible, vous utilisez %s. Consultez le blog pour plus de détails. dashboard.statistic=Résumé -dashboard.operations=Opérations de maintenance dashboard.system_status=État du système dashboard.operation_name=Nom de l'Opération dashboard.operation_switch=Basculer diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 93e3b42115..fb229090d4 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -1266,7 +1266,6 @@ last_page=Utolsó total=Összesen: %d dashboard.statistic=Összefoglaló -dashboard.operations=Karbantartási műveletek dashboard.system_status=Rendszer Állapota dashboard.operation_name=Művelet Neve dashboard.operation_switch=Váltás diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index cc379e8109..9a22995dfb 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -2233,7 +2233,6 @@ last_page=Ultima total=Totale: %d dashboard.statistic=Riepilogo -dashboard.operations=Operazioni di manutenzione dashboard.system_status=Stato del sistema dashboard.operation_name=Nome Operazione dashboard.operation_switch=Cambia diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index d5c2885f00..eddad35073 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -2719,7 +2719,6 @@ settings=管理設定 dashboard.new_version_hint=Gitea %s が入手可能になりました。 現在実行しているのは %s です。 詳細は ブログ を確認してください。 dashboard.statistic=サマリー -dashboard.operations=メンテナンス操作 dashboard.system_status=システム状況 dashboard.operation_name=操作の名称 dashboard.operation_switch=切り替え diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 0a2729980b..9a15090012 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -2693,7 +2693,6 @@ settings=Administratora iestatījumi dashboard.new_version_hint=Ir pieejama Gitea versija %s, pašreizējā versija %s. Papildus informācija par jauno versiju ir pieejama mājas lapā. dashboard.statistic=Kopsavilkums -dashboard.operations=Uzturēšanas darbības dashboard.system_status=Sistēmas statuss dashboard.operation_name=Darbības nosaukums dashboard.operation_switch=Pārslēgt diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 255a3db9fa..6b5122a86f 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -2135,7 +2135,6 @@ last_page=Laatste total=Totaal: %d dashboard.statistic=Overzicht -dashboard.operations=Onderhoudswerkzaamheden dashboard.system_status=Systeemtatus dashboard.operation_name=Bewerking naam dashboard.operation_switch=Omschakelen diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 1496877fd5..a1d7e95842 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -2010,7 +2010,6 @@ last_page=Ostatnia total=Ogółem: %d dashboard.statistic=Podsumowanie -dashboard.operations=Operacje konserwacji dashboard.system_status=Status strony dashboard.operation_name=Nazwa operacji dashboard.operation_switch=Przełącz diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 0d1614df3f..45f1c3b3f8 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -2648,7 +2648,6 @@ settings=Configurações de Administrador dashboard.new_version_hint=Uma nova versão está disponível: %s. Versão atual: %s. Visite o blog para mais informações. dashboard.statistic=Resumo -dashboard.operations=Operações de manutenção dashboard.system_status=Status do sistema dashboard.operation_name=Nome da operação dashboard.operation_switch=Trocar diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index ea80cd7abb..09b9d4e3ce 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -2775,6 +2775,7 @@ teams.invite.by=Convidado(a) por %s teams.invite.description=Clique no botão abaixo para se juntar à equipa. [admin] +maintenance=Manutenção dashboard=Painel de controlo self_check=Auto-verificação identity_access=Identidade e acesso @@ -2798,7 +2799,7 @@ settings=Configurações de administração dashboard.new_version_hint=O Gitea %s está disponível, você está a correr a versão %s. Verifique o blog para mais detalhes. dashboard.statistic=Resumo -dashboard.operations=Operações de manutenção +dashboard.maintenance_operations=Operações de manutenção dashboard.system_status=Estado do sistema dashboard.operation_name=Nome da operação dashboard.operation_switch=Comutar @@ -3305,6 +3306,7 @@ notices.op=Op. notices.delete_success=As notificações do sistema foram eliminadas. self_check.no_problem_found=Nenhum problema encontrado até agora. +self_check.startup_warnings=Alertas do arranque: self_check.database_collation_mismatch=Supor que a base de dados usa a colação: %s self_check.database_collation_case_insensitive=A base de dados está a usar a colação %s, que é insensível à diferença entre maiúsculas e minúsculas. Embora o Gitea possa trabalhar com ela, pode haver alguns casos raros que não funcionem como esperado. self_check.database_inconsistent_collation_columns=A base de dados está a usar a colação %s, mas estas colunas estão a usar colações diferentes. Isso poderá causar alguns problemas inesperados. diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 74c4c9c935..818dad1147 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -2634,7 +2634,6 @@ total=Всего: %d dashboard.new_version_hint=Доступна новая версия Gitea %s, вы используете %s. Более подробную информацию читайте в блоге. dashboard.statistic=Статистика -dashboard.operations=Операции dashboard.system_status=Состояние системы dashboard.operation_name=Имя операции dashboard.operation_switch=Переключить diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index 7e82cfe3d6..99559802c5 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -2024,7 +2024,6 @@ last_page=පසුගිය total=මුළු: %d dashboard.statistic=සාරාංශය -dashboard.operations=නඩත්තු මෙහෙයුම් dashboard.system_status=පද්ධතියේ තත්වය dashboard.operation_name=මෙහෙයුමේ නම dashboard.operation_switch=මාරුවන්න diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index e48d84ff78..9234e9aa58 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -1647,7 +1647,6 @@ last_page=Sista total=Totalt: %d dashboard.statistic=Översikt -dashboard.operations=Operationer för underhåll dashboard.system_status=Status dashboard.operation_name=Operationsnamn dashboard.operation_switch=Byt till diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 5a5036f87d..119e1ef150 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -2687,7 +2687,6 @@ settings=Yönetici Ayarları dashboard.new_version_hint=Gitea %s şimdi hazır, %s çalıştırıyorsunuz. Ayrıntılar için blog'a bakabilirsiniz. dashboard.statistic=Özet -dashboard.operations=Bakım İşlemleri dashboard.system_status=Sistem Durumu dashboard.operation_name=İşlem Adı dashboard.operation_switch=Geç diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 09561a7902..e8a3acedda 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -2074,7 +2074,6 @@ last_page=Остання total=Разом: %d dashboard.statistic=Підсумок -dashboard.operations=Технічне обслуговування dashboard.system_status=Статус системи dashboard.operation_name=Назва операції dashboard.operation_switch=Перемкнути diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 406e9ac8f2..01058d48d2 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -2711,7 +2711,6 @@ settings=管理设置 dashboard.new_version_hint=Gitea %s 现已可用,您正在运行 %s。查看 博客 了解详情。 dashboard.statistic=摘要 -dashboard.operations=维护操作 dashboard.system_status=系统状态 dashboard.operation_name=操作名称 dashboard.operation_switch=开关 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 0511fa44ae..0447a7d8b7 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -2439,7 +2439,6 @@ total=總計:%d dashboard.new_version_hint=現已推出 Gitea %s,您正在執行 %s。詳情請參閱部落格的說明。 dashboard.statistic=摘要 -dashboard.operations=維護作業 dashboard.system_status=系統狀態 dashboard.operation_name=作業名稱 dashboard.operation_switch=開關 From b4825670596fe745cebdcc63a8ead4388602d42c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 2 Apr 2024 16:02:05 +0800 Subject: [PATCH 006/247] Add unique index for project_issue to prevent duplicate data (#30190) Fix #27639 --- .../project_issue.yml | 9 ++++ models/migrations/migrations.go | 5 ++ models/migrations/v1_23/main_test.go | 14 +++++ models/migrations/v1_23/v294.go | 53 +++++++++++++++++++ models/migrations/v1_23/v294_test.go | 52 ++++++++++++++++++ 5 files changed, 133 insertions(+) create mode 100644 models/migrations/fixtures/Test_AddUniqueIndexForProjectIssue/project_issue.yml create mode 100644 models/migrations/v1_23/main_test.go create mode 100644 models/migrations/v1_23/v294.go create mode 100644 models/migrations/v1_23/v294_test.go diff --git a/models/migrations/fixtures/Test_AddUniqueIndexForProjectIssue/project_issue.yml b/models/migrations/fixtures/Test_AddUniqueIndexForProjectIssue/project_issue.yml new file mode 100644 index 0000000000..6feaeb39f0 --- /dev/null +++ b/models/migrations/fixtures/Test_AddUniqueIndexForProjectIssue/project_issue.yml @@ -0,0 +1,9 @@ +- + id: 1 + project_id: 1 + issue_id: 1 + +- + id: 2 + project_id: 1 + issue_id: 1 diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 0daa799ff6..387cd96a53 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/models/migrations/v1_20" "code.gitea.io/gitea/models/migrations/v1_21" "code.gitea.io/gitea/models/migrations/v1_22" + "code.gitea.io/gitea/models/migrations/v1_23" "code.gitea.io/gitea/models/migrations/v1_6" "code.gitea.io/gitea/models/migrations/v1_7" "code.gitea.io/gitea/models/migrations/v1_8" @@ -572,6 +573,10 @@ var migrations = []Migration{ NewMigration("Ensure every project has exactly one default column - No Op", noopMigration), // v293 -> v294 NewMigration("Ensure every project has exactly one default column", v1_22.CheckProjectColumnsConsistency), + + // Gitea 1.22.0 ends at 294 + + NewMigration("Add unique index for project issue table", v1_23.AddUniqueIndexForProjectIssue), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_23/main_test.go b/models/migrations/v1_23/main_test.go new file mode 100644 index 0000000000..b7948bd4dd --- /dev/null +++ b/models/migrations/v1_23/main_test.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "testing" + + "code.gitea.io/gitea/models/migrations/base" +) + +func TestMain(m *testing.M) { + base.MainTest(m) +} diff --git a/models/migrations/v1_23/v294.go b/models/migrations/v1_23/v294.go new file mode 100644 index 0000000000..f2a54f6d23 --- /dev/null +++ b/models/migrations/v1_23/v294.go @@ -0,0 +1,53 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "fmt" + + "xorm.io/xorm" + "xorm.io/xorm/schemas" +) + +// AddUniqueIndexForProjectIssue adds unique indexes for project issue table +func AddUniqueIndexForProjectIssue(x *xorm.Engine) error { + // remove possible duplicated records in table project_issue + type result struct { + IssueID int64 + ProjectID int64 + Cnt int + } + var results []result + if err := x.Select("issue_id, project_id, count(*) as cnt"). + Table("project_issue"). + GroupBy("issue_id, project_id"). + Having("count(*) > 1"). + Find(&results); err != nil { + return err + } + for _, r := range results { + if x.Dialect().URI().DBType == schemas.MSSQL { + if _, err := x.Exec(fmt.Sprintf("delete from project_issue where id in (SELECT top %d id FROM project_issue WHERE issue_id = ? and project_id = ?)", r.Cnt-1), r.IssueID, r.ProjectID); err != nil { + return err + } + } else { + var ids []int64 + if err := x.SQL("SELECT id FROM project_issue WHERE issue_id = ? and project_id = ? limit ?", r.IssueID, r.ProjectID, r.Cnt-1).Find(&ids); err != nil { + return err + } + if _, err := x.Table("project_issue").In("id", ids).Delete(); err != nil { + return err + } + } + } + + // add unique index for project_issue table + type ProjectIssue struct { //revive:disable-line:exported + ID int64 `xorm:"pk autoincr"` + IssueID int64 `xorm:"INDEX unique(s)"` + ProjectID int64 `xorm:"INDEX unique(s)"` + } + + return x.Sync(new(ProjectIssue)) +} diff --git a/models/migrations/v1_23/v294_test.go b/models/migrations/v1_23/v294_test.go new file mode 100644 index 0000000000..d9a44ad866 --- /dev/null +++ b/models/migrations/v1_23/v294_test.go @@ -0,0 +1,52 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "slices" + "testing" + + "code.gitea.io/gitea/models/migrations/base" + + "github.com/stretchr/testify/assert" + "xorm.io/xorm/schemas" +) + +func Test_AddUniqueIndexForProjectIssue(t *testing.T) { + type ProjectIssue struct { //revive:disable-line:exported + ID int64 `xorm:"pk autoincr"` + IssueID int64 `xorm:"INDEX"` + ProjectID int64 `xorm:"INDEX"` + } + + // Prepare and load the testing database + x, deferable := base.PrepareTestEnv(t, 0, new(ProjectIssue)) + defer deferable() + if x == nil || t.Failed() { + return + } + + cnt, err := x.Table("project_issue").Where("project_id=1 AND issue_id=1").Count() + assert.NoError(t, err) + assert.EqualValues(t, 2, cnt) + + assert.NoError(t, AddUniqueIndexForProjectIssue(x)) + + cnt, err = x.Table("project_issue").Where("project_id=1 AND issue_id=1").Count() + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + tables, err := x.DBMetas() + assert.NoError(t, err) + assert.EqualValues(t, 1, len(tables)) + found := false + for _, index := range tables[0].Indexes { + if index.Type == schemas.UniqueType { + found = true + slices.Equal(index.Cols, []string{"project_id", "issue_id"}) + break + } + } + assert.True(t, found) +} From 944c76e78423405a33450eb3d07cd2b772f4a81c Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 2 Apr 2024 13:48:07 +0200 Subject: [PATCH 007/247] Fix spacing in issue navbar (#30238) Create a new `issue-navbar` class specifically for this bar, previous class used in many places and I thought I had them all removed, but not this one. Fixes: https://github.com/go-gitea/gitea/issues/30226 --- templates/repo/issue/choose.tmpl | 2 +- templates/repo/issue/labels.tmpl | 2 +- templates/repo/issue/milestone_new.tmpl | 2 +- web_src/css/modules/navbar.css | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/templates/repo/issue/choose.tmpl b/templates/repo/issue/choose.tmpl index a8037482be..38cf9e485f 100644 --- a/templates/repo/issue/choose.tmpl +++ b/templates/repo/issue/choose.tmpl @@ -3,7 +3,7 @@ {{template "repo/header" .}}
{{template "base/alert" .}} -
+ + + + + + + +
# repo1
+
+`, string(htm)) + + ctx, _ = contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) + htm, err = renderRepoFileCodePreview(ctx, markup.RenderCodePreviewOptions{ + FullURL: "http://full", + OwnerName: "user2", + RepoName: "repo1", + CommitID: "65f1bf27bc3bf70f64657658635e66094edbcb4d", + FilePath: "/README.md", + LineStart: 1, + }) + assert.NoError(t, err) + assert.Equal(t, `
+
+ /README.md + repo.code_preview_line_in:1,65f1bf27bc +
+ + + + + +
# repo1
+
+`, string(htm)) + + ctx, _ = contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) + _, err = renderRepoFileCodePreview(ctx, markup.RenderCodePreviewOptions{ + FullURL: "http://full", + OwnerName: "user15", + RepoName: "big_test_private_1", + CommitID: "65f1bf27bc3bf70f64657658635e66094edbcb4d", + FilePath: "/README.md", + LineStart: 1, + LineStop: 10, + }) + assert.ErrorContains(t, err, "no permission") +} diff --git a/templates/base/markup_codepreview.tmpl b/templates/base/markup_codepreview.tmpl new file mode 100644 index 0000000000..c65ab28406 --- /dev/null +++ b/templates/base/markup_codepreview.tmpl @@ -0,0 +1,25 @@ +
+
+ {{.FilePath}} + {{$link := HTMLFormat `%s` .RepoLink .CommitID (.CommitID | ShortSha) -}} + {{- if eq .LineStart .LineStop -}} + {{ctx.Locale.Tr "repo.code_preview_line_in" .LineStart $link}} + {{- else -}} + {{ctx.Locale.Tr "repo.code_preview_line_from_to" .LineStart .LineStop $link}} + {{- end}} +
+ + + {{- range $idx, $line := .HighlightLines -}} + + + {{- if $.EscapeStatus.Escaped -}} + {{- $lineEscapeStatus := index $.LineEscapeStatus $idx -}} + + {{- end}} + + + {{- end -}} + +
{{if $lineEscapeStatus.Escaped}}{{end}}{{$line.FormattedContent}}
+
diff --git a/web_src/css/base.css b/web_src/css/base.css index 96c90ee692..05ddba3223 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -1186,10 +1186,13 @@ overflow-menu .ui.label { content: attr(data-line-number); line-height: 20px !important; padding: 0 10px; - cursor: pointer; display: block; } +.code-view .lines-num span::after { + cursor: pointer; +} + .lines-type-marker { vertical-align: top; } diff --git a/web_src/css/index.css b/web_src/css/index.css index 40b1d3c881..7be8065dc7 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -41,6 +41,7 @@ @import "./markup/content.css"; @import "./markup/codecopy.css"; +@import "./markup/codepreview.css"; @import "./markup/asciicast.css"; @import "./chroma/base.css"; diff --git a/web_src/css/markup/codepreview.css b/web_src/css/markup/codepreview.css new file mode 100644 index 0000000000..9219544993 --- /dev/null +++ b/web_src/css/markup/codepreview.css @@ -0,0 +1,36 @@ +.markup .code-preview-container { + border: 1px solid var(--color-secondary); + border-radius: var(--border-radius); + margin: 0.25em 0; +} + +.markup .code-preview-container .code-preview-header { + border-bottom: 1px solid var(--color-secondary); + padding: 0.5em; + font-size: 12px; +} + +.markup .code-preview-container table { + width: 100%; + max-height: 100px; + overflow-y: auto; + margin: 0; /* override ".markup table {margin}" */ +} + +/* workaround to hide empty p before container - more details are in "html_codepreview.go" */ +.markup p:empty:has(+ .code-preview-container) { + display: none; +} + +/* override the polluted styles from the content.css: ".markup table ..." */ +.markup .code-preview-container table tr { + border: 0 !important; +} +.markup .code-preview-container table th, +.markup .code-preview-container table td { + border: 0 !important; + padding: 0 0 0 5px !important; +} +.markup .code-preview-container table tr:nth-child(2n) { + background: none !important; +} diff --git a/web_src/css/markup/content.css b/web_src/css/markup/content.css index 5eeef078a5..376d3030c7 100644 --- a/web_src/css/markup/content.css +++ b/web_src/css/markup/content.css @@ -382,7 +382,7 @@ text-align: center; } -.markup span.align-center span img +.markup span.align-center span img, .markup span.align-center span video { margin: 0 auto; text-align: center; @@ -432,7 +432,7 @@ text-align: right; } -.markup code, +.markup code:not(.code-inner), .markup tt { padding: 0.2em 0.4em; margin: 0; From e006451ab1509f8d6d43c5974387c05b26517392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Tiago?= <114936010+jmlt2002@users.noreply.github.com> Date: Tue, 2 Apr 2024 19:15:40 +0100 Subject: [PATCH 010/247] Fixes #27605: inline math blocks can't be preceeded/followed by alphanumerical characters (#30175) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Inline math blocks couldn't be preceeded or succeeded by alphanumerical characters due to changes introduced in PR #21171. Removed the condition that caused this (precedingCharacter condition) and added a new exit condition of the for-loop that checks if a specific '$' was escaped using '\' so that the math expression can be rendered as intended. - Additionally this PR fixes another bug where math blocks of the type '$xyz$abc$' where the dollar sign was not escaped by the user, generated an error (shown in the screenshots below) - Altered the tests to accomodate for the changes Former behaviour (from try.gitea.io): ![image](https://github.com/go-gitea/gitea/assets/114936010/8f0cbb21-321d-451c-b871-c67a8e1e9235) Fixed behaviour (from my local build): ![image](https://github.com/go-gitea/gitea/assets/114936010/5c22687c-6f11-4407-b5e7-c14b838bc20d) (Edit) Source code for the README.md file: ``` $x$ -$x$ $x$- a$xa$ $xa$a 1$xb$ $xb$1 $a a$b b$ a$b $a a$b b$ $a a\$b b$ ``` --------- Signed-off-by: João Tiago Co-authored-by: Giteabot --- modules/markup/markdown/markdown_test.go | 20 +++++++++++++++++-- modules/markup/markdown/math/inline_parser.go | 18 ++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index c664758a27..a9c9024982 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -511,9 +511,17 @@ func TestMathBlock(t *testing.T) { `\(a\) \(b\)`, `

a b

` + nl, }, + { + `$a$.`, + `

a.

` + nl, + }, + { + `.$a$`, + `

.$a$

` + nl, + }, { `$a a$b b$`, - `

a a$b b

` + nl, + `

$a a$b b$

` + nl, }, { `a a$b b`, @@ -521,7 +529,15 @@ func TestMathBlock(t *testing.T) { }, { `a$b $a a$b b$`, - `

a$b a a$b b

` + nl, + `

a$b $a a$b b$

` + nl, + }, + { + "a$x$", + `

a$x$

` + nl, + }, + { + "$x$a", + `

$x$a

` + nl, }, { "$$a$$", diff --git a/modules/markup/markdown/math/inline_parser.go b/modules/markup/markdown/math/inline_parser.go index 0ac25c2b2a..862234e69b 100644 --- a/modules/markup/markdown/math/inline_parser.go +++ b/modules/markup/markdown/math/inline_parser.go @@ -41,9 +41,12 @@ func (parser *inlineParser) Trigger() []byte { return parser.start[0:1] } +func isPunctuation(b byte) bool { + return b == '.' || b == '!' || b == '?' || b == ',' || b == ';' || b == ':' +} + func isAlphanumeric(b byte) bool { - // Github only cares about 0-9A-Za-z - return (b >= '0' && b <= '9') || (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z') + return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') } // Parse parses the current line and returns a result of parsing. @@ -56,7 +59,7 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. } precedingCharacter := block.PrecendingCharacter() - if precedingCharacter < 256 && isAlphanumeric(byte(precedingCharacter)) { + if precedingCharacter < 256 && (isAlphanumeric(byte(precedingCharacter)) || isPunctuation(byte(precedingCharacter))) { // need to exclude things like `a$` from being considered a start return nil } @@ -75,14 +78,19 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. ender += pos // Now we want to check the character at the end of our parser section - // that is ender + len(parser.end) + // that is ender + len(parser.end) and check if char before ender is '\' pos = ender + len(parser.end) if len(line) <= pos { break } - if !isAlphanumeric(line[pos]) { + suceedingCharacter := line[pos] + if !isPunctuation(suceedingCharacter) && !(suceedingCharacter == ' ') { + return nil + } + if line[ender-1] != '\\' { break } + // move the pointer onwards ender += len(parser.end) } From 6f4e2e79ffd1a244e9c266db19840a5bfda09119 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 3 Apr 2024 03:44:15 +0200 Subject: [PATCH 011/247] Show 12 lines in markup code preview (#30255) Show up to 12 lines instead of previous 5. --- web_src/css/markup/codepreview.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/css/markup/codepreview.css b/web_src/css/markup/codepreview.css index 9219544993..c9d19f5cc8 100644 --- a/web_src/css/markup/codepreview.css +++ b/web_src/css/markup/codepreview.css @@ -12,7 +12,7 @@ .markup .code-preview-container table { width: 100%; - max-height: 100px; + max-height: 240px; /* 12 lines at 20px per line */ overflow-y: auto; margin: 0; /* override ".markup table {margin}" */ } From b28d3a4218b1338ce6f683d11993081b722bae0a Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Tue, 2 Apr 2024 19:47:13 -0600 Subject: [PATCH 012/247] Add -u git to docs when using docker exec with root installation (#29314) This fixes a minor issue in the documentation for SSH Container Passthrough for non-rootless installs. The non-rootless Dockerfile and docker-compose do not set `USER`/`user` instructions so `docker exec` will run as root by default. While running as root, gitea commands will refuse to execute, breaking these approaches. For containers built with the rootless instructions, `docker exec` will run as git by default so this is not necessary in that case. This issue was already discussed in #19065, but it does not appear this part of the issue was ever added to the documentation. --- docs/content/installation/with-docker.en-us.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/installation/with-docker.en-us.md b/docs/content/installation/with-docker.en-us.md index e67f5bccb2..e8a80f7c96 100644 --- a/docs/content/installation/with-docker.en-us.md +++ b/docs/content/installation/with-docker.en-us.md @@ -545,7 +545,7 @@ In this option, the idea is that the host SSH uses an `AuthorizedKeysCommand` in ```bash cat <<"EOF" | sudo tee /home/git/docker-shell #!/bin/sh - /usr/bin/docker exec -i --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@" + /usr/bin/docker exec -i -u git --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@" EOF sudo chmod +x /home/git/docker-shell sudo usermod -s /home/git/docker-shell git @@ -560,7 +560,7 @@ Add the following block to `/etc/ssh/sshd_config`, on the host: ```bash Match User git AuthorizedKeysCommandUser git - AuthorizedKeysCommand /usr/bin/docker exec -i gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k + AuthorizedKeysCommand /usr/bin/docker exec -i -u git gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k ``` (From 1.16.0 you will not need to set the `-c /data/gitea/conf/app.ini` option.) From 654cfd1dfbd3f3f1d94addee50b6fe2b018a49c3 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 3 Apr 2024 10:16:46 +0800 Subject: [PATCH 013/247] Refactor "dump" sub-command (#30240) Major changes: * Move some functions like "addReader" / "isSubDir" / "addRecursiveExclude" to a separate package, and add tests * Clarify the filename&dump type logic and add tests * Clarify the logger behavior and remove FIXME comments Co-authored-by: Giteabot --- cmd/dump.go | 296 ++++++++-------------------------- modules/dump/dumper.go | 174 ++++++++++++++++++++ modules/dump/dumper_test.go | 113 +++++++++++++ modules/setting/log.go | 9 ++ modules/timeutil/timestamp.go | 3 +- modules/util/util.go | 8 + 6 files changed, 374 insertions(+), 229 deletions(-) create mode 100644 modules/dump/dumper.go create mode 100644 modules/dump/dumper_test.go diff --git a/cmd/dump.go b/cmd/dump.go index 69ecdcec12..da0a51d9ce 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -6,14 +6,13 @@ package cmd import ( "fmt" - "io" "os" "path" "path/filepath" "strings" - "time" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/dump" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -25,89 +24,17 @@ import ( "github.com/urfave/cli/v2" ) -func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error { - if verbose { - log.Info("Adding file %s", customName) - } - - return w.Write(archiver.File{ - FileInfo: archiver.FileInfo{ - FileInfo: info, - CustomName: customName, - }, - ReadCloser: r, - }) -} - -func addFile(w archiver.Writer, filePath, absPath string, verbose bool) error { - file, err := os.Open(absPath) - if err != nil { - return err - } - defer file.Close() - fileInfo, err := file.Stat() - if err != nil { - return err - } - - return addReader(w, file, fileInfo, filePath, verbose) -} - -func isSubdir(upper, lower string) (bool, error) { - if relPath, err := filepath.Rel(upper, lower); err != nil { - return false, err - } else if relPath == "." || !strings.HasPrefix(relPath, ".") { - return true, nil - } - return false, nil -} - -type outputType struct { - Enum []string - Default string - selected string -} - -func (o outputType) Join() string { - return strings.Join(o.Enum, ", ") -} - -func (o *outputType) Set(value string) error { - for _, enum := range o.Enum { - if enum == value { - o.selected = value - return nil - } - } - - return fmt.Errorf("allowed values are %s", o.Join()) -} - -func (o outputType) String() string { - if o.selected == "" { - return o.Default - } - return o.selected -} - -var outputTypeEnum = &outputType{ - Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4", "tar.zst"}, - Default: "zip", -} - // CmdDump represents the available dump sub-command. var CmdDump = &cli.Command{ - Name: "dump", - Usage: "Dump Gitea files and database", - Description: `Dump compresses all related files and database into zip file. -It can be used for backup and capture Gitea server image to send to maintainer`, - Action: runDump, + Name: "dump", + Usage: "Dump Gitea files and database", + Description: `Dump compresses all related files and database into zip file. It can be used for backup and capture Gitea server image to send to maintainer`, + Action: runDump, Flags: []cli.Flag{ &cli.StringFlag{ Name: "file", Aliases: []string{"f"}, - Value: fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix()), - Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.", + Usage: `Name of the dump file which will be created, default to "gitea-dump-{time}.zip". Supply '-' for stdout. See type for available types.`, }, &cli.BoolFlag{ Name: "verbose", @@ -160,64 +87,52 @@ It can be used for backup and capture Gitea server image to send to maintainer`, Name: "skip-index", Usage: "Skip bleve index data", }, - &cli.GenericFlag{ + &cli.StringFlag{ Name: "type", - Value: outputTypeEnum, - Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()), + Usage: fmt.Sprintf(`Dump output format, default to "zip", supported types: %s`, strings.Join(dump.SupportedOutputTypes, ", ")), }, }, } func fatal(format string, args ...any) { - fmt.Fprintf(os.Stderr, format+"\n", args...) log.Fatal(format, args...) } func runDump(ctx *cli.Context) error { - var file *os.File - fileName := ctx.String("file") - outType := ctx.String("type") - if fileName == "-" { - file = os.Stdout - setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr) - } else { - for _, suffix := range outputTypeEnum.Enum { - if strings.HasSuffix(fileName, "."+suffix) { - fileName = strings.TrimSuffix(fileName, "."+suffix) - break - } - } - fileName += "." + outType - } setting.MustInstalled() - // make sure we are logging to the console no matter what the configuration tells us do to - // FIXME: don't use CfgProvider directly - if _, err := setting.CfgProvider.Section("log").NewKey("MODE", "console"); err != nil { - fatal("Setting logging mode to console failed: %v", err) - } - if _, err := setting.CfgProvider.Section("log.console").NewKey("STDERR", "true"); err != nil { - fatal("Setting console logger to stderr failed: %v", err) - } - - // Set loglevel to Warn if quiet-mode is requested - if ctx.Bool("quiet") { - if _, err := setting.CfgProvider.Section("log.console").NewKey("LEVEL", "Warn"); err != nil { - fatal("Setting console log-level failed: %v", err) - } - } - - if !setting.InstallLock { - log.Error("Is '%s' really the right config path?\n", setting.CustomConf) - return fmt.Errorf("gitea is not initialized") - } - setting.LoadSettings() // cannot access session settings otherwise - + quite := ctx.Bool("quiet") verbose := ctx.Bool("verbose") - if verbose && ctx.Bool("quiet") { - return fmt.Errorf("--quiet and --verbose cannot both be set") + if verbose && quite { + fatal("Option --quiet and --verbose cannot both be set") } + // outFileName is either "-" or a file name (will be made absolute) + outFileName, outType := dump.PrepareFileNameAndType(ctx.String("file"), ctx.String("type")) + if outType == "" { + fatal("Invalid output type") + } + + outFile := os.Stdout + if outFileName != "-" { + var err error + if outFileName, err = filepath.Abs(outFileName); err != nil { + fatal("Unable to get absolute path of dump file: %v", err) + } + if exist, _ := util.IsExist(outFileName); exist { + fatal("Dump file %q exists", outFileName) + } + if outFile, err = os.Create(outFileName); err != nil { + fatal("Unable to create dump file %q: %v", outFileName, err) + } + defer outFile.Close() + } + + setupConsoleLogger(util.Iif(quite, log.WARN, log.INFO), log.CanColorStderr, os.Stderr) + + setting.DisableLoggerInit() + setting.LoadSettings() // cannot access session settings otherwise + stdCtx, cancel := installSignals() defer cancel() @@ -226,44 +141,32 @@ func runDump(ctx *cli.Context) error { return err } - if err := storage.Init(); err != nil { + if err = storage.Init(); err != nil { return err } - if file == nil { - file, err = os.Create(fileName) - if err != nil { - fatal("Unable to open %s: %v", fileName, err) - } - } - defer file.Close() - - absFileName, err := filepath.Abs(fileName) - if err != nil { - return err - } - - var iface any - if fileName == "-" { - iface, err = archiver.ByExtension(fmt.Sprintf(".%s", outType)) - } else { - iface, err = archiver.ByExtension(fileName) - } + archiverGeneric, err := archiver.ByExtension("." + outType) if err != nil { fatal("Unable to get archiver for extension: %v", err) } - w, _ := iface.(archiver.Writer) - if err := w.Create(file); err != nil { + archiverWriter := archiverGeneric.(archiver.Writer) + if err := archiverWriter.Create(outFile); err != nil { fatal("Creating archiver.Writer failed: %v", err) } - defer w.Close() + defer archiverWriter.Close() + + dumper := &dump.Dumper{ + Writer: archiverWriter, + Verbose: verbose, + } + dumper.GlobalExcludeAbsPath(outFileName) if ctx.IsSet("skip-repository") && ctx.Bool("skip-repository") { log.Info("Skip dumping local repositories") } else { log.Info("Dumping local repositories... %s", setting.RepoRootPath) - if err := addRecursiveExclude(w, "repos", setting.RepoRootPath, []string{absFileName}, verbose); err != nil { + if err := dumper.AddRecursiveExclude("repos", setting.RepoRootPath, nil); err != nil { fatal("Failed to include repositories: %v", err) } @@ -276,8 +179,7 @@ func runDump(ctx *cli.Context) error { if err != nil { return err } - - return addReader(w, object, info, path.Join("data", "lfs", objPath), verbose) + return dumper.AddReader(object, info, path.Join("data", "lfs", objPath)) }); err != nil { fatal("Failed to dump LFS objects: %v", err) } @@ -310,15 +212,13 @@ func runDump(ctx *cli.Context) error { fatal("Failed to dump database: %v", err) } - if err := addFile(w, "gitea-db.sql", dbDump.Name(), verbose); err != nil { + if err = dumper.AddFile("gitea-db.sql", dbDump.Name()); err != nil { fatal("Failed to include gitea-db.sql: %v", err) } - if len(setting.CustomConf) > 0 { - log.Info("Adding custom configuration file from %s", setting.CustomConf) - if err := addFile(w, "app.ini", setting.CustomConf, verbose); err != nil { - fatal("Failed to include specified app.ini: %v", err) - } + log.Info("Adding custom configuration file from %s", setting.CustomConf) + if err = dumper.AddFile("app.ini", setting.CustomConf); err != nil { + fatal("Failed to include specified app.ini: %v", err) } if ctx.IsSet("skip-custom-dir") && ctx.Bool("skip-custom-dir") { @@ -326,8 +226,8 @@ func runDump(ctx *cli.Context) error { } else { customDir, err := os.Stat(setting.CustomPath) if err == nil && customDir.IsDir() { - if is, _ := isSubdir(setting.AppDataPath, setting.CustomPath); !is { - if err := addRecursiveExclude(w, "custom", setting.CustomPath, []string{absFileName}, verbose); err != nil { + if is, _ := dump.IsSubdir(setting.AppDataPath, setting.CustomPath); !is { + if err := dumper.AddRecursiveExclude("custom", setting.CustomPath, nil); err != nil { fatal("Failed to include custom: %v", err) } } else { @@ -364,8 +264,7 @@ func runDump(ctx *cli.Context) error { excludes = append(excludes, setting.Attachment.Storage.Path) excludes = append(excludes, setting.Packages.Storage.Path) excludes = append(excludes, setting.Log.RootPath) - excludes = append(excludes, absFileName) - if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil { + if err := dumper.AddRecursiveExclude("data", setting.AppDataPath, excludes); err != nil { fatal("Failed to include data directory: %v", err) } } @@ -377,8 +276,7 @@ func runDump(ctx *cli.Context) error { if err != nil { return err } - - return addReader(w, object, info, path.Join("data", "attachments", objPath), verbose) + return dumper.AddReader(object, info, path.Join("data", "attachments", objPath)) }); err != nil { fatal("Failed to dump attachments: %v", err) } @@ -392,8 +290,7 @@ func runDump(ctx *cli.Context) error { if err != nil { return err } - - return addReader(w, object, info, path.Join("data", "packages", objPath), verbose) + return dumper.AddReader(object, info, path.Join("data", "packages", objPath)) }); err != nil { fatal("Failed to dump packages: %v", err) } @@ -409,80 +306,23 @@ func runDump(ctx *cli.Context) error { log.Error("Unable to check if %s exists. Error: %v", setting.Log.RootPath, err) } if isExist { - if err := addRecursiveExclude(w, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil { + if err := dumper.AddRecursiveExclude("log", setting.Log.RootPath, nil); err != nil { fatal("Failed to include log: %v", err) } } } - if fileName != "-" { - if err = w.Close(); err != nil { - _ = util.Remove(fileName) - fatal("Failed to save %s: %v", fileName, err) + if outFileName == "-" { + log.Info("Finish dumping to stdout") + } else { + if err = archiverWriter.Close(); err != nil { + _ = os.Remove(outFileName) + fatal("Failed to save %q: %v", outFileName, err) } - - if err := os.Chmod(fileName, 0o600); err != nil { + if err = os.Chmod(outFileName, 0o600); err != nil { log.Info("Can't change file access permissions mask to 0600: %v", err) } - } - - if fileName != "-" { - log.Info("Finish dumping in file %s", fileName) - } else { - log.Info("Finish dumping to stdout") - } - - return nil -} - -// addRecursiveExclude zips absPath to specified insidePath inside writer excluding excludeAbsPath -func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeAbsPath []string, verbose bool) error { - absPath, err := filepath.Abs(absPath) - if err != nil { - return err - } - dir, err := os.Open(absPath) - if err != nil { - return err - } - defer dir.Close() - - files, err := dir.Readdir(0) - if err != nil { - return err - } - for _, file := range files { - currentAbsPath := filepath.Join(absPath, file.Name()) - currentInsidePath := path.Join(insidePath, file.Name()) - if file.IsDir() { - if !util.SliceContainsString(excludeAbsPath, currentAbsPath) { - if err := addFile(w, currentInsidePath, currentAbsPath, false); err != nil { - return err - } - if err = addRecursiveExclude(w, currentInsidePath, currentAbsPath, excludeAbsPath, verbose); err != nil { - return err - } - } - } else { - // only copy regular files and symlink regular files, skip non-regular files like socket/pipe/... - shouldAdd := file.Mode().IsRegular() - if !shouldAdd && file.Mode()&os.ModeSymlink == os.ModeSymlink { - target, err := filepath.EvalSymlinks(currentAbsPath) - if err != nil { - return err - } - targetStat, err := os.Stat(target) - if err != nil { - return err - } - shouldAdd = targetStat.Mode().IsRegular() - } - if shouldAdd { - if err = addFile(w, currentInsidePath, currentAbsPath, verbose); err != nil { - return err - } - } - } + log.Info("Finish dumping in file %s", outFileName) } return nil } diff --git a/modules/dump/dumper.go b/modules/dump/dumper.go new file mode 100644 index 0000000000..47730851fb --- /dev/null +++ b/modules/dump/dumper.go @@ -0,0 +1,174 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package dump + +import ( + "fmt" + "io" + "os" + "path" + "path/filepath" + "slices" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + + "github.com/mholt/archiver/v3" +) + +var SupportedOutputTypes = []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4", "tar.zst"} + +// PrepareFileNameAndType prepares the output file name and type, if the type is not supported, it returns an empty "outType" +func PrepareFileNameAndType(argFile, argType string) (outFileName, outType string) { + if argFile == "" && argType == "" { + outType = SupportedOutputTypes[0] + outFileName = fmt.Sprintf("gitea-dump-%d.%s", timeutil.TimeStampNow(), outType) + } else if argFile == "" { + outType = argType + outFileName = fmt.Sprintf("gitea-dump-%d.%s", timeutil.TimeStampNow(), outType) + } else if argType == "" { + if filepath.Ext(outFileName) == "" { + outType = SupportedOutputTypes[0] + outFileName = argFile + } else { + for _, t := range SupportedOutputTypes { + if strings.HasSuffix(argFile, "."+t) { + outFileName = argFile + outType = t + } + } + } + } else { + outFileName, outType = argFile, argType + } + if !slices.Contains(SupportedOutputTypes, outType) { + return "", "" + } + return outFileName, outType +} + +func IsSubdir(upper, lower string) (bool, error) { + if relPath, err := filepath.Rel(upper, lower); err != nil { + return false, err + } else if relPath == "." || !strings.HasPrefix(relPath, ".") { + return true, nil + } + return false, nil +} + +type Dumper struct { + Writer archiver.Writer + Verbose bool + + globalExcludeAbsPaths []string +} + +func (dumper *Dumper) AddReader(r io.ReadCloser, info os.FileInfo, customName string) error { + if dumper.Verbose { + log.Info("Adding file %s", customName) + } + + return dumper.Writer.Write(archiver.File{ + FileInfo: archiver.FileInfo{ + FileInfo: info, + CustomName: customName, + }, + ReadCloser: r, + }) +} + +func (dumper *Dumper) AddFile(filePath, absPath string) error { + file, err := os.Open(absPath) + if err != nil { + return err + } + defer file.Close() + fileInfo, err := file.Stat() + if err != nil { + return err + } + return dumper.AddReader(file, fileInfo, filePath) +} + +func (dumper *Dumper) normalizeFilePath(absPath string) string { + absPath = filepath.Clean(absPath) + if setting.IsWindows { + absPath = strings.ToLower(absPath) + } + return absPath +} + +func (dumper *Dumper) GlobalExcludeAbsPath(absPaths ...string) { + for _, absPath := range absPaths { + dumper.globalExcludeAbsPaths = append(dumper.globalExcludeAbsPaths, dumper.normalizeFilePath(absPath)) + } +} + +func (dumper *Dumper) shouldExclude(absPath string, excludes []string) bool { + norm := dumper.normalizeFilePath(absPath) + return slices.Contains(dumper.globalExcludeAbsPaths, norm) || slices.Contains(excludes, norm) +} + +func (dumper *Dumper) AddRecursiveExclude(insidePath, absPath string, excludes []string) error { + excludes = slices.Clone(excludes) + for i := range excludes { + excludes[i] = dumper.normalizeFilePath(excludes[i]) + } + return dumper.addFileOrDir(insidePath, absPath, excludes) +} + +func (dumper *Dumper) addFileOrDir(insidePath, absPath string, excludes []string) error { + absPath, err := filepath.Abs(absPath) + if err != nil { + return err + } + dir, err := os.Open(absPath) + if err != nil { + return err + } + defer dir.Close() + + files, err := dir.Readdir(0) + if err != nil { + return err + } + for _, file := range files { + currentAbsPath := filepath.Join(absPath, file.Name()) + if dumper.shouldExclude(currentAbsPath, excludes) { + continue + } + + currentInsidePath := path.Join(insidePath, file.Name()) + if file.IsDir() { + if err := dumper.AddFile(currentInsidePath, currentAbsPath); err != nil { + return err + } + if err = dumper.addFileOrDir(currentInsidePath, currentAbsPath, excludes); err != nil { + return err + } + } else { + // only copy regular files and symlink regular files, skip non-regular files like socket/pipe/... + shouldAdd := file.Mode().IsRegular() + if !shouldAdd && file.Mode()&os.ModeSymlink == os.ModeSymlink { + target, err := filepath.EvalSymlinks(currentAbsPath) + if err != nil { + return err + } + targetStat, err := os.Stat(target) + if err != nil { + return err + } + shouldAdd = targetStat.Mode().IsRegular() + } + if shouldAdd { + if err = dumper.AddFile(currentInsidePath, currentAbsPath); err != nil { + return err + } + } + } + } + return nil +} diff --git a/modules/dump/dumper_test.go b/modules/dump/dumper_test.go new file mode 100644 index 0000000000..b444fa2de5 --- /dev/null +++ b/modules/dump/dumper_test.go @@ -0,0 +1,113 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package dump + +import ( + "fmt" + "io" + "os" + "path/filepath" + "sort" + "testing" + "time" + + "code.gitea.io/gitea/modules/timeutil" + + "github.com/mholt/archiver/v3" + "github.com/stretchr/testify/assert" +) + +func TestPrepareFileNameAndType(t *testing.T) { + defer timeutil.MockSet(time.Unix(1234, 0))() + test := func(argFile, argType, expFile, expType string) { + outFile, outType := PrepareFileNameAndType(argFile, argType) + assert.Equal(t, + fmt.Sprintf("outFile=%s, outType=%s", expFile, expType), + fmt.Sprintf("outFile=%s, outType=%s", outFile, outType), + fmt.Sprintf("argFile=%s, argType=%s", argFile, argType), + ) + } + + test("", "", "gitea-dump-1234.zip", "zip") + test("", "tar.gz", "gitea-dump-1234.tar.gz", "tar.gz") + test("", "no-such", "", "") + + test("-", "", "-", "zip") + test("-", "tar.gz", "-", "tar.gz") + test("-", "no-such", "", "") + + test("a", "", "a", "zip") + test("a", "tar.gz", "a", "tar.gz") + test("a", "no-such", "", "") + + test("a.zip", "", "a.zip", "zip") + test("a.zip", "tar.gz", "a.zip", "tar.gz") + test("a.zip", "no-such", "", "") + + test("a.tar.gz", "", "a.tar.gz", "zip") + test("a.tar.gz", "tar.gz", "a.tar.gz", "tar.gz") + test("a.tar.gz", "no-such", "", "") +} + +func TestIsSubDir(t *testing.T) { + tmpDir := t.TempDir() + _ = os.MkdirAll(filepath.Join(tmpDir, "include/sub"), 0o755) + + isSub, err := IsSubdir(filepath.Join(tmpDir, "include"), filepath.Join(tmpDir, "include")) + assert.NoError(t, err) + assert.True(t, isSub) + + isSub, err = IsSubdir(filepath.Join(tmpDir, "include"), filepath.Join(tmpDir, "include/sub")) + assert.NoError(t, err) + assert.True(t, isSub) + + isSub, err = IsSubdir(filepath.Join(tmpDir, "include/sub"), filepath.Join(tmpDir, "include")) + assert.NoError(t, err) + assert.False(t, isSub) +} + +type testWriter struct { + added []string +} + +func (t *testWriter) Create(out io.Writer) error { + return nil +} + +func (t *testWriter) Write(f archiver.File) error { + t.added = append(t.added, f.Name()) + return nil +} + +func (t *testWriter) Close() error { + return nil +} + +func TestDumper(t *testing.T) { + sortStrings := func(s []string) []string { + sort.Strings(s) + return s + } + tmpDir := t.TempDir() + _ = os.MkdirAll(filepath.Join(tmpDir, "include/exclude1"), 0o755) + _ = os.MkdirAll(filepath.Join(tmpDir, "include/exclude2"), 0o755) + _ = os.MkdirAll(filepath.Join(tmpDir, "include/sub"), 0o755) + _ = os.WriteFile(filepath.Join(tmpDir, "include/a"), nil, 0o644) + _ = os.WriteFile(filepath.Join(tmpDir, "include/sub/b"), nil, 0o644) + _ = os.WriteFile(filepath.Join(tmpDir, "include/exclude1/a-1"), nil, 0o644) + _ = os.WriteFile(filepath.Join(tmpDir, "include/exclude2/a-2"), nil, 0o644) + + tw := &testWriter{} + d := &Dumper{Writer: tw} + d.GlobalExcludeAbsPath(filepath.Join(tmpDir, "include/exclude1")) + err := d.AddRecursiveExclude("include", filepath.Join(tmpDir, "include"), []string{filepath.Join(tmpDir, "include/exclude2")}) + assert.NoError(t, err) + assert.EqualValues(t, sortStrings([]string{"include/a", "include/sub", "include/sub/b"}), sortStrings(tw.added)) + + tw = &testWriter{} + d = &Dumper{Writer: tw} + err = d.AddRecursiveExclude("include", filepath.Join(tmpDir, "include"), nil) + assert.NoError(t, err) + assert.EqualValues(t, sortStrings([]string{"include/exclude2", "include/exclude2/a-2", "include/a", "include/sub", "include/sub/b", "include/exclude1", "include/exclude1/a-1"}), sortStrings(tw.added)) +} diff --git a/modules/setting/log.go b/modules/setting/log.go index e404074b72..50c5779994 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -185,8 +185,13 @@ func InitLoggersForTest() { initAllLoggers() } +var initLoggerDisabled bool + // initAllLoggers creates all the log services func initAllLoggers() { + if initLoggerDisabled { + return + } initManagedLoggers(log.GetManager(), CfgProvider) golog.SetFlags(0) @@ -194,6 +199,10 @@ func initAllLoggers() { golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info)) } +func DisableLoggerInit() { + initLoggerDisabled = true +} + func initManagedLoggers(manager *log.LoggerManager, cfg ConfigProvider) { loadLogGlobalFrom(cfg) prepareLoggerConfig(cfg) diff --git a/modules/timeutil/timestamp.go b/modules/timeutil/timestamp.go index 27a80b6682..e77652b24f 100644 --- a/modules/timeutil/timestamp.go +++ b/modules/timeutil/timestamp.go @@ -21,8 +21,9 @@ var ( ) // MockSet sets the time to a mocked time.Time -func MockSet(now time.Time) { +func MockSet(now time.Time) func() { mockNow = now + return MockUnset } // MockUnset will unset the mocked time.Time diff --git a/modules/util/util.go b/modules/util/util.go index b6e730eb54..3921002e2a 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -213,6 +213,14 @@ func ToPointer[T any](val T) *T { return &val } +// Iif is an "inline-if", it returns "trueVal" if "condition" is true, otherwise "falseVal" +func Iif[T comparable](condition bool, trueVal, falseVal T) T { + if condition { + return trueVal + } + return falseVal +} + // IfZero returns "def" if "v" is a zero value, otherwise "v" func IfZero[T comparable](v, def T) T { var zero T From 1195be41a13d2198ab644c8558549edd74485510 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 3 Apr 2024 11:15:06 +0200 Subject: [PATCH 014/247] Replace coloris with vanilla-colorful (#30201) Found [a better color picker](https://github.com/web-padawan/vanilla-colorful) that [does not rely](https://github.com/mdbassit/Coloris/issues/139) on `querySelectorAll` or a global shared instance, and is also around a third of the size of the previous one. The popover is handled by tippy.js for which I introduced a new "bare" theme and it uses a new sibling-based mechanism which should prove useful later to create tippy popovers via HTML only. Screenshot 2024-03-31 at 04 03 38 --- package-lock.json | 12 +-- package.json | 2 +- web_src/css/features/colorpicker.css | 141 +++------------------------ web_src/css/modules/tippy.css | 11 +++ web_src/js/features/colorpicker.js | 85 +++++++++++----- web_src/js/modules/tippy.js | 7 +- 6 files changed, 94 insertions(+), 164 deletions(-) diff --git a/package-lock.json b/package-lock.json index 21de79387f..a5f7a09ed0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "@github/relative-time-element": "4.4.0", "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@melloware/coloris": "0.23.0", "@primer/octicons": "19.9.0", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", @@ -54,6 +53,7 @@ "toastify-js": "1.12.0", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", + "vanilla-colorful": "0.7.2", "vue": "3.4.21", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.0", @@ -1290,11 +1290,6 @@ "@mcaptcha/core-glue": "^0.1.0-alpha-5" } }, - "node_modules/@melloware/coloris": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@melloware/coloris/-/coloris-0.23.0.tgz", - "integrity": "sha512-VGIjI9+IQwg6BHjIE10yl0K2ARYz5bsjn6BgFEs1y1ErPAQymgdoxwVcSVL4Ai5t9OVs8xaCB7JKHqFu2N96Ow==" - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -11853,6 +11848,11 @@ "builtins": "^1.0.3" } }, + "node_modules/vanilla-colorful": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/vanilla-colorful/-/vanilla-colorful-0.7.2.tgz", + "integrity": "sha512-z2YZusTFC6KnLERx1cgoIRX2CjPRP0W75N+3CC6gbvdX5Ch47rZkEMGO2Xnf+IEmi3RiFLxS18gayMA27iU7Kg==" + }, "node_modules/vite": { "version": "5.2.6", "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", diff --git a/package.json b/package.json index beea0e5d86..004ac9e2bf 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "@github/relative-time-element": "4.4.0", "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@melloware/coloris": "0.23.0", "@primer/octicons": "19.9.0", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", @@ -53,6 +52,7 @@ "toastify-js": "1.12.0", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", + "vanilla-colorful": "0.7.2", "vue": "3.4.21", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.0", diff --git a/web_src/css/features/colorpicker.css b/web_src/css/features/colorpicker.css index 0c651cfeb3..b7436783df 100644 --- a/web_src/css/features/colorpicker.css +++ b/web_src/css/features/colorpicker.css @@ -1,10 +1,6 @@ -/* This is a stripped-down version of coloris's CSS tailored to our needs. It does only include - opaqua colors, and if more features like opacity are needed, the CSS needs to be extended - based on upstream: https://github.com/mdbassit/Coloris/blob/main/src/coloris.css. */ - .js-color-picker-input { display: flex; - flex-wrap: wrap; + position: relative; } .js-color-picker-input input { @@ -13,152 +9,39 @@ padding-left: 32px !important; } -.clr-picker { - display: none; - flex-wrap: wrap; - position: absolute; - width: 200px; - z-index: 1002; /* above .ui.modal which has 1001 */ - border-radius: var(--border-radius); - background-color: var(--color-menu); - justify-content: flex-end; - direction: ltr; - box-shadow: 0 5px 20px var(--color-shadow); - user-select: none; -} - -.clr-picker.clr-open { - display: flex; -} - -.clr-gradient { - position: relative; - width: 100%; - height: 100px; - border-radius: 3px 3px 0 0; - background: linear-gradient(rgba(0,0,0,0), #000), linear-gradient(90deg, #fff, currentcolor); /* stylelint-disable-line scale-unlimited/declaration-strict-value */ - cursor: pointer; -} - -.clr-marker { - position: absolute; - width: 12px; - height: 12px; - margin: -6px 0 0 -6px; - border: 1px solid var(--color-white); - border-radius: 50%; - background-color: currentcolor; - cursor: pointer; -} - -.clr-picker input[type="range"]::-webkit-slider-runnable-track { - width: 100%; - height: 16px; -} - -.clr-picker input[type="range"]::-webkit-slider-thumb { - width: 16px; - height: 16px; - -webkit-appearance: none; -} - -.clr-picker input[type="range"]::-moz-range-track { - width: 100%; - height: 16px; - border: 0; -} - -.clr-picker input[type="range"]::-moz-range-thumb { - width: 16px; - height: 16px; - border: 0; -} - -.clr-hue { - background: linear-gradient(to right, #f00 0%, #ff0 16.66%, #0f0 33.33%, #0ff 50%, #00f 66.66%, #f0f 83.33%, #f00 100%); /* stylelint-disable-line scale-unlimited/declaration-strict-value */ - position: relative; - width: calc(100% - 40px); - height: 10px; - margin: 10px 20px; - border-radius: 4px; -} - -.clr-hue input[type="range"] { - position: absolute; - width: calc(100% + 32px); - margin: 0; - background-color: transparent; - opacity: 0; - cursor: pointer; - appearance: none; -} - -.clr-hue div { - position: absolute; - width: 16px; - height: 16px; - left: 0; - top: 50%; - transform: translate(-50%, -50%); - border: 2px solid var(--color-white); - border-radius: 50%; - background-color: currentcolor; - box-shadow: 0 0 1px var(--color-shadow); - pointer-events: none; -} - -.clr-field { - flex: 1; - position: relative; - color: transparent; -} - -.clr-field button { +.js-color-picker-input .preview-square { position: absolute; aspect-ratio: 1; height: 16px; left: 10px; top: 50%; transform: translateY(-50%); - margin: 0; - padding: 0; - border: 0; - color: inherit; - pointer-events: none; border-radius: 2px; background: repeating-linear-gradient(45deg, #aaa 25%, transparent 25%, transparent 75%, #aaa 75%, #aaa), repeating-linear-gradient(45deg, #aaa 25%, #fff 25%, #fff 75%, #aaa 75%, #aaa); /* stylelint-disable-line scale-unlimited/declaration-strict-value */ background-position: 0 0, 4px 4px; background-size: 8px 8px; } -.clr-field button::after { +.js-color-picker-input .preview-square::after { content: ""; - display: block; position: absolute; width: 100%; height: 100%; - left: 0; - top: 0; border-radius: inherit; background-color: currentcolor; } -.clr-marker:focus { - outline: none; +hex-color-picker { + width: 180px; + height: 120px; } -.clr-keyboard-nav .clr-marker:focus, -.clr-keyboard-nav .clr-hue input:focus + div, -.clr-keyboard-nav .clr-alpha input:focus + div { - outline: none; - box-shadow: 0 0 2px 2px var(--color-white); +hex-color-picker::part(hue-pointer), +hex-color-picker::part(saturation-pointer) { + width: 22px; + height: 22px; } -.clr-picker .clr-preview, -.clr-picker .clr-clear, -.clr-picker .clr-swatches, -.clr-picker .clr-format, -.clr-picker .clr-alpha, -.clr-picker .clr-color { - display: none; +hex-color-picker::part(hue) { + flex-basis: 16px; } diff --git a/web_src/css/modules/tippy.css b/web_src/css/modules/tippy.css index 76d36b4293..6ac7c37d93 100644 --- a/web_src/css/modules/tippy.css +++ b/web_src/css/modules/tippy.css @@ -29,6 +29,17 @@ z-index: 1; } +/* bare theme, no styling at all, except box-shadow */ +.tippy-box[data-theme="bare"] { + border: none; + box-shadow: 0 6px 18px var(--color-shadow); +} + +.tippy-box[data-theme="bare"] .tippy-content { + padding: 0; + background: transparent; +} + /* tooltip theme for text tooltips */ .tippy-box[data-theme="tooltip"] { diff --git a/web_src/js/features/colorpicker.js b/web_src/js/features/colorpicker.js index f342598e66..6d00d908c9 100644 --- a/web_src/js/features/colorpicker.js +++ b/web_src/js/features/colorpicker.js @@ -1,31 +1,66 @@ -export async function initColorPickers(selector = '.js-color-picker-input input', opts = {}) { - const inputEls = document.querySelectorAll(selector); - if (!inputEls.length) return; +import {createTippy} from '../modules/tippy.js'; - const [{coloris, init}] = await Promise.all([ - import(/* webpackChunkName: "colorpicker" */'@melloware/coloris'), +export async function initColorPickers() { + const els = document.getElementsByClassName('js-color-picker-input'); + if (!els.length) return; + + await Promise.all([ + import(/* webpackChunkName: "colorpicker" */'vanilla-colorful/hex-color-picker.js'), import(/* webpackChunkName: "colorpicker" */'../../css/features/colorpicker.css'), ]); - init(); - coloris({ - el: selector, - alpha: false, - focusInput: true, - selectInput: false, - ...opts, - }); - - for (const inputEl of inputEls) { - const parent = inputEl.closest('.js-color-picker-input'); - // prevent tabbing on the color preview `button` inside the input - parent.querySelector('button').tabIndex = -1; - // init precolors - for (const el of parent.querySelectorAll('.precolors .color')) { - el.addEventListener('click', (e) => { - inputEl.value = e.target.getAttribute('data-color-hex'); - inputEl.dispatchEvent(new Event('input', {bubbles: true})); - }); - } + for (const el of els) { + initPicker(el); + } +} + +function updateSquare(el, newValue) { + el.style.color = /#[0-9a-f]{6}/i.test(newValue) ? newValue : 'transparent'; +} + +function updatePicker(el, newValue) { + el.setAttribute('color', newValue); +} + +function initPicker(el) { + const input = el.querySelector('input'); + + const square = document.createElement('div'); + square.classList.add('preview-square'); + updateSquare(square, input.value); + el.append(square); + + const picker = document.createElement('hex-color-picker'); + picker.addEventListener('color-changed', (e) => { + input.value = e.detail.value; + input.focus(); + updateSquare(square, e.detail.value); + }); + + input.addEventListener('input', (e) => { + updateSquare(square, e.target.value); + updatePicker(picker, e.target.value); + }); + + createTippy(input, { + trigger: 'focus click', + theme: 'bare', + hideOnClick: true, + content: picker, + placement: 'bottom-start', + interactive: true, + onShow() { + updatePicker(picker, input.value); + }, + }); + + // init precolors + for (const colorEl of el.querySelectorAll('.precolors .color')) { + colorEl.addEventListener('click', (e) => { + const newValue = e.target.getAttribute('data-color-hex'); + input.value = newValue; + input.dispatchEvent(new Event('input', {bubbles: true})); + updateSquare(square, newValue); + }); } } diff --git a/web_src/js/modules/tippy.js b/web_src/js/modules/tippy.js index 220c9e5512..83b28e5745 100644 --- a/web_src/js/modules/tippy.js +++ b/web_src/js/modules/tippy.js @@ -3,11 +3,12 @@ import {isDocumentFragmentOrElementNode} from '../utils/dom.js'; import {formatDatetime} from '../utils/time.js'; const visibleInstances = new Set(); +const arrowSvg = ``; export function createTippy(target, opts = {}) { // the callback functions should be destructured from opts, // because we should use our own wrapper functions to handle them, do not let the user override them - const {onHide, onShow, onDestroy, role, theme, ...other} = opts; + const {onHide, onShow, onDestroy, role, theme, arrow, ...other} = opts; const instance = tippy(target, { appendTo: document.body, @@ -35,9 +36,9 @@ export function createTippy(target, opts = {}) { visibleInstances.add(instance); return onShow?.(instance); }, - arrow: ``, + arrow: arrow || (theme === 'bare' ? false : arrowSvg), role: role || 'menu', // HTML role attribute - theme: theme || role || 'menu', // CSS theme, either "tooltip", "menu" or "box-with-header" + theme: theme || role || 'menu', // CSS theme, either "tooltip", "menu", "box-with-header" or "bare" plugins: [followCursor], ...other, }); From 0ceecfc11ab4851863a5a6bc5e398d2baf7e86f6 Mon Sep 17 00:00:00 2001 From: guangwu Date: Wed, 3 Apr 2024 22:58:13 +0800 Subject: [PATCH 015/247] fix: close file in the Upload func (#30262) --- modules/lfs/filesystem_client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/lfs/filesystem_client.go b/modules/lfs/filesystem_client.go index 3503a9effc..71bef5c899 100644 --- a/modules/lfs/filesystem_client.go +++ b/modules/lfs/filesystem_client.go @@ -44,7 +44,7 @@ func (c *FilesystemClient) Download(ctx context.Context, objects []Pointer, call if err != nil { return err } - + defer f.Close() if err := callback(p, f, nil); err != nil { return err } @@ -75,7 +75,7 @@ func (c *FilesystemClient) Upload(ctx context.Context, objects []Pointer, callba if err != nil { return err } - + defer f.Close() _, err = io.Copy(f, content) return err From 609a627a44dbcb7b630ff51ce9f4b9f448b48ca8 Mon Sep 17 00:00:00 2001 From: Yakov Date: Wed, 3 Apr 2024 09:01:50 -0700 Subject: [PATCH 016/247] Add `[other].SHOW_FOOTER_POWERED_BY` setting to hide `Powered by` (#30253) This allows you to hide the "Powered by" text in footer via `SHOW_FOOTER_POWERED_BY` flag in configuration. --------- Co-authored-by: silverwind --- custom/conf/app.example.ini | 2 ++ docs/content/administration/config-cheat-sheet.en-us.md | 1 + docs/content/administration/config-cheat-sheet.zh-cn.md | 1 + modules/setting/other.go | 2 ++ modules/templates/helper.go | 3 +++ templates/base/footer_content.tmpl | 4 +++- 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 1584b10301..918252044b 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2315,6 +2315,8 @@ LEVEL = Info ;SHOW_FOOTER_VERSION = true ;; Show template execution time in the footer ;SHOW_FOOTER_TEMPLATE_LOAD_TIME = true +;; Show the "powered by" text in the footer +;SHOW_FOOTER_POWERED_BY = true ;; Generate sitemap. Defaults to `true`. ;ENABLE_SITEMAP = true ;; Enable/Disable RSS/Atom feed diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index f2209d269a..9de7511964 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -1429,5 +1429,6 @@ Like `uses: https://gitea.com/actions/checkout@v4` or `uses: http://your-git-ser - `SHOW_FOOTER_VERSION`: **true**: Show Gitea and Go version information in the footer. - `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: Show time of template execution in the footer. +- `SHOW_FOOTER_POWERED_BY`: **true**: Show the "powered by" text in the footer. - `ENABLE_SITEMAP`: **true**: Generate sitemap. - `ENABLE_FEED`: **true**: Enable/Disable RSS/Atom feed. diff --git a/docs/content/administration/config-cheat-sheet.zh-cn.md b/docs/content/administration/config-cheat-sheet.zh-cn.md index 41c8844ae5..759f39b576 100644 --- a/docs/content/administration/config-cheat-sheet.zh-cn.md +++ b/docs/content/administration/config-cheat-sheet.zh-cn.md @@ -1353,5 +1353,6 @@ PROXY_HOSTS = *.github.com - `SHOW_FOOTER_VERSION`: **true**: 在页面底部显示Gitea的版本。 - `SHOW_FOOTER_TEMPLATE_LOAD_TIME`: **true**: 在页脚显示模板执行的时间。 +- `SHOW_FOOTER_POWERED_BY`: **true**: 在页脚显示“由...提供动力”的文本。 - `ENABLE_SITEMAP`: **true**: 生成sitemap. - `ENABLE_FEED`: **true**: 是否启用RSS/Atom diff --git a/modules/setting/other.go b/modules/setting/other.go index 706cb1e3d9..4ba494765b 100644 --- a/modules/setting/other.go +++ b/modules/setting/other.go @@ -8,6 +8,7 @@ import "code.gitea.io/gitea/modules/log" type OtherConfig struct { ShowFooterVersion bool ShowFooterTemplateLoadTime bool + ShowFooterPoweredBy bool EnableFeed bool EnableSitemap bool } @@ -15,6 +16,7 @@ type OtherConfig struct { var Other = OtherConfig{ ShowFooterVersion: true, ShowFooterTemplateLoadTime: true, + ShowFooterPoweredBy: true, EnableSitemap: true, EnableFeed: true, } diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 2452064749..9e770a2606 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -106,6 +106,9 @@ func NewFuncMap() template.FuncMap { "ShowFooterTemplateLoadTime": func() bool { return setting.Other.ShowFooterTemplateLoadTime }, + "ShowFooterPoweredBy": func() bool { + return setting.Other.ShowFooterPoweredBy + }, "AllowedReactions": func() []string { return setting.UI.Reactions }, diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl index f0a7865602..8d0d8e669c 100644 --- a/templates/base/footer_content.tmpl +++ b/templates/base/footer_content.tmpl @@ -1,6 +1,8 @@
From 9c1f4dae2ee85b748250ba7b161d70bd529088d3 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 6 Apr 2024 10:25:39 +0200 Subject: [PATCH 025/247] Always use `octicon-eye` on watch button (#30288) This might appear odd but I think it's the right thing to do: On Github, the "Watch" button always has the open eye icon: Screenshot 2024-04-05 at 08 26 48 Screenshot 2024-04-05 at 08 26 40 On Gitea, while watching, the icon is this and this sometimes confuses me slightly, being used to above: Screenshot 2024-04-05 at 08 29 08 After this PR, both states will use the same icon: Screenshot 2024-04-05 at 08 26 27 Screenshot 2024-04-05 at 08 26 33 --- templates/repo/watch_unwatch.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/watch_unwatch.tmpl b/templates/repo/watch_unwatch.tmpl index 2bf2c7bd21..64be971416 100644 --- a/templates/repo/watch_unwatch.tmpl +++ b/templates/repo/watch_unwatch.tmpl @@ -3,7 +3,7 @@ {{$buttonText := ctx.Locale.Tr "repo.watch"}} {{if $.IsWatchingRepo}}{{$buttonText = ctx.Locale.Tr "repo.unwatch"}}{{end}} From 7396172a02a9ea8d80f9763469fd65a5a12ff3f7 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sat, 6 Apr 2024 20:07:08 +0800 Subject: [PATCH 026/247] Fix code block style for code preview (#30298) Fix #30292 To avoid unnecessary style overriding, use "div" instead of "code" --- modules/markup/sanitizer.go | 2 +- services/markup/processorhelper_codepreview_test.go | 6 +++--- templates/base/markup_codepreview.tmpl | 2 +- web_src/css/markup/content.css | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index 77fbdf4520..570a1da248 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -65,7 +65,7 @@ func createDefaultPolicy() *bluemonday.Policy { policy.AllowAttrs("class").Matching(regexp.MustCompile(`^lines-num$`)).OnElements("td") policy.AllowAttrs("data-line-number").OnElements("span") policy.AllowAttrs("class").Matching(regexp.MustCompile(`^lines-code chroma$`)).OnElements("td") - policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-inner$`)).OnElements("code") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-inner$`)).OnElements("div") // For code preview (unicode escape) policy.AllowAttrs("class").Matching(regexp.MustCompile(`^file-view( unicode-escaped)?$`)).OnElements("table") diff --git a/services/markup/processorhelper_codepreview_test.go b/services/markup/processorhelper_codepreview_test.go index 01db792925..154e4e8e44 100644 --- a/services/markup/processorhelper_codepreview_test.go +++ b/services/markup/processorhelper_codepreview_test.go @@ -36,10 +36,10 @@ func TestProcessorHelperCodePreview(t *testing.T) { - + - +
# repo1
# repo1
@@ -63,7 +63,7 @@ func TestProcessorHelperCodePreview(t *testing.T) { - +
# repo1
# repo1
diff --git a/templates/base/markup_codepreview.tmpl b/templates/base/markup_codepreview.tmpl index c65ab28406..a1a4f26b47 100644 --- a/templates/base/markup_codepreview.tmpl +++ b/templates/base/markup_codepreview.tmpl @@ -17,7 +17,7 @@ {{- $lineEscapeStatus := index $.LineEscapeStatus $idx -}} {{if $lineEscapeStatus.Escaped}}{{end}} {{- end}} - {{$line.FormattedContent}} +
{{$line.FormattedContent}}
{{/* only div works, span generates incorrect HTML structure */}} {{- end -}} diff --git a/web_src/css/markup/content.css b/web_src/css/markup/content.css index 376d3030c7..d44e727a25 100644 --- a/web_src/css/markup/content.css +++ b/web_src/css/markup/content.css @@ -432,7 +432,7 @@ text-align: right; } -.markup code:not(.code-inner), +.markup code, .markup tt { padding: 0.2em 0.4em; margin: 0; From 662eb4b0852f9ce2c161e7fea5ac66bf912fc9f6 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 6 Apr 2024 23:06:27 +0200 Subject: [PATCH 027/247] Markup color and font size fixes (#30282) 1. Distinguish inline an block code with new CSS variable `--color-markup-code-inline` 2. Various color tweaks, better contrast from background Screenshot 2024-04-05 at 00 51 00 Screenshot 2024-04-05 at 00 50 44 --- web_src/css/markup/content.css | 4 ++-- web_src/css/themes/theme-gitea-dark.css | 5 +++-- web_src/css/themes/theme-gitea-light.css | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/web_src/css/markup/content.css b/web_src/css/markup/content.css index d44e727a25..6ba4e40072 100644 --- a/web_src/css/markup/content.css +++ b/web_src/css/markup/content.css @@ -438,7 +438,7 @@ margin: 0; font-size: 85%; white-space: break-spaces; - background-color: var(--color-markup-code-block); + background-color: var(--color-markup-code-inline); border-radius: var(--border-radius); } @@ -508,7 +508,7 @@ line-height: 10px; color: var(--color-text-light); vertical-align: middle; - background-color: var(--color-markup-code-block); + background-color: var(--color-markup-code-inline); border: 1px solid var(--color-secondary); border-radius: var(--border-radius); box-shadow: inset 0 -1px 0 var(--color-secondary); diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 626590ca54..07e217742d 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -204,8 +204,9 @@ --color-active: #e8e8ff24; --color-menu: #151a1e; --color-card: #151a1e; - --color-markup-table-row: #e8e8ff06; - --color-markup-code-block: #e8e8ff16; + --color-markup-table-row: #e8e8ff0f; + --color-markup-code-block: #e8e8ff12; + --color-markup-code-inline: #e8e8ff28; --color-button: #151a1e; --color-code-bg: #14171a; --color-shadow: #00001758; diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index f6913fbe22..2741e0e0bd 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -204,8 +204,9 @@ --color-active: #00001714; --color-menu: #f8f9fb; --color-card: #f8f9fb; - --color-markup-table-row: #00001708; - --color-markup-code-block: #00001710; + --color-markup-table-row: #0030600a; + --color-markup-code-block: #00306010; + --color-markup-code-inline: #00306012; --color-button: #f8f9fb; --color-code-bg: #fafdff; --color-shadow: #00001726; From 649aada3664f5adccdaecc7dd24b8252ae070220 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 6 Apr 2024 23:33:45 +0200 Subject: [PATCH 028/247] Remove fomantic list module (#30281) Likely still some unnecessary CSS but any combinations with the `ui list` classes are covered. There was only on instance of `horizontal list` which I removed. It was this part of the commit page: image --- templates/repo/commit_page.tmpl | 4 +- templates/user/settings/repos.tmpl | 2 +- web_src/css/base.css | 29 +- web_src/css/index.css | 1 + web_src/css/modules/list.css | 187 ++++++ web_src/fomantic/build/semantic.css | 977 ---------------------------- web_src/fomantic/semantic.json | 1 - 7 files changed, 192 insertions(+), 1009 deletions(-) create mode 100644 web_src/css/modules/list.css diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 3ae7fffa1c..49a0b445b1 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -164,9 +164,9 @@ {{end}} {{end}}
-
+
{{if .Parents}} -
+
{{ctx.Locale.Tr "repo.diff.parent"}} {{range .Parents}} {{if $.PageIsWiki}} diff --git a/templates/user/settings/repos.tmpl b/templates/user/settings/repos.tmpl index c874ccd878..26b9dfeed9 100644 --- a/templates/user/settings/repos.tmpl +++ b/templates/user/settings/repos.tmpl @@ -6,7 +6,7 @@
{{if or .allowAdopt .allowDelete}} {{if .Dirs}} -
+
{{range $dirI, $dir := .Dirs}} {{$repo := index $.ReposMap $dir}}
{{/* if not repo, then there are "adapt" buttons, so the padding shouldn't be that default large*/}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 05ddba3223..096b67058e 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -44,7 +44,7 @@ html, body { } body { - line-height: 1.4285rem; + line-height: 20px; font-family: var(--fonts-regular); color: var(--color-text); background-color: var(--color-body); @@ -305,14 +305,6 @@ a.label, background-color: var(--color-label-bg); } -/* fix Fomantic's line-height causing vertical scrollbars to appear */ -ul.ui.list li, -ol.ui.list li, -.ui.list > .item, -.ui.list .list > .item { - line-height: var(--line-height-default); -} - .ui.menu { display: flex; } @@ -456,21 +448,6 @@ ol.ui.list li, color: var(--color-text-light-2); } -.ui.list .list > .item .header, -.ui.list > .item .header { - color: var(--color-text-dark); -} - -.ui.list .list > .item > .content, -.ui.list > .item > .content { - color: var(--color-text); -} - -.ui.list .list > .item .description, -.ui.list > .item .description { - color: var(--color-text); -} - /* replace item margin on secondary menu items with gap and remove both the negative margins on the menu as well as margin on the items */ .ui.secondary.menu { @@ -589,10 +566,6 @@ img.ui.avatar, aspect-ratio: 1; } -.ui.divided.list > .item { - border-color: var(--color-secondary); -} - .ui.error.message .header, .ui.warning.message .header { color: inherit; diff --git a/web_src/css/index.css b/web_src/css/index.css index 7be8065dc7..ad59f32636 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -8,6 +8,7 @@ @import "./modules/header.css"; @import "./modules/input.css"; @import "./modules/label.css"; +@import "./modules/list.css"; @import "./modules/segment.css"; @import "./modules/grid.css"; @import "./modules/message.css"; diff --git a/web_src/css/modules/list.css b/web_src/css/modules/list.css new file mode 100644 index 0000000000..73760390de --- /dev/null +++ b/web_src/css/modules/list.css @@ -0,0 +1,187 @@ +/* based on Fomantic UI list module, with just the parts extracted that we use. If you find any + unused rules here after refactoring, please remove them. */ + +.ui.list { + list-style-type: none; + margin: 1em 0; + padding: 0; + font-size: 1em; +} + +.ui.list:first-child { + margin-top: 0; + padding-top: 0; +} + +.ui.list:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +.ui.list > .item, +.ui.list .list > .item { + display: list-item; + table-layout: fixed; + list-style-type: none; + list-style-position: outside; +} + +.ui.list > .list > .item::after, +.ui.list > .item::after { + content: ""; + display: block; + height: 0; + clear: both; + visibility: hidden; +} + +.ui.list .list:not(.icon) { + clear: both; + margin: 0; + padding: 0.75em 0 0.25em 0.5em; +} + +.ui.list .list > .item { + padding: 0.14285714em 0; +} + +.ui.list .list > .item > i.icon, +.ui.list > .item > i.icon { + display: table-cell; + min-width: 1.55em; + padding-top: 0; + transition: color 0.1s ease; + padding-right: 0.28571429em; + vertical-align: top; +} +.ui.list .list > .item > i.icon:only-child, +.ui.list > .item > i.icon:only-child { + display: inline-block; + min-width: auto; + vertical-align: top; +} + +.ui.list .list > .item > .image, +.ui.list > .item > .image { + display: table-cell; + background-color: transparent; + vertical-align: top; +} +.ui.list .list > .item > .image:not(:only-child):not(img), +.ui.list > .item > .image:not(:only-child):not(img) { + padding-right: 0.5em; +} +.ui.list .list > .item > .image img, +.ui.list > .item > .image img { + vertical-align: top; +} +.ui.list .list > .item > img.image, +.ui.list .list > .item > .image:only-child, +.ui.list > .item > img.image, +.ui.list > .item > .image:only-child { + display: inline-block; +} + +.ui.list .list > .item > .content, +.ui.list > .item > .content { + color: var(--color-text); +} +.ui.list .list > .item > .image + .content, +.ui.list .list > .item > i.icon + .content, +.ui.list > .item > .image + .content, +.ui.list > .item > i.icon + .content { + display: table-cell; + width: 100%; + padding: 0 0 0 0.5em; + vertical-align: top; +} +.ui.list .list > .item > img.image + .content, +.ui.list > .item > img.image + .content { + display: inline-block; + width: auto; +} +.ui.list .list > .item > .content > .list, +.ui.list > .item > .content > .list { + margin-left: 0; + padding-left: 0; +} + +.ui.list .list > .item .header, +.ui.list > .item .header { + display: block; + margin: 0; + font-family: var(--fonts-regular); + font-weight: var(--font-weight-medium); + color: var(--color-text-dark); +} + +.ui.list .list > .item .description, +.ui.list > .item .description { + display: block; + color: var(--color-text); +} + +.ui.list > .item a, +.ui.list .list > .item a { + cursor: pointer; +} + +.ui.menu .ui.list > .item, +.ui.menu .ui.list .list > .item { + display: list-item; + table-layout: fixed; + background-color: transparent; + list-style-type: none; + list-style-position: outside; + padding: 0.21428571em 0; +} +.ui.menu .ui.list .list > .item::before, +.ui.menu .ui.list > .item::before { + border: none; + background: none; +} +.ui.menu .ui.list .list > .item:first-child, +.ui.menu .ui.list > .item:first-child { + padding-top: 0; +} +.ui.menu .ui.list .list > .item:last-child, +.ui.menu .ui.list > .item:last-child { + padding-bottom: 0; +} + +.ui.list .list > .disabled.item, +.ui.list > .disabled.item { + pointer-events: none; + opacity: var(--opacity-disabled); +} + +.ui.list .list > a.item:hover > .icons, +.ui.list > a.item:hover > .icons, +.ui.list .list > a.item:hover > i.icon, +.ui.list > a.item:hover > i.icon { + color: var(--color-text-dark); +} + +.ui.divided.list > .item { + border-top: 1px solid var(--color-secondary); +} +.ui.divided.list .list > .item { + border-top: none; +} +.ui.divided.list .item .list > .item { + border-top: none; +} +.ui.divided.list .list > .item:first-child, +.ui.divided.list > .item:first-child { + border-top: none; +} +.ui.divided.list .list > .item:first-child { + border-top-width: 1px; +} + +.ui.relaxed.list > .item:not(:first-child) { + padding-top: 0.42857143em; +} +.ui.relaxed.list > .item:not(:last-child) { + padding-bottom: 0.42857143em; +} diff --git a/web_src/fomantic/build/semantic.css b/web_src/fomantic/build/semantic.css index 5cb6a371e5..49c00c4dad 100644 --- a/web_src/fomantic/build/semantic.css +++ b/web_src/fomantic/build/semantic.css @@ -6477,983 +6477,6 @@ select.ui.dropdown { /******************************* Site Overrides *******************************/ -/*! - * # Fomantic-UI - List - * http://github.com/fomantic/Fomantic-UI/ - * - * - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - -/******************************* - List -*******************************/ - -ul.ui.list, -ol.ui.list, -.ui.list { - list-style-type: none; - margin: 1em 0; - padding: 0 0; -} - -ul.ui.list:first-child, -ol.ui.list:first-child, -.ui.list:first-child { - margin-top: 0; - padding-top: 0; -} - -ul.ui.list:last-child, -ol.ui.list:last-child, -.ui.list:last-child { - margin-bottom: 0; - padding-bottom: 0; -} - -/******************************* - Content -*******************************/ - -/* List Item */ - -ul.ui.list li, -ol.ui.list li, -.ui.list > .item, -.ui.list .list > .item { - display: list-item; - table-layout: fixed; - list-style-type: none; - list-style-position: outside; - padding: 0.21428571em 0; - line-height: 1.14285714em; -} - -ul.ui.list > li:first-child:after, -ol.ui.list > li:first-child:after, -.ui.list > .list > .item:after, -.ui.list > .item:after { - content: ''; - display: block; - height: 0; - clear: both; - visibility: hidden; -} - -ul.ui.list li:first-child, -ol.ui.list li:first-child, -.ui.list .list > .item:first-child, -.ui.list > .item:first-child { - padding-top: 0; -} - -ul.ui.list li:last-child, -ol.ui.list li:last-child, -.ui.list .list > .item:last-child, -.ui.list > .item:last-child { - padding-bottom: 0; -} - -/* Child List */ - -ul.ui.list ul, -ol.ui.list ol, -.ui.list .list:not(.icon) { - clear: both; - margin: 0; - padding: 0.75em 0 0.25em 0.5em; -} - -/* Child Item */ - -ul.ui.list ul li, -ol.ui.list ol li, -.ui.list .list > .item { - padding: 0.14285714em 0; - line-height: inherit; -} - -/* Icon */ - -.ui.list .list > .item > i.icon, -.ui.list > .item > i.icon { - display: table-cell; - min-width: 1.55em; - margin: 0; - padding-top: 0; - transition: color 0.1s ease; -} - -.ui.list .list > .item > i.icon:not(.loading), -.ui.list > .item > i.icon:not(.loading) { - padding-right: 0.28571429em; - vertical-align: top; -} - -.ui.list .list > .item > i.icon:only-child, -.ui.list > .item > i.icon:only-child { - display: inline-block; - min-width: auto; - vertical-align: top; -} - -/* Image */ - -.ui.list .list > .item > .image, -.ui.list > .item > .image { - display: table-cell; - background-color: transparent; - margin: 0; - vertical-align: top; -} - -.ui.list .list > .item > .image:not(:only-child):not(img), -.ui.list > .item > .image:not(:only-child):not(img) { - padding-right: 0.5em; -} - -.ui.list .list > .item > .image img, -.ui.list > .item > .image img { - vertical-align: top; -} - -.ui.list .list > .item > img.image, -.ui.list .list > .item > .image:only-child, -.ui.list > .item > img.image, -.ui.list > .item > .image:only-child { - display: inline-block; -} - -/* Content */ - -.ui.list .list > .item > .content, -.ui.list > .item > .content { - line-height: 1.14285714em; - color: rgba(0, 0, 0, 0.87); -} - -.ui.list .list > .item > .image + .content, -.ui.list .list > .item > i.icon + .content, -.ui.list > .item > .image + .content, -.ui.list > .item > i.icon + .content { - display: table-cell; - width: 100%; - padding: 0 0 0 0.5em; - vertical-align: top; -} - -.ui.list .list > .item > i.loading.icon + .content, -.ui.list > .item > i.loading.icon + .content { - padding-left: calc(0.2857142857142857em + 0.5em); -} - -.ui.list .list > .item > img.image + .content, -.ui.list > .item > img.image + .content { - display: inline-block; - width: auto; -} - -.ui.list .list > .item > .content > .list, -.ui.list > .item > .content > .list { - margin-left: 0; - padding-left: 0; -} - -/* Header */ - -.ui.list .list > .item .header, -.ui.list > .item .header { - display: block; - margin: 0; - font-family: var(--fonts-regular); - font-weight: 500; - color: rgba(0, 0, 0, 0.87); -} - -/* Description */ - -.ui.list .list > .item .description, -.ui.list > .item .description { - display: block; - color: rgba(0, 0, 0, 0.7); -} - -/* Child Link */ - -.ui.list > .item a, -.ui.list .list > .item a { - cursor: pointer; -} - -/* Linking Item */ - -.ui.list .list > a.item, -.ui.list > a.item { - cursor: pointer; - color: #4183C4; -} - -.ui.list .list > a.item:hover, -.ui.list > a.item:hover { - color: #1e70bf; -} - -/* Linked Item Icons */ - -.ui.list .list > a.item > i.icons, -.ui.list > a.item > i.icons, -.ui.list .list > a.item > i.icon, -.ui.list > a.item > i.icon { - color: rgba(0, 0, 0, 0.4); -} - -/* Header Link */ - -.ui.list .list > .item a.header, -.ui.list > .item a.header { - cursor: pointer; - color: #4183C4 !important; -} - -.ui.list .list > .item > a.header:hover, -.ui.list > .item > a.header:hover { - color: #1e70bf !important; -} - -/* Floated Content */ - -.ui[class*="left floated"].list { - float: left; -} - -.ui[class*="right floated"].list { - float: right; -} - -.ui.list .list > .item [class*="left floated"], -.ui.list > .item [class*="left floated"] { - float: left; - margin: 0 1em 0 0; -} - -.ui.list .list > .item [class*="right floated"], -.ui.list > .item [class*="right floated"] { - float: right; - margin: 0 0 0 1em; -} - -/******************************* - Coupling -*******************************/ - -.ui.menu .ui.list > .item, -.ui.menu .ui.list .list > .item { - display: list-item; - table-layout: fixed; - background-color: transparent; - list-style-type: none; - list-style-position: outside; - padding: 0.21428571em 0; - line-height: 1.14285714em; -} - -.ui.menu .ui.list .list > .item:before, -.ui.menu .ui.list > .item:before { - border: none; - background: none; -} - -.ui.menu .ui.list .list > .item:first-child, -.ui.menu .ui.list > .item:first-child { - padding-top: 0; -} - -.ui.menu .ui.list .list > .item:last-child, -.ui.menu .ui.list > .item:last-child { - padding-bottom: 0; -} - -/******************************* - Types -*******************************/ - -/*------------------- - Horizontal - --------------------*/ - -.ui.horizontal.list { - display: inline-block; - font-size: 0; -} - -.ui.horizontal.list > .item { - display: inline-block; - margin-right: 1em; - font-size: 1rem; -} - -.ui.horizontal.list:not(.celled) > .item:last-child { - margin-right: 0; - padding-right: 0; -} - -.ui.horizontal.list .list:not(.icon) { - padding-left: 0; - padding-bottom: 0; -} - -.ui.horizontal.list > .item > .image, -.ui.horizontal.list .list > .item > .image, -.ui.horizontal.list > .item > i.icon, -.ui.horizontal.list .list > .item > i.icon, -.ui.horizontal.list > .item > .content, -.ui.horizontal.list .list > .item > .content { - vertical-align: middle; -} - -/* Padding on all elements */ - -.ui.horizontal.list > .item:first-child, -.ui.horizontal.list > .item:last-child { - padding-top: 0.21428571em; - padding-bottom: 0.21428571em; -} - -/* Horizontal List */ - -.ui.horizontal.list > .item > i.icon, -.ui.horizontal.list .item > i.icons > i.icon { - margin: 0; - padding: 0 0.25em 0 0; -} - -.ui.horizontal.list > .item > .image + .content, -.ui.horizontal.list > .item > i.icon, -.ui.horizontal.list > .item > i.icon + .content { - float: none; - display: inline-block; - width: auto; -} - -.ui.horizontal.list > .item > .image { - display: inline-block; -} - -/******************************* - States -*******************************/ - -/*------------------- - Disabled - --------------------*/ - -.ui.list .list > .disabled.item, -.ui.list > .disabled.item { - pointer-events: none; - color: rgba(40, 40, 40, 0.3) !important; -} - -/*------------------- - Hover ---------------------*/ - -.ui.list .list > a.item:hover > .icons, -.ui.list > a.item:hover > .icons, -.ui.list .list > a.item:hover > i.icon, -.ui.list > a.item:hover > i.icon { - color: rgba(0, 0, 0, 0.87); -} - -/******************************* - Variations -*******************************/ - -/*------------------- - Aligned - --------------------*/ - -.ui.list[class*="top aligned"] .image, -.ui.list[class*="top aligned"] .content, -.ui.list [class*="top aligned"] { - vertical-align: top !important; -} - -.ui.list[class*="middle aligned"] .image, -.ui.list[class*="middle aligned"] .content, -.ui.list [class*="middle aligned"] { - vertical-align: middle !important; -} - -.ui.list[class*="bottom aligned"] .image, -.ui.list[class*="bottom aligned"] .content, -.ui.list [class*="bottom aligned"] { - vertical-align: bottom !important; -} - -/*------------------- - Link - --------------------*/ - -.ui.link.list .item, -.ui.link.list a.item, -.ui.link.list .item a:not(.ui) { - color: rgba(0, 0, 0, 0.4); - transition: 0.1s color ease; -} - -.ui.link.list.list a.item:hover, -.ui.link.list.list .item a:not(.ui):hover { - color: rgba(0, 0, 0, 0.8); -} - -.ui.link.list.list a.item:active, -.ui.link.list.list .item a:not(.ui):active { - color: rgba(0, 0, 0, 0.9); -} - -.ui.link.list.list .active.item, -.ui.link.list.list .active.item a:not(.ui) { - color: rgba(0, 0, 0, 0.95); -} - -/*------------------- - Selection - --------------------*/ - -.ui.selection.list .list > .item, -.ui.selection.list > .item { - cursor: pointer; - background: transparent; - padding: 0.5em 0.5em; - margin: 0; - color: rgba(0, 0, 0, 0.4); - border-radius: 0.5em; - transition: 0.1s color ease, 0.1s padding-left ease, 0.1s background-color ease; -} - -.ui.selection.list .list > .item:last-child, -.ui.selection.list > .item:last-child { - margin-bottom: 0; -} - -.ui.selection.list .list > .item:hover, -.ui.selection.list > .item:hover { - background: rgba(0, 0, 0, 0.03); - color: rgba(0, 0, 0, 0.8); -} - -.ui.selection.list .list > .item:active, -.ui.selection.list > .item:active { - background: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.9); -} - -.ui.selection.list .list > .item.active, -.ui.selection.list > .item.active { - background: rgba(0, 0, 0, 0.05); - color: rgba(0, 0, 0, 0.95); -} - -/* Celled / Divided Selection List */ - -.ui.celled.selection.list .list > .item, -.ui.divided.selection.list .list > .item, -.ui.celled.selection.list > .item, -.ui.divided.selection.list > .item { - border-radius: 0; -} - -/*------------------- - Animated - --------------------*/ - -.ui.animated.list > .item { - transition: 0.25s color ease 0.1s, 0.25s padding-left ease 0.1s, 0.25s background-color ease 0.1s; -} - -.ui.animated.list:not(.horizontal) > .item:hover { - padding-left: 1em; -} - -/*------------------- - Fitted - --------------------*/ - -.ui.fitted.list:not(.selection) .list > .item, -.ui.fitted.list:not(.selection) > .item { - padding-left: 0; - padding-right: 0; -} - -.ui.fitted.selection.list .list > .item, -.ui.fitted.selection.list > .item { - margin-left: -0.5em; - margin-right: -0.5em; -} - -/*------------------- - Bulleted - --------------------*/ - -ul.ui.list, -.ui.bulleted.list { - margin-left: 1.25rem; -} - -ul.ui.list li, -.ui.bulleted.list .list > .item, -.ui.bulleted.list > .item { - position: relative; -} - -ul.ui.list li:before, -.ui.bulleted.list .list > .item:before, -.ui.bulleted.list > .item:before { - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - pointer-events: none; - position: absolute; - top: auto; - left: auto; - font-weight: normal; - margin-left: -1.25rem; - content: '\2022'; - opacity: 1; - color: inherit; - vertical-align: top; -} - -ul.ui.list li:before, -.ui.bulleted.list .list > a.item:before, -.ui.bulleted.list > a.item:before { - color: rgba(0, 0, 0, 0.87); -} - -ul.ui.list ul, -.ui.bulleted.list .list:not(.icon) { - padding-left: 1.25rem; -} - -/* Horizontal Bulleted */ - -ul.ui.horizontal.bulleted.list, -.ui.horizontal.bulleted.list { - margin-left: 0; -} - -ul.ui.horizontal.bulleted.list li, -.ui.horizontal.bulleted.list > .item { - margin-left: 1.75rem; -} - -ul.ui.horizontal.bulleted.list li:first-child, -.ui.horizontal.bulleted.list > .item:first-child { - margin-left: 0; -} - -ul.ui.horizontal.bulleted.list li::before, -.ui.horizontal.bulleted.list > .item::before { - color: rgba(0, 0, 0, 0.87); -} - -ul.ui.horizontal.bulleted.list li:first-child::before, -.ui.horizontal.bulleted.list > .item:first-child::before { - display: none; -} - -/*------------------- - Ordered - --------------------*/ - -ol.ui.list, -.ui.ordered.list, -.ui.ordered.list .list:not(.icon), -ol.ui.list ol { - counter-reset: ordered; - margin-left: 1.25rem; - list-style-type: none; -} - -ol.ui.list li, -.ui.ordered.list .list > .item, -.ui.ordered.list > .item { - list-style-type: none; - position: relative; -} - -ol.ui.list li:before, -.ui.ordered.list .list > .item:before, -.ui.ordered.list > .item:before { - position: absolute; - top: auto; - left: auto; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - pointer-events: none; - margin-left: -1.25rem; - counter-increment: ordered; - content: counters(ordered, ".") " "; - text-align: right; - color: rgba(0, 0, 0, 0.87); - vertical-align: middle; - opacity: 0.8; -} - -/* Value */ - -.ui.ordered.list .list > .item[data-value]:before, -.ui.ordered.list > .item[data-value]:before { - content: attr(data-value); -} - -ol.ui.list li[value]:before { - content: attr(value); -} - -/* Child Lists */ - -ol.ui.list ol, -.ui.ordered.list .list:not(.icon) { - margin-left: 1em; -} - -ol.ui.list ol li:before, -.ui.ordered.list .list > .item:before { - margin-left: -2em; -} - -/* Horizontal Ordered */ - -ol.ui.horizontal.list, -.ui.ordered.horizontal.list { - margin-left: 0; -} - -ol.ui.horizontal.list li:before, -.ui.ordered.horizontal.list .list > .item:before, -.ui.ordered.horizontal.list > .item:before { - position: static; - margin: 0 0.5em 0 0; -} - -/* Suffixed Ordered */ - -ol.ui.suffixed.list li:before, -.ui.suffixed.ordered.list .list > .item:before, -.ui.suffixed.ordered.list > .item:before { - content: counters(ordered, ".") "."; -} - -/*------------------- - Divided - --------------------*/ - -.ui.divided.list > .item { - border-top: 1px solid rgba(34, 36, 38, 0.15); -} - -.ui.divided.list .list > .item { - border-top: none; -} - -.ui.divided.list .item .list > .item { - border-top: none; -} - -.ui.divided.list .list > .item:first-child, -.ui.divided.list > .item:first-child { - border-top: none; -} - -/* Sub Menu */ - -.ui.divided.list:not(.horizontal) .list > .item:first-child { - border-top-width: 1px; -} - -/* Divided bulleted */ - -.ui.divided.bulleted.list:not(.horizontal), -.ui.divided.bulleted.list .list:not(.icon) { - margin-left: 0; - padding-left: 0; -} - -.ui.divided.bulleted.list > .item:not(.horizontal) { - padding-left: 1.25rem; -} - -/* Divided Ordered */ - -.ui.divided.ordered.list { - margin-left: 0; -} - -.ui.divided.ordered.list .list > .item, -.ui.divided.ordered.list > .item { - padding-left: 1.25rem; -} - -.ui.divided.ordered.list .item .list:not(.icon) { - margin-left: 0; - margin-right: 0; - padding-bottom: 0.21428571em; -} - -.ui.divided.ordered.list .item .list > .item { - padding-left: 1em; -} - -/* Divided Selection */ - -.ui.divided.selection.list .list > .item, -.ui.divided.selection.list > .item { - margin: 0; - border-radius: 0; -} - -/* Divided horizontal */ - -.ui.divided.horizontal.list { - margin-left: 0; -} - -.ui.divided.horizontal.list > .item { - padding-left: 0.5em; -} - -.ui.divided.horizontal.list > .item:not(:last-child) { - padding-right: 0.5em; -} - -.ui.divided.horizontal.list > .item { - border-top: none; - border-right: 1px solid rgba(34, 36, 38, 0.15); - margin: 0; - line-height: 0.6; -} - -.ui.horizontal.divided.list > .item:last-child { - border-right: none; -} - -/*------------------- - Celled - --------------------*/ - -.ui.celled.list > .item, -.ui.celled.list > .list { - border-top: 1px solid rgba(34, 36, 38, 0.15); - padding-left: 0.5em; - padding-right: 0.5em; -} - -.ui.celled.list > .item:last-child { - border-bottom: 1px solid rgba(34, 36, 38, 0.15); -} - -/* Padding on all elements */ - -.ui.celled.list > .item:first-child, -.ui.celled.list > .item:last-child { - padding-top: 0.21428571em; - padding-bottom: 0.21428571em; -} - -/* Sub Menu */ - -.ui.celled.list .item .list > .item { - border-width: 0; -} - -.ui.celled.list .list > .item:first-child { - border-top-width: 0; -} - -/* Celled Bulleted */ - -.ui.celled.bulleted.list { - margin-left: 0; -} - -.ui.celled.bulleted.list .list > .item, -.ui.celled.bulleted.list > .item { - padding-left: 1.25rem; -} - -.ui.celled.bulleted.list .item .list:not(.icon) { - margin-left: -1.25rem; - margin-right: -1.25rem; - padding-bottom: 0.21428571em; -} - -/* Celled Ordered */ - -.ui.celled.ordered.list { - margin-left: 0; -} - -.ui.celled.ordered.list .list > .item, -.ui.celled.ordered.list > .item { - padding-left: 1.25rem; -} - -.ui.celled.ordered.list .item .list:not(.icon) { - margin-left: 0; - margin-right: 0; - padding-bottom: 0.21428571em; -} - -.ui.celled.ordered.list .list > .item { - padding-left: 1em; -} - -/* Celled Horizontal */ - -.ui.horizontal.celled.list { - margin-left: 0; -} - -.ui.horizontal.celled.list .list > .item, -.ui.horizontal.celled.list > .item { - border-top: none; - border-left: 1px solid rgba(34, 36, 38, 0.15); - margin: 0; - padding-left: 0.5em; - padding-right: 0.5em; - line-height: 0.6; -} - -.ui.horizontal.celled.list .list > .item:last-child, -.ui.horizontal.celled.list > .item:last-child { - border-bottom: none; - border-right: 1px solid rgba(34, 36, 38, 0.15); -} - -/*------------------- - Relaxed - --------------------*/ - -.ui.relaxed.list:not(.horizontal) > .item:not(:first-child) { - padding-top: 0.42857143em; -} - -.ui.relaxed.list:not(.horizontal) > .item:not(:last-child) { - padding-bottom: 0.42857143em; -} - -.ui.horizontal.relaxed.list .list > .item:not(:first-child), -.ui.horizontal.relaxed.list > .item:not(:first-child) { - padding-left: 1rem; -} - -.ui.horizontal.relaxed.list .list > .item:not(:last-child), -.ui.horizontal.relaxed.list > .item:not(:last-child) { - padding-right: 1rem; -} - -/* Very Relaxed */ - -.ui[class*="very relaxed"].list:not(.horizontal) > .item:not(:first-child) { - padding-top: 0.85714286em; -} - -.ui[class*="very relaxed"].list:not(.horizontal) > .item:not(:last-child) { - padding-bottom: 0.85714286em; -} - -.ui.horizontal[class*="very relaxed"].list .list > .item:not(:first-child), -.ui.horizontal[class*="very relaxed"].list > .item:not(:first-child) { - padding-left: 1.5rem; -} - -.ui.horizontal[class*="very relaxed"].list .list > .item:not(:last-child), -.ui.horizontal[class*="very relaxed"].list > .item:not(:last-child) { - padding-right: 1.5rem; -} - -/*------------------- - Sizes ---------------------*/ - -.ui.list { - font-size: 1em; -} - -.ui.mini.list { - font-size: 0.78571429em; -} - -.ui.mini.horizontal.list .list > .item, -.ui.mini.horizontal.list > .item { - font-size: 0.78571429rem; -} - -.ui.tiny.list { - font-size: 0.85714286em; -} - -.ui.tiny.horizontal.list .list > .item, -.ui.tiny.horizontal.list > .item { - font-size: 0.85714286rem; -} - -.ui.small.list { - font-size: 0.92857143em; -} - -.ui.small.horizontal.list .list > .item, -.ui.small.horizontal.list > .item { - font-size: 0.92857143rem; -} - -.ui.large.list { - font-size: 1.14285714em; -} - -.ui.large.horizontal.list .list > .item, -.ui.large.horizontal.list > .item { - font-size: 1.14285714rem; -} - -.ui.big.list { - font-size: 1.28571429em; -} - -.ui.big.horizontal.list .list > .item, -.ui.big.horizontal.list > .item { - font-size: 1.28571429rem; -} - -.ui.huge.list { - font-size: 1.42857143em; -} - -.ui.huge.horizontal.list .list > .item, -.ui.huge.horizontal.list > .item { - font-size: 1.42857143rem; -} - -.ui.massive.list { - font-size: 1.71428571em; -} - -.ui.massive.horizontal.list .list > .item, -.ui.massive.horizontal.list > .item { - font-size: 1.71428571rem; -} - -/******************************* - Theme Overrides -*******************************/ - -/******************************* - User Variable Overrides -*******************************/ /* * # Fomantic - Menu * http://github.com/fomantic/Fomantic-UI/ diff --git a/web_src/fomantic/semantic.json b/web_src/fomantic/semantic.json index 7ec520f315..5db57bc8d4 100644 --- a/web_src/fomantic/semantic.json +++ b/web_src/fomantic/semantic.json @@ -26,7 +26,6 @@ "dimmer", "dropdown", "form", - "list", "menu", "modal", "search", From 48223909be0511bcd773bceea76918bfd7cc7d46 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 7 Apr 2024 00:27:31 +0000 Subject: [PATCH 029/247] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 7e725b4647..57b2aff254 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -652,7 +652,7 @@ block.unblock.failure=ユーザーのブロック解除に失敗しました: %s block.blocked=あなたはこのユーザーをブロックしています。 block.title=ユーザーをブロックする block.info=ユーザーをブロックすると、そのユーザーは、プルリクエストやイシューの作成、コメントの投稿など、リポジトリに対する操作ができなくなります。 ユーザーのブロックについてはよく確認してください。 -block.info_1=ユーザーをブロックすることで、あなたのアカウントとリポジトリに対する以下の行為を防ぎます: +block.info_1=ユーザーをブロックすることで、あなたのアカウントとあなたのリポジトリに対する以下の行為を阻止します: block.info_2=あなたのアカウントのフォロー block.info_3=あなたのユーザー名で@メンションして通知を送ること block.info_4=そのユーザーのリポジトリに、あなたを共同作業者として招待すること @@ -709,8 +709,8 @@ language=言語 ui=テーマ hidden_comment_types=非表示にするコメントの種類 hidden_comment_types_description=ここでチェックを入れたコメントの種類は、イシューのページには表示されません。 たとえば「ラベル」にチェックを入れると、「<ユーザー> が <ラベル> を追加/削除」といったコメントはすべて除去されます。 -hidden_comment_types.ref_tooltip=このイシューが別のイシューやコミット等から参照されたというコメント -hidden_comment_types.issue_ref_tooltip=このイシューに関連付けるブランチやタグをユーザーが変更したというコメント +hidden_comment_types.ref_tooltip=このイシューが別のイシューやコミット等から参照された、というコメント +hidden_comment_types.issue_ref_tooltip=このイシューのブランチやタグへの関連付けをユーザーが変更した、というコメント comment_type_group_reference=参照 comment_type_group_label=ラベル comment_type_group_milestone=マイルストーン @@ -780,7 +780,7 @@ add_email_success=新しいメールアドレスを追加しました。 email_preference_set_success=メール設定を保存しました。 add_openid_success=新しいOpenIDアドレスを追加しました。 keep_email_private=メールアドレスを隠す -keep_email_private_popup=これによりプロフィールでメールアドレスが隠され、Webインターフェースでのプルリクエスト作成やファイル編集でもメールアドレスが隠されます。 プッシュ済みのコミットは変更されません。 +keep_email_private_popup=あなたのプロフィールからメールアドレスが隠され、Webインターフェースを使ったプルリクエスト作成やファイル編集でも、メールアドレスが隠されます。 プッシュ済みのコミットは変更されません。 コミットであなたのアカウントに関連付ける場合は %s を使用してください。 openid_desc=OpenIDを使うと外部プロバイダーに認証を委任することができます。 manage_ssh_keys=SSHキーの管理 @@ -2961,12 +2961,12 @@ packages.size=サイズ packages.published=配布 defaulthooks=デフォルトWebhook -defaulthooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義されたWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくはWebhooksガイドをご覧下さい。 +defaulthooks.desc=Webhookは、特定のGiteaイベントが発生したときに、サーバーにHTTP POSTリクエストを自動的に送信するものです。 ここで定義したWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくはWebhooksガイドをご覧下さい。 defaulthooks.add_webhook=デフォルトWebhookの追加 defaulthooks.update_webhook=デフォルトWebhookの更新 systemhooks=システムWebhook -systemhooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義したWebhookはシステム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくはWebhooksガイドをご覧下さい。 +systemhooks.desc=Webhookは、特定のGiteaイベントが発生したときに、サーバーにHTTP POSTリクエストを自動的に送信するものです。 ここで定義したWebhookは、システム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくはWebhooksガイドをご覧下さい。 systemhooks.add_webhook=システムWebhookを追加 systemhooks.update_webhook=システムWebhookを更新 @@ -3342,9 +3342,9 @@ raw_seconds=秒 raw_minutes=分 [dropzone] -default_message=ここにファイルをドロップまたはクリックしてアップロードします。 +default_message=ファイルをここにドロップ、またはここをクリックしてアップロード invalid_input_type=この種類のファイルはアップロードできません。 -file_too_big=アップロードされたファイルのサイズ ({{filesize}} MB) が最大サイズ ({{maxFilesize}} MB) を超えています。 +file_too_big=アップロードされたファイルのサイズ ({{filesize}} MB) は、最大サイズ ({{maxFilesize}} MB) を超えています。 remove_file=ファイル削除 [notification] @@ -3369,7 +3369,7 @@ error.no_committer_account=コミッターのメールアドレスに対応す error.no_gpg_keys_found=この署名に対応する既知のキーがデータベースに存在しません error.not_signed_commit=署名されたコミットではありません error.failed_retrieval_gpg_keys=コミッターのアカウントに登録されたキーを取得できませんでした -error.probable_bad_signature=警告! このIDの鍵はデータベースに登録されていますが、その鍵でコミットの検証が通りません! これは疑わしいコミットです。 +error.probable_bad_signature=警告! このIDに該当する鍵がデータベースにありますが、コミットの検証が通りません! これは疑わしいコミットです。 error.probable_bad_default_signature=警告! これはデフォルト鍵のIDですが、デフォルト鍵ではコミットの検証が通りません! これは疑わしいコミットです。 [units] @@ -3382,7 +3382,7 @@ title=パッケージ desc=リポジトリ パッケージを管理します。 empty=パッケージはまだありません。 empty.documentation=パッケージレジストリの詳細については、 ドキュメント を参照してください。 -empty.repo=パッケージはアップロードしたけども、ここに表示されない? パッケージ設定を開いて、パッケージをこのリポジトリにリンクしてください。 +empty.repo=パッケージはアップロード済みで、ここに表示されていないですか? パッケージ設定を開いて、パッケージをこのリポジトリにリンクしてください。 registry.documentation=%sレジストリの詳細については、 ドキュメント を参照してください。 filter.type=タイプ filter.type.all=すべて From bbe5cd7c92ccc3793473ae0163398cdbccdd4246 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 7 Apr 2024 09:11:25 +0800 Subject: [PATCH 030/247] Refactor startup deprecation messages (#30305) It doesn't change logic, it only does: 1. Rename the variable and function names 2. Use more consistent format when mentioning config section&key 3. Improve some messages --- modules/setting/config_provider.go | 16 ++++++++++------ modules/setting/indexer.go | 2 +- modules/setting/oauth2.go | 2 +- modules/setting/repository.go | 2 +- modules/setting/server.go | 2 +- modules/setting/session.go | 2 +- modules/setting/setting.go | 4 +--- modules/setting/storage.go | 2 +- routers/web/admin/admin.go | 18 +++++++++--------- routers/web/admin/config.go | 2 +- templates/admin/self_check.tmpl | 6 +++--- 11 files changed, 30 insertions(+), 28 deletions(-) diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go index 3fa3f3b50b..03f27ba203 100644 --- a/modules/setting/config_provider.go +++ b/modules/setting/config_provider.go @@ -315,21 +315,25 @@ func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting any) { } } -// DeprecatedWarnings contains the warning message for various deprecations, including: setting option, file/folder, etc -var DeprecatedWarnings []string +// StartupProblems contains the messages for various startup problems, including: setting option, file/folder, etc +var StartupProblems []string + +func logStartupProblem(skip int, level log.Level, format string, args ...any) { + msg := fmt.Sprintf(format, args...) + log.Log(skip+1, level, "%s", msg) + StartupProblems = append(StartupProblems, msg) +} func deprecatedSetting(rootCfg ConfigProvider, oldSection, oldKey, newSection, newKey, version string) { if rootCfg.Section(oldSection).HasKey(oldKey) { - msg := fmt.Sprintf("Deprecated config option `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version) - log.Error("%v", msg) - DeprecatedWarnings = append(DeprecatedWarnings, msg) + logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents, please use `[%s].%s` instead because this fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version) } } // deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini func deprecatedSettingDB(rootCfg ConfigProvider, oldSection, oldKey string) { if rootCfg.Section(oldSection).HasKey(oldKey) { - log.Error("Deprecated `[%s]` `%s` present which has been copied to database table sys_setting", oldSection, oldKey) + logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents but it won't take effect because it has been moved to admin panel -> config setting", oldSection, oldKey) } } diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index cec364d370..6877d70e3c 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -58,7 +58,7 @@ func loadIndexerFrom(rootCfg ConfigProvider) { if !filepath.IsAbs(Indexer.IssuePath) { Indexer.IssuePath = filepath.ToSlash(filepath.Join(AppWorkPath, Indexer.IssuePath)) } - checkOverlappedPath("indexer.ISSUE_INDEXER_PATH", Indexer.IssuePath) + checkOverlappedPath("[indexer].ISSUE_INDEXER_PATH", Indexer.IssuePath) } else { Indexer.IssueConnStr = sec.Key("ISSUE_INDEXER_CONN_STR").MustString(Indexer.IssueConnStr) if Indexer.IssueType == "meilisearch" { diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 4d3bfd3eb6..1429a7585c 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -168,7 +168,7 @@ func GetGeneralTokenSigningSecret() []byte { } if generalSigningSecret.CompareAndSwap(old, &jwtSecret) { // FIXME: in main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...) - log.Warn("OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes") + logStartupProblem(1, log.WARN, "OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes") return jwtSecret } return *generalSigningSecret.Load() diff --git a/modules/setting/repository.go b/modules/setting/repository.go index a332d6adb3..8656ebc7ec 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -286,7 +286,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) { RepoRootPath = filepath.Clean(RepoRootPath) } - checkOverlappedPath("repository.ROOT", RepoRootPath) + checkOverlappedPath("[repository].ROOT", RepoRootPath) defaultDetectedCharsetsOrder := make([]string, 0, len(Repository.DetectedCharsetsOrder)) for _, charset := range Repository.DetectedCharsetsOrder { diff --git a/modules/setting/server.go b/modules/setting/server.go index 315faaeb21..7d6ece2727 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -331,7 +331,7 @@ func loadServerFrom(rootCfg ConfigProvider) { if !filepath.IsAbs(PprofDataPath) { PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath) } - checkOverlappedPath("server.PPROF_DATA_PATH", PprofDataPath) + checkOverlappedPath("[server].PPROF_DATA_PATH", PprofDataPath) landingPage := sec.Key("LANDING_PAGE").MustString("home") switch landingPage { diff --git a/modules/setting/session.go b/modules/setting/session.go index 3cb1bfe7b5..afe63bfdb7 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -46,7 +46,7 @@ func loadSessionFrom(rootCfg ConfigProvider) { SessionConfig.ProviderConfig = strings.Trim(sec.Key("PROVIDER_CONFIG").MustString(filepath.Join(AppDataPath, "sessions")), "\" ") if SessionConfig.Provider == "file" && !filepath.IsAbs(SessionConfig.ProviderConfig) { SessionConfig.ProviderConfig = filepath.Join(AppWorkPath, SessionConfig.ProviderConfig) - checkOverlappedPath("session.PROVIDER_CONFIG", SessionConfig.ProviderConfig) + checkOverlappedPath("[session].PROVIDER_CONFIG", SessionConfig.ProviderConfig) } SessionConfig.CookieName = sec.Key("COOKIE_NAME").MustString("i_like_gitea") SessionConfig.CookiePath = AppSubURL diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 6aca9ec6cf..92bb0b6541 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -235,9 +235,7 @@ var configuredPaths = make(map[string]string) func checkOverlappedPath(name, path string) { // TODO: some paths shouldn't overlap (storage.xxx.path), while some could (data path is the base path for storage path) if targetName, ok := configuredPaths[path]; ok && targetName != name { - msg := fmt.Sprintf("Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name) - log.Error("%s", msg) - DeprecatedWarnings = append(DeprecatedWarnings, msg) + logStartupProblem(1, log.ERROR, "Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name) } configuredPaths[path] = name } diff --git a/modules/setting/storage.go b/modules/setting/storage.go index f4e33a53af..aeb61ac513 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -240,7 +240,7 @@ func getStorageForLocal(targetSec, overrideSec ConfigSection, tp targetSecType, } } - checkOverlappedPath("storage."+name+".PATH", storage.Path) + checkOverlappedPath("[storage."+name+"].PATH", storage.Path) return &storage, nil } diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index 4dc0dfdef8..e6585d8833 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -117,11 +117,11 @@ func updateSystemStatus() { sysStatus.NumGC = m.NumGC } -func prepareDeprecatedWarningsAlert(ctx *context.Context) { - if len(setting.DeprecatedWarnings) > 0 { - content := setting.DeprecatedWarnings[0] - if len(setting.DeprecatedWarnings) > 1 { - content += fmt.Sprintf(" (and %d more)", len(setting.DeprecatedWarnings)-1) +func prepareStartupProblemsAlert(ctx *context.Context) { + if len(setting.StartupProblems) > 0 { + content := setting.StartupProblems[0] + if len(setting.StartupProblems) > 1 { + content += fmt.Sprintf(" (and %d more)", len(setting.StartupProblems)-1) } ctx.Flash.Error(content, true) } @@ -136,7 +136,7 @@ func Dashboard(ctx *context.Context) { updateSystemStatus() ctx.Data["SysStatus"] = sysStatus ctx.Data["SSH"] = setting.SSH - prepareDeprecatedWarningsAlert(ctx) + prepareStartupProblemsAlert(ctx) ctx.HTML(http.StatusOK, tplDashboard) } @@ -191,10 +191,10 @@ func DashboardPost(ctx *context.Context) { func SelfCheck(ctx *context.Context) { ctx.Data["PageIsAdminSelfCheck"] = true - ctx.Data["DeprecatedWarnings"] = setting.DeprecatedWarnings - if len(setting.DeprecatedWarnings) == 0 && !setting.IsProd { + ctx.Data["StartupProblems"] = setting.StartupProblems + if len(setting.StartupProblems) == 0 && !setting.IsProd { if time.Now().Unix()%2 == 0 { - ctx.Data["DeprecatedWarnings"] = []string{"This is a test warning message in dev mode"} + ctx.Data["StartupProblems"] = []string{"This is a test warning message in dev mode"} } } diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index 2f5f17e201..48f80dbbf1 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -165,7 +165,7 @@ func Config(ctx *context.Context) { ctx.Data["Loggers"] = log.GetManager().DumpLoggers() config.GetDynGetter().InvalidateCache() - prepareDeprecatedWarningsAlert(ctx) + prepareStartupProblemsAlert(ctx) ctx.HTML(http.StatusOK, tplConfig) } diff --git a/templates/admin/self_check.tmpl b/templates/admin/self_check.tmpl index c100ffd504..a6c2ac1ac9 100644 --- a/templates/admin/self_check.tmpl +++ b/templates/admin/self_check.tmpl @@ -5,11 +5,11 @@ {{ctx.Locale.Tr "admin.self_check"}} - {{if .DeprecatedWarnings}} + {{if .StartupProblems}}
{{ctx.Locale.Tr "admin.self_check.startup_warnings"}}
-
    {{range .DeprecatedWarnings}}
  • {{.}}
  • {{end}}
+
    {{range .StartupProblems}}
  • {{.}}
  • {{end}}
{{end}} @@ -40,7 +40,7 @@
{{end}} - {{if and (not .DeprecatedWarnings) (not .DatabaseCheckHasProblems)}} + {{if and (not .StartupProblems) (not .DatabaseCheckHasProblems)}}
{{ctx.Locale.Tr "admin.self_check.no_problem_found"}}
From 94aad35a120b05897a0b6b97f0d9605a52ea9642 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 7 Apr 2024 10:53:28 +0200 Subject: [PATCH 031/247] Fix right-aligned input icons (#30301) Fix regression from https://github.com/go-gitea/gitea/pull/30194 where right-aligned items would not display correctly. Before and After: Screenshot 2024-04-06 at 01 12 11 Screenshot 2024-04-06 at 01 11 49 Frontpage search tweaked to accommodate (which was the reason for the changes that broken above): Screenshot 2024-04-06 at 01 11 34 Screenshot 2024-04-06 at 01 11 39 --- web_src/css/modules/input.css | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/web_src/css/modules/input.css b/web_src/css/modules/input.css index 48cd2fa9ff..18b785ac82 100644 --- a/web_src/css/modules/input.css +++ b/web_src/css/modules/input.css @@ -48,8 +48,11 @@ cursor: default; position: absolute; text-align: center; - top: 50%; - transform: translateY(-50%); + top: 0; + right: 0; + margin: 0; + height: 100%; + width: 2.67142857em; opacity: 0.5; border-radius: 0 0.28571429rem 0.28571429rem 0; pointer-events: none; @@ -58,6 +61,8 @@ .ui.icon.input > i.icon.is-loading { position: absolute !important; + height: 28px; + top: 4px; } .ui.icon.input > i.icon.is-loading > * { @@ -78,7 +83,7 @@ .ui[class*="left icon"].input > i.icon { right: auto; - left: 8px; + left: 1px; border-radius: 0.28571429rem 0 0 0.28571429rem; } .ui[class*="left icon"].input > i.circular.icon { From 83f83019ef3471b847a300f0821499b3896ec987 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 7 Apr 2024 19:17:06 +0800 Subject: [PATCH 032/247] Clean up log messages (#30313) `log.Xxx("%v")` is not ideal, this PR adds necessary context messages. Remove some unnecessary logs. Co-authored-by: Giteabot --- cmd/web.go | 2 +- models/asymkey/ssh_key_fingerprint.go | 17 ++++------------- models/repo/issue.go | 2 +- modules/util/util.go | 2 +- routers/api/v1/notify/repo.go | 2 -- routers/private/actions.go | 16 ++++++++-------- routers/private/hook_verification.go | 3 +-- routers/private/mail.go | 2 +- routers/web/admin/users.go | 1 - routers/web/auth/password.go | 2 -- routers/web/user/setting/account.go | 1 - services/context/captcha.go | 4 ++-- services/notify/notify.go | 4 ++-- services/repository/files/cherry_pick.go | 2 +- services/repository/files/patch.go | 2 +- services/repository/files/update.go | 2 +- services/wiki/wiki.go | 14 +++++++------- 17 files changed, 31 insertions(+), 47 deletions(-) diff --git a/cmd/web.go b/cmd/web.go index 01386251be..ef8a7426c1 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -114,7 +114,7 @@ func showWebStartupMessage(msg string) { log.Info("* WorkPath: %s", setting.AppWorkPath) log.Info("* CustomPath: %s", setting.CustomPath) log.Info("* ConfigFile: %s", setting.CustomConf) - log.Info("%s", msg) + log.Info("%s", msg) // show startup message } func serveInstall(ctx *cli.Context) error { diff --git a/models/asymkey/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go index b9cfb1b251..1ed3b5df2a 100644 --- a/models/asymkey/ssh_key_fingerprint.go +++ b/models/asymkey/ssh_key_fingerprint.go @@ -76,23 +76,14 @@ func calcFingerprintNative(publicKeyContent string) (string, error) { // CalcFingerprint calculate public key's fingerprint func CalcFingerprint(publicKeyContent string) (string, error) { // Call the method based on configuration - var ( - fnName, fp string - err error - ) - if len(setting.SSH.KeygenPath) == 0 { - fnName = "calcFingerprintNative" - fp, err = calcFingerprintNative(publicKeyContent) - } else { - fnName = "calcFingerprintSSHKeygen" - fp, err = calcFingerprintSSHKeygen(publicKeyContent) - } + useNative := setting.SSH.KeygenPath == "" + calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen) + fp, err := calcFn(publicKeyContent) if err != nil { if IsErrKeyUnableVerify(err) { - log.Info("%s", publicKeyContent) return "", err } - return "", fmt.Errorf("%s: %w", fnName, err) + return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err) } return fp, nil } diff --git a/models/repo/issue.go b/models/repo/issue.go index 6f6b565a00..0dd4fd5ed4 100644 --- a/models/repo/issue.go +++ b/models/repo/issue.go @@ -53,7 +53,7 @@ func (repo *Repository) IsDependenciesEnabled(ctx context.Context) bool { var u *RepoUnit var err error if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { - log.Trace("%s", err) + log.Trace("IsDependenciesEnabled: %v", err) return setting.Service.DefaultEnableDependencies } return u.IssuesConfig().EnableDependencies diff --git a/modules/util/util.go b/modules/util/util.go index 3921002e2a..44b5a6ed81 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -214,7 +214,7 @@ func ToPointer[T any](val T) *T { } // Iif is an "inline-if", it returns "trueVal" if "condition" is true, otherwise "falseVal" -func Iif[T comparable](condition bool, trueVal, falseVal T) T { +func Iif[T any](condition bool, trueVal, falseVal T) T { if condition { return trueVal } diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index 8d97e8a3f8..1744426ee8 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -10,7 +10,6 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" @@ -201,7 +200,6 @@ func ReadRepoNotifications(ctx *context.APIContext) { if !ctx.FormBool("all") { statuses := ctx.FormStrings("status-types") opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"}) - log.Error("%v", opts.Status) } nl, err := db.Find[activities_model.Notification](ctx, opts) if err != nil { diff --git a/routers/private/actions.go b/routers/private/actions.go index 53c2412308..696634b5e7 100644 --- a/routers/private/actions.go +++ b/routers/private/actions.go @@ -26,7 +26,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { defer rd.Close() if err := json.NewDecoder(rd).Decode(&genRequest); err != nil { - log.Error("%v", err) + log.Error("JSON Decode failed: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), }) @@ -35,7 +35,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { owner, repo, err := parseScope(ctx, genRequest.Scope) if err != nil { - log.Error("%v", err) + log.Error("parseScope failed: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), }) @@ -45,18 +45,18 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { token, err = actions_model.NewRunnerToken(ctx, owner, repo) if err != nil { - err := fmt.Sprintf("error while creating runner token: %v", err) - log.Error("%v", err) + errMsg := fmt.Sprintf("error while creating runner token: %v", err) + log.Error("NewRunnerToken failed: %v", errMsg) ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: err, + Err: errMsg, }) return } } else if err != nil { - err := fmt.Sprintf("could not get unactivated runner token: %v", err) - log.Error("%v", err) + errMsg := fmt.Sprintf("could not get unactivated runner token: %v", err) + log.Error("GetLatestRunnerToken failed: %v", errMsg) ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: err, + Err: errMsg, }) return } diff --git a/routers/private/hook_verification.go b/routers/private/hook_verification.go index 42b8e5abed..764c976fa9 100644 --- a/routers/private/hook_verification.go +++ b/routers/private/hook_verification.go @@ -47,7 +47,7 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env [] _ = stdoutWriter.Close() err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env) if err != nil { - log.Error("%v", err) + log.Error("readAndVerifyCommitsFromShaReader failed: %v", err) cancel() } _ = stdoutReader.Close() @@ -66,7 +66,6 @@ func readAndVerifyCommitsFromShaReader(input io.ReadCloser, repo *git.Repository line := scanner.Text() err := readAndVerifyCommit(line, repo, env) if err != nil { - log.Error("%v", err) return err } } diff --git a/routers/private/mail.go b/routers/private/mail.go index c19ee67896..cf3abb31c6 100644 --- a/routers/private/mail.go +++ b/routers/private/mail.go @@ -35,7 +35,7 @@ func SendEmail(ctx *context.PrivateContext) { defer rd.Close() if err := json.NewDecoder(rd).Decode(&mail); err != nil { - log.Error("%v", err) + log.Error("JSON Decode failed: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), }) diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index b93668c5a2..ea9d6f4c9c 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -403,7 +403,6 @@ func EditUserPost(ctx *context.Context) { ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplUserEdit, &form) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form) default: diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index f6b76c1ffd..0e88fe68f9 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -214,7 +214,6 @@ func ResetPasswdPost(ctx *context.Context) { case errors.Is(err, password.ErrIsPwned): ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplResetPassword, nil) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplResetPassword, nil) default: ctx.ServerError("UpdateAuth", err) @@ -298,7 +297,6 @@ func MustChangePasswordPost(ctx *context.Context) { ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplMustChangePassword, &form) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplMustChangePassword, &form) default: diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index c93b70af76..8ea7548e51 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -74,7 +74,6 @@ func AccountPost(ctx *context.Context) { case errors.Is(err, password.ErrIsPwned): ctx.Flash.Error(ctx.Tr("auth.password_pwned")) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.Flash.Error(ctx.Tr("auth.password_pwned_err")) default: ctx.ServerError("UpdateAuth", err) diff --git a/services/context/captcha.go b/services/context/captcha.go index a1999900c9..fa8d779f56 100644 --- a/services/context/captcha.go +++ b/services/context/captcha.go @@ -79,11 +79,11 @@ func VerifyCaptcha(ctx *Context, tpl base.TplName, form any) { case setting.CfTurnstile: valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField)) default: - ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) + ctx.ServerError("Unknown Captcha Type", fmt.Errorf("unknown Captcha Type: %s", setting.Service.CaptchaType)) return } if err != nil { - log.Debug("%v", err) + log.Debug("Captcha Verify failed: %v", err) } if !valid { diff --git a/services/notify/notify.go b/services/notify/notify.go index 16fbb6325d..0c8262ef7a 100644 --- a/services/notify/notify.go +++ b/services/notify/notify.go @@ -91,7 +91,7 @@ func AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues // NewPullRequest notifies new pull request to notifiers func NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) { if err := pr.LoadIssue(ctx); err != nil { - log.Error("%v", err) + log.Error("LoadIssue failed: %v", err) return } if err := pr.Issue.LoadPoster(ctx); err != nil { @@ -112,7 +112,7 @@ func PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *iss // PullRequestReview notifies new pull request review func PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { if err := review.LoadReviewer(ctx); err != nil { - log.Error("%v", err) + log.Error("LoadReviewer failed: %v", err) return } for _, notifier := range notifiers { diff --git a/services/repository/files/cherry_pick.go b/services/repository/files/cherry_pick.go index 613b46d8f6..451a182155 100644 --- a/services/repository/files/cherry_pick.go +++ b/services/repository/files/cherry_pick.go @@ -28,7 +28,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod t, err := NewTemporaryUploadRepository(ctx, repo) if err != nil { - log.Error("%v", err) + log.Error("NewTemporaryUploadRepository failed: %v", err) } defer t.Close() if err := t.Clone(opts.OldBranch, false); err != nil { diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index f6d5643dc9..e5f7e2af96 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -111,7 +111,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user t, err := NewTemporaryUploadRepository(ctx, repo) if err != nil { - log.Error("%v", err) + log.Error("NewTemporaryUploadRepository failed: %v", err) } defer t.Close() if err := t.Clone(opts.OldBranch, true); err != nil { diff --git a/services/repository/files/update.go b/services/repository/files/update.go index 4f7178184b..f029a9aefe 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -143,7 +143,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use t, err := NewTemporaryUploadRepository(ctx, repo) if err != nil { - log.Error("%v", err) + log.Error("NewTemporaryUploadRepository failed: %v", err) } defer t.Close() hasOldBranch := true diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index 1b921a44bd..f8387416c1 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -161,7 +161,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model if isOldWikiExist { err := gitRepo.RemoveFilesFromIndex(oldWikiPath) if err != nil { - log.Error("%v", err) + log.Error("RemoveFilesFromIndex failed: %v", err) return err } } @@ -171,18 +171,18 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model objectHash, err := gitRepo.HashObject(strings.NewReader(content)) if err != nil { - log.Error("%v", err) + log.Error("HashObject failed: %v", err) return err } if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil { - log.Error("%v", err) + log.Error("AddObjectToIndex failed: %v", err) return err } tree, err := gitRepo.WriteTree() if err != nil { - log.Error("%v", err) + log.Error("WriteTree failed: %v", err) return err } @@ -207,7 +207,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), committer, tree, commitTreeOpts) if err != nil { - log.Error("%v", err) + log.Error("CommitTree failed: %v", err) return err } @@ -222,11 +222,11 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model 0, ), }); err != nil { - log.Error("%v", err) + log.Error("Push failed: %v", err) if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) { return err } - return fmt.Errorf("Push: %w", err) + return fmt.Errorf("failed to push: %w", err) } return nil From 644ade5ae6805a3db063b3f81a596febe49bacaf Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 7 Apr 2024 14:36:33 +0200 Subject: [PATCH 033/247] Fix checkboxes on mobile view, remove some dead css (#30308) Fix the checkbox issues in https://github.com/go-gitea/gitea/issues/30303 which were existing problems with these selectors, but made visible with https://github.com/go-gitea/gitea/pull/30162. There is a lot of dead/useless CSS in `form.css`, I only fixed the two problems and remove CSS that was definitely not in use or needed. Screenshot 2024-04-06 at 18 00 08 Screenshot 2024-04-06 at 18 00 28 Co-authored-by: Giteabot --- web_src/css/form.css | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/web_src/css/form.css b/web_src/css/form.css index 2a976c056d..a8f73b6b66 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -249,21 +249,6 @@ textarea:focus, .user.signup form .optional .title { margin-left: 250px !important; } - .user.activate form .inline.field > input, - .user.forgot.password form .inline.field > input, - .user.reset.password form .inline.field > input, - .user.link-account form .inline.field > input, - .user.signin form .inline.field > input, - .user.signup form .inline.field > input, - .user.activate form .inline.field > textarea, - .user.forgot.password form .inline.field > textarea, - .user.reset.password form .inline.field > textarea, - .user.link-account form .inline.field > textarea, - .user.signin form .inline.field > textarea, - .user.signup form .inline.field > textarea, - .oauth-login-link { - width: 50%; - } } @media (max-width: 767.98px) { @@ -310,14 +295,7 @@ textarea:focus, .user.reset.password form .inline.field > label, .user.link-account form .inline.field > label, .user.signin form .inline.field > label, - .user.signup form .inline.field > label, - .user.activate form input, - .user.forgot.password form input, - .user.reset.password form input, - .user.link-account form input, - .user.signin form input, - .user.signup form input, - .oauth-login-link { + .user.signup form .inline.field > label { width: 100% !important; } } @@ -435,9 +413,9 @@ textarea:focus, .repository.new.repo form label, .repository.new.migrate form label, .repository.new.fork form label, - .repository.new.repo form input, - .repository.new.migrate form input, - .repository.new.fork form input, + .repository.new.repo form .inline.field > input, + .repository.new.migrate form .inline.field > input, + .repository.new.fork form .inline.field > input, .repository.new.fork form .field a, .repository.new.repo form .selection.dropdown, .repository.new.migrate form .selection.dropdown, From 0178eaec256a349371c75e582edd7fefca2085d0 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 7 Apr 2024 14:41:42 +0200 Subject: [PATCH 034/247] Action view mobile improvements and fixes (#30309) Fix the action issue in https://github.com/go-gitea/gitea/issues/30303, specifically: - Use opaque step header hover background to avoid transparency issue - Un-sticky the `action-view-left` on mobile, it would otherwise overlap into right view - Improve commit summary, let it wrap - Fix and comment z-indexes - Tweak width for run-list-item-right so it wastes less space on desktop - Synced latest changes to console colors from dark to light theme Screenshot 2024-04-06 at 18 58 15 --- web_src/css/actions.css | 2 +- web_src/css/themes/theme-gitea-dark.css | 2 +- web_src/css/themes/theme-gitea-light.css | 12 +++++----- web_src/js/components/RepoActionView.vue | 28 +++++++++++++++++++----- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/web_src/css/actions.css b/web_src/css/actions.css index e7b9a3855a..1d5bea2395 100644 --- a/web_src/css/actions.css +++ b/web_src/css/actions.css @@ -44,7 +44,7 @@ } .run-list-item-right { - flex: 0 0 15%; + flex: 0 0 min(20%, 130px); display: flex; flex-direction: column; gap: 3px; diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 07e217742d..ed6718e40c 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -65,7 +65,7 @@ --color-console-fg-subtle: #bec4c8; --color-console-bg: #171b1e; --color-console-border: #2e353b; - --color-console-hover-bg: #e8e8ff16; + --color-console-hover-bg: #292d31; --color-console-active-bg: #2e353b; --color-console-menu-bg: #252b30; --color-console-menu-border: #424b51; diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index 2741e0e0bd..b10ad7d840 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -63,12 +63,12 @@ /* console colors - used for actions console and console files */ --color-console-fg: #f8f8f9; --color-console-fg-subtle: #bec4c8; - --color-console-bg: #181b1d; - --color-console-border: #313538; - --color-console-hover-bg: #ffffff16; - --color-console-active-bg: #313538; - --color-console-menu-bg: #272b2e; - --color-console-menu-border: #464a4d; + --color-console-bg: #171b1e; + --color-console-border: #2e353b; + --color-console-hover-bg: #292d31; + --color-console-active-bg: #2e353b; + --color-console-menu-bg: #252b30; + --color-console-menu-border: #424b51; /* named colors */ --color-red: #db2828; --color-orange: #f2711c; diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 75cd1db70a..06c42f0b35 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -517,8 +517,16 @@ export function initRepositoryActionView() { .action-commit-summary { display: flex; + flex-wrap: wrap; gap: 5px; - margin: 0 0 0 28px; + margin-left: 28px; +} + +@media (max-width: 767.98px) { + .action-commit-summary { + margin-left: 0; + margin-top: 8px; + } } /* ================ */ @@ -531,6 +539,14 @@ export function initRepositoryActionView() { top: 12px; max-height: 100vh; overflow-y: auto; + background: var(--color-body); + z-index: 2; /* above .job-info-header */ +} + +@media (max-width: 767.98px) { + .action-view-left { + position: static; /* can not sticky because multiple jobs would overlap into right view */ + } } .job-artifacts-title { @@ -692,7 +708,9 @@ export function initRepositoryActionView() { position: sticky; top: 0; height: 60px; - z-index: 1; + z-index: 1; /* above .job-step-container */ + background: var(--color-console-bg); + border-radius: 3px; } .job-info-header:has(+ .job-step-container) { @@ -730,7 +748,7 @@ export function initRepositoryActionView() { .job-step-container .job-step-summary.step-expandable:hover { color: var(--color-console-fg); - background-color: var(--color-console-hover-bg); + background: var(--color-console-hover-bg); } .job-step-container .job-step-summary .step-summary-msg { @@ -748,17 +766,15 @@ export function initRepositoryActionView() { top: 60px; } -@media (max-width: 768px) { +@media (max-width: 767.98px) { .action-view-body { flex-direction: column; } .action-view-left, .action-view-right { width: 100%; } - .action-view-left { max-width: none; - overflow-y: hidden; } } From 019857a7015cae32c12b5eac0b895c05f0264b77 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 7 Apr 2024 17:45:36 +0200 Subject: [PATCH 035/247] Add `--page-spacing` variable, fix admin dashboard notice (#30302) Fixes https://github.com/go-gitea/gitea/issues/30293 and introduce the `--page-spacing` variable which holds the spacing between the elements on the page. This is working vertically for all pages, including ones that have fomantic grid, and horizontally for all that use `flex-container`. The `.page-content > :first-child:not(.secondary-nav)` selector uses margin which in some cases enables to adjacent margins to overlap, which is nice. Screenshot 2024-04-06 at 01 35 19 --- Screenshot 2024-04-06 at 01 35 45 --- Screenshot 2024-04-06 at 01 35 31 --- templates/user/notification/notification_div.tmpl | 2 +- web_src/css/base.css | 12 ++++++++---- web_src/css/modules/flexcontainer.css | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/templates/user/notification/notification_div.tmpl b/templates/user/notification/notification_div.tmpl index 04e79ba749..bf3b51ee3b 100644 --- a/templates/user/notification/notification_div.tmpl +++ b/templates/user/notification/notification_div.tmpl @@ -1,7 +1,7 @@
{{$notificationUnreadCount := call .NotificationUnreadCount}} -
+
- +

Input with SVG

@@ -271,10 +243,6 @@ button dropdown {{svg "octicon-triangle-down" 14 "dropdown icon"}}
-
@@ -290,10 +258,6 @@ button compact {{svg "octicon-triangle-down" 14 "dropdown icon"}}
-
diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index 9311a46e38..b9e55dd587 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -79,7 +79,7 @@
{{if .IsOrganizationOwner}} {{end}}
diff --git a/templates/repo/code/recently_pushed_new_branches.tmpl b/templates/repo/code/recently_pushed_new_branches.tmpl index 17ae7d119d..b808f413d3 100644 --- a/templates/repo/code/recently_pushed_new_branches.tmpl +++ b/templates/repo/code/recently_pushed_new_branches.tmpl @@ -5,7 +5,7 @@ {{$branchLink := HTMLFormat `%s` $.RepoLink (PathEscapeSegments .Name) .Name}} {{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" $branchLink $timeSince}}
- + {{ctx.Locale.Tr "repo.pulls.compare_changes"}}
diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index d0472577d0..f927501197 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -184,23 +184,15 @@ {{end}} {{else if and .PageIsComparePull (gt .CommitCount 0)}} {{if .HasPullRequest}} -
-
- {{ctx.Locale.Tr "repo.pulls.has_pull_request" (print $.RepoLink "/pulls/" .PullRequest.Issue.Index) $.RepoRelPath .PullRequest.Index}} -

- {{RenderIssueTitle $.Context .PullRequest.Issue.Title ($.Repository.ComposeMetas ctx)}} - #{{.PullRequest.Issue.Index}} -

-
-
- {{- if .PullRequest.HasMerged -}} - {{svg "octicon-git-merge" 16}} {{ctx.Locale.Tr "repo.pulls.view"}} - {{else if .Issue.IsClosed}} - {{svg "octicon-issue-closed" 16}} {{ctx.Locale.Tr "repo.pulls.view"}} - {{else}} - {{svg "octicon-git-pull-request" 16}} {{ctx.Locale.Tr "repo.pulls.view"}} - {{end}} +
+ {{template "shared/issueicon" .}} +
+ {{RenderIssueTitle $.Context .PullRequest.Issue.Title ($.Repository.ComposeMetas ctx) | RenderCodeBlock}} + #{{.PullRequest.Issue.Index}}
+ + {{ctx.Locale.Tr "repo.pulls.view"}} +
{{else}} {{if and $.IsSigned (not .Repository.IsArchived)}} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 7040c2849a..bb0bb2cff3 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -572,7 +572,7 @@ {{end}} -
diff --git a/templates/repo/settings/lfs_pointers.tmpl b/templates/repo/settings/lfs_pointers.tmpl index a0bb8c46f0..758aec6bb0 100644 --- a/templates/repo/settings/lfs_pointers.tmpl +++ b/templates/repo/settings/lfs_pointers.tmpl @@ -37,7 +37,7 @@ - + {{ShortSha .Oid}} diff --git a/templates/repo/settings/webhook/history.tmpl b/templates/repo/settings/webhook/history.tmpl index 8ee1446a16..149840b0de 100644 --- a/templates/repo/settings/webhook/history.tmpl +++ b/templates/repo/settings/webhook/history.tmpl @@ -6,7 +6,7 @@
- diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index 5e2ffc3bb3..8baa07c90b 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -109,7 +109,7 @@

{{ctx.Locale.Tr "settings.access_token_deletion_desc"}}

- {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}} + {{template "base/modal_actions_confirm"}}
{{template "user/settings/layout_footer" .}} diff --git a/web_src/css/base.css b/web_src/css/base.css index 20f3616177..b3f87044e0 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -663,10 +663,6 @@ input:-webkit-autofill:active, font-size: 0.75em; } -.ui.form .ui.button { - font-weight: var(--font-weight-normal); -} - /* popover box shadows */ .ui.dropdown .menu, .ui.upward.dropdown > .menu, @@ -1347,10 +1343,6 @@ table th[data-sortt-desc] .svg { vertical-align: middle; } -.ui.ui.button { - justify-content: center; -} - .ui.dropdown .ui.label .svg { vertical-align: middle; } diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index 118c058b19..cf2e73572c 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -52,6 +52,9 @@ only use: */ .tw-hidden.tw-hidden { display: none !important; } +/* proposed class from https://github.com/tailwindlabs/tailwindcss/pull/12128 */ +.tw-break-anywhere { overflow-wrap: anywhere !important; } + @media (max-width: 767.98px) { /* double selector so it wins over .tw-flex (old .gt-df) etc */ .not-mobile.not-mobile { diff --git a/web_src/css/modules/button.css b/web_src/css/modules/button.css index faeed8c9a1..47f55df7fa 100644 --- a/web_src/css/modules/button.css +++ b/web_src/css/modules/button.css @@ -1,11 +1,33 @@ -/* this contains override styles for buttons and related elements */ +/* based on Fomantic UI checkbox module, with just the parts extracted that we use. If you find any + unused rules here after refactoring, please remove them. */ -/* these styles changed the Fomantic UI's rules, Fomantic UI expects only "basic" buttons have borders */ -.ui.button, -.ui.button:focus { +.ui.button { + cursor: pointer; + display: inline-block; + min-height: 1em; + outline: none; + vertical-align: baseline; + font-family: var(--fonts-regular); + margin: 0 0.25em 0 0; + padding: 0.78571429em 1.5em; + font-weight: var(--font-weight-normal); + text-align: center; + text-decoration: none; + line-height: 1; + border-radius: 0.28571429rem; + user-select: none; + -webkit-tap-highlight-color: transparent; + justify-content: center; background: var(--color-button); border: 1px solid var(--color-light-border); color: var(--color-text); + white-space: nowrap; +} + +@media (max-width: 767.98px) { + .ui.button { + white-space: normal; + } } .ui.button:hover { @@ -13,10 +35,6 @@ color: var(--color-text); } -.page-content .ui.button { - box-shadow: none !important; -} - .ui.active.button, .ui.button:active, .ui.active.button:active, @@ -25,6 +43,286 @@ color: var(--color-text); } +.ui.buttons .disabled.button:not(.basic), +.ui.disabled.button, +.ui.button:disabled, +.ui.disabled.button:hover, +.ui.disabled.active.button { + cursor: default; + opacity: var(--opacity-disabled) !important; + background-image: none; + pointer-events: none !important; +} + +.ui.labeled.button:not(.icon) { + display: inline-flex; + flex-direction: row; + background: none; + padding: 0 !important; + border: none; +} +.ui.labeled.button > .button { + margin: 0; +} +.ui.labeled.button > .label { + display: flex; + align-items: center; + margin: 0 0 0 -1px !important; + font-size: 1em; + border-color: var(--color-light-border); +} + +.ui.button > .icon:not(.button) { + height: auto; + opacity: 0.8; +} +.ui.button:not(.icon) > .icon:not(.button):not(.dropdown), +.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) { + margin: 0 0.42857143em 0 -0.21428571em; + vertical-align: baseline; +} +.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) > .icon { + vertical-align: baseline; +} +.ui.button:not(.icon) > .right.icon:not(.button):not(.dropdown) { + margin: 0 -0.21428571em 0 0.42857143em; +} + +.ui.compact.buttons .button, +.ui.compact.button { + padding: 0.58928571em 1.125em; +} +.ui.compact.icon.buttons .button, +.ui.compact.icon.button { + padding: 0.58928571em; +} +.ui.compact.labeled.icon.button { + padding: 0.58928571em 3.69642857em; +} +.ui.compact.labeled.icon.button > .icon { + padding: 0.58928571em 0; +} + +.ui.buttons .button, +.ui.button { + font-size: 1rem; +} +.ui.mini.buttons .dropdown, +.ui.mini.buttons .dropdown .menu > .item, +.ui.mini.buttons .button, +.ui.ui.ui.ui.mini.button { + font-size: 0.78571429rem; +} +.ui.tiny.buttons .dropdown, +.ui.tiny.buttons .dropdown .menu > .item, +.ui.tiny.buttons .button, +.ui.ui.ui.ui.tiny.button { + font-size: 0.85714286rem; +} +.ui.small.buttons .dropdown, +.ui.small.buttons .dropdown .menu > .item, +.ui.small.buttons .button, +.ui.ui.ui.ui.small.button { + font-size: 0.92857143rem; +} + +.ui.icon.buttons .button, +.ui.icon.button:not(.compact) { + padding: 0.78571429em; +} +.ui.icon.buttons .button > .icon, +.ui.icon.button > .icon { + margin: 0 !important; + vertical-align: top; +} + +.ui.basic.buttons .button, +.ui.basic.button { + border-radius: 0.28571429rem; + background: none; +} +.ui.basic.buttons { + border: 1px solid var(--color-secondary); + border-radius: 0.28571429rem; +} +.ui.basic.buttons .button { + border-radius: 0; + border-left: 1px solid var(--color-secondary); +} + +.ui.labeled.button.disabled > .button, +.ui.basic.buttons .button, +.ui.basic.button { + color: var(--color-text-light); + background: var(--color-button); +} + +.ui.basic.buttons .button:hover, +.ui.basic.button:hover { + color: var(--color-text); + background: var(--color-hover); + border-color: var(--color-secondary-dark-2); +} + +.ui.basic.buttons .button:active, +.ui.basic.button:active, +.ui.basic.buttons .active.button, +.ui.basic.active.button, +.ui.basic.buttons .active.button:hover, +.ui.basic.active.button:hover { + color: var(--color-text); + background: var(--color-active); +} + +.ui.labeled.icon.button { + position: relative; + padding-left: 4.07142857em !important; + padding-right: 1.5em !important; +} + +.ui.labeled.icon.button > .icon { + position: absolute; + top: 0; + left: 0; + height: 100%; + line-height: 1; + border-radius: 0; + border-top-left-radius: inherit; + border-bottom-left-radius: inherit; + text-align: center; + animation: none; + padding: 0.78571429em 0; + margin: 0; + width: 2.57142857em; + background: var(--color-hover); +} + +.ui.button.toggle.active { + background-color: var(--color-green); + color: var(--color-white); +} +.ui.button.toggle.active:hover { + background-color: var(--color-green-dark-1); + color: var(--color-white); +} + +.ui.fluid.button { + width: 100%; + display: block; +} + +.ui.primary.button, +.ui.primary.buttons .button { + background: var(--color-primary); + color: var(--color-primary-contrast); +} + +.ui.primary.button:hover, +.ui.primary.buttons .button:hover { + background: var(--color-primary-hover); + color: var(--color-primary-contrast); +} + +.ui.primary.button:active, +.ui.primary.buttons .button:active { + background: var(--color-primary-active); +} + +.ui.basic.primary.buttons .button, +.ui.basic.primary.button { + color: var(--color-primary); + border-color: var(--color-primary); + background: none; +} + +.ui.basic.primary.buttons .button:hover, +.ui.basic.primary.button:hover { + color: var(--color-primary-hover); + border-color: var(--color-primary-hover); +} + +.ui.basic.primary.buttons .button:active, +.ui.basic.primary.button:active { + color: var(--color-primary-active); + border-color: var(--color-primary-active); +} + +.ui.red.button, +.ui.red.buttons .button { + background: var(--color-red); +} + +.ui.red.button:hover, +.ui.red.buttons .button:hover { + background: var(--color-red-dark-1); +} + +.ui.red.button:active, +.ui.red.buttons .button:active { + background: var(--color-red-dark-2); +} + +.ui.basic.red.buttons .button, +.ui.basic.red.button { + color: var(--color-red); + border-color: var(--color-red); + background: none; +} + +.ui.basic.red.buttons .button:hover, +.ui.basic.red.button:hover { + color: var(--color-red-dark-1); + border-color: var(--color-red-dark-1); +} + +.ui.basic.red.buttons .button:active, +.ui.basic.red.button:active { + color: var(--color-red-dark-2); + border-color: var(--color-red-dark-2); +} + +.ui.green.button, +.ui.green.buttons .button { + background: var(--color-green); +} + +.ui.green.button:hover, +.ui.green.buttons .button:hover { + background: var(--color-green-dark-1); +} + +.ui.green.button:active, +.ui.green.buttons .button:active { + background: var(--color-green-dark-2); +} + +.ui.basic.green.buttons .button, +.ui.basic.green.button { + color: var(--color-green); + border-color: var(--color-green); + background: none; +} + +.ui.basic.green.buttons .button:hover, +.ui.basic.green.button:hover { + color: var(--color-green-dark-1); + border-color: var(--color-green-dark-1); +} + +.ui.basic.green.buttons .button:active, +.ui.basic.green.button:active { + color: var(--color-green-dark-2); + border-color: var(--color-green-dark-2); +} + +.ui.buttons { + display: inline-flex; + flex-direction: row; + font-size: 0; + vertical-align: baseline; + margin: 0 0.25em 0 0; +} + .delete-button, .delete-button:hover { color: var(--color-red); @@ -42,8 +340,7 @@ } .btn:hover, -.btn:active, -.btn:focus { +.btn:active { background: none; border: none; } @@ -59,6 +356,19 @@ It needs some tricks to tweak the left/right borders with active state */ .ui.buttons .button { border-right: none; + flex: 1 0 auto; + border-radius: 0; + margin: 0; +} +.ui.buttons .button:first-child { + border-left: none; + margin-left: 0; + border-top-left-radius: 0.28571429rem; + border-bottom-left-radius: 0.28571429rem; +} +.ui.buttons .button:last-child { + border-top-right-radius: 0.28571429rem; + border-bottom-right-radius: 0.28571429rem; } .ui.buttons .button:hover { @@ -89,664 +399,9 @@ It needs some tricks to tweak the left/right borders with active state */ border-left: none; } -.ui.basic.buttons .button, -.ui.basic.button, -.ui.basic.buttons .button:hover, -.ui.basic.button:hover { - box-shadow: none; -} - /* apply the vertical padding of .compact to non-compact buttons when they contain a svg as they would otherwise appear too large. Seen on "RSS Feed" button on repo releases tab. */ .ui.small.button:not(.compact):has(.svg) { padding-top: 0.58928571em; padding-bottom: 0.58928571em; } - -.ui.labeled.button.disabled > .button, -.ui.basic.buttons .button, -.ui.basic.button, -.ui.basic.buttons .button:focus, -.ui.basic.button:focus { - color: var(--color-text-light); - background: var(--color-button); -} - -.ui.basic.buttons .button:hover, -.ui.basic.button:hover { - color: var(--color-text); - background: var(--color-hover); - border-color: var(--color-secondary-dark-2); -} - -.ui.basic.buttons .button:active, -.ui.basic.button:active, -.ui.basic.buttons .active.button, -.ui.basic.active.button, -.ui.basic.buttons .active.button:hover, -.ui.basic.active.button:hover { - color: var(--color-text); - background: var(--color-active); -} - -.ui.labeled.button > .label { - border-color: var(--color-light-border); -} - -.ui.labeled.icon.buttons > .button > .icon, -.ui.labeled.icon.button > .icon { - background: var(--color-hover); -} - -/* primary */ - -.ui.primary.labels .label, -.ui.ui.ui.primary.label, -.ui.primary.button, -.ui.primary.buttons .button, -.ui.primary.button:focus, -.ui.primary.buttons .button:focus { - background: var(--color-primary); - color: var(--color-primary-contrast); -} - -.ui.primary.button:hover, -.ui.primary.buttons .button:hover { - background: var(--color-primary-hover); - color: var(--color-primary-contrast); -} - -.ui.primary.button:active, -.ui.primary.buttons .button:active { - background: var(--color-primary-active); -} - -.ui.basic.primary.buttons .button, -.ui.basic.primary.button, -.ui.basic.primary.buttons .button:focus, -.ui.basic.primary.button:focus { - color: var(--color-primary); - border-color: var(--color-primary); -} - -.ui.basic.primary.buttons .button:hover, -.ui.basic.primary.button:hover { - color: var(--color-primary-hover); - border-color: var(--color-primary-hover); -} - -.ui.basic.primary.buttons .button:active, -.ui.basic.primary.button:active { - color: var(--color-primary-active); - border-color: var(--color-primary-active); -} - -/* secondary */ - -.ui.secondary.labels .label, -.ui.ui.ui.secondary.label, -.ui.secondary.button, -.ui.secondary.buttons .button, -.ui.secondary.button:focus, -.ui.secondary.buttons .button:focus { - background: var(--color-secondary-button); -} - -.ui.secondary.button:hover, -.ui.secondary.buttons .button:hover { - background: var(--color-secondary-hover); -} - -.ui.secondary.button:active, -.ui.secondary.buttons .button:active { - background: var(--color-secondary-active); -} - -.ui.basic.secondary.buttons .button, -.ui.basic.secondary.button, -.ui.basic.secondary.button:focus, -.ui.basic.secondary.buttons .button:focus { - color: var(--color-secondary-button); - border-color: var(--color-secondary-button); -} - -.ui.basic.secondary.buttons .button:hover, -.ui.basic.secondary.button:hover { - color: var(--color-secondary-hover); - border-color: var(--color-secondary-hover); -} - -.ui.basic.secondary.buttons .button:active, -.ui.basic.secondary.button:active { - color: var(--color-secondary-active); - border-color: var(--color-secondary-active); -} - -/* red */ - -.ui.red.labels .label, -.ui.ui.ui.red.label, -.ui.red.button, -.ui.red.buttons .button, -.ui.red.button:focus, -.ui.red.buttons .button:focus { - background: var(--color-red); -} - -.ui.red.button:hover, -.ui.red.buttons .button:hover { - background: var(--color-red-dark-1); -} - -.ui.red.button:active, -.ui.red.buttons .button:active { - background: var(--color-red-dark-2); -} - -.ui.basic.red.buttons .button, -.ui.basic.red.button, -.ui.basic.red.buttons .button:focus, -.ui.basic.red.button:focus { - color: var(--color-red); - border-color: var(--color-red); -} - -.ui.basic.red.buttons .button:hover, -.ui.basic.red.button:hover { - color: var(--color-red-dark-1); - border-color: var(--color-red-dark-1); -} - -.ui.basic.red.buttons .button:active, -.ui.basic.red.button:active { - color: var(--color-red-dark-2); - border-color: var(--color-red-dark-2); -} - -/* orange */ - -.ui.orange.labels .label, -.ui.ui.ui.orange.label, -.ui.orange.button, -.ui.orange.buttons .button, -.ui.orange.button:focus, -.ui.orange.buttons .button:focus { - background: var(--color-orange); -} - -.ui.orange.button:hover, -.ui.orange.buttons .button:hover { - background: var(--color-orange-dark-1); -} - -.ui.orange.button:active, -.ui.orange.buttons .button:active { - background: var(--color-orange-dark-2); -} - -.ui.basic.orange.buttons .button, -.ui.basic.orange.button, -.ui.basic.orange.buttons .button:focus, -.ui.basic.orange.button:focus { - color: var(--color-orange); - border-color: var(--color-orange); -} - -.ui.basic.orange.buttons .button:hover, -.ui.basic.orange.button:hover { - color: var(--color-orange-dark-1); - border-color: var(--color-orange-dark-1); -} - -.ui.basic.orange.buttons .button:active, -.ui.basic.orange.button:active { - color: var(--color-orange-dark-2); - border-color: var(--color-orange-dark-2); -} - -/* yellow */ - -.ui.yellow.labels .label, -.ui.ui.ui.yellow.label, -.ui.yellow.button, -.ui.yellow.buttons .button, -.ui.yellow.button:focus, -.ui.yellow.buttons .button:focus { - background: var(--color-yellow); -} - -.ui.yellow.button:hover, -.ui.yellow.buttons .button:hover { - background: var(--color-yellow-dark-1); -} - -.ui.yellow.button:active, -.ui.yellow.buttons .button:active { - background: var(--color-yellow-dark-2); -} - -.ui.basic.yellow.buttons .button, -.ui.basic.yellow.button, -.ui.basic.yellow.buttons .button:focus, -.ui.basic.yellow.button:focus { - color: var(--color-yellow); - border-color: var(--color-yellow); -} - -.ui.basic.yellow.buttons .button:hover, -.ui.basic.yellow.button:hover { - color: var(--color-yellow-dark-1); - border-color: var(--color-yellow-dark-1); -} - -.ui.basic.yellow.buttons .button:active, -.ui.basic.yellow.button:active { - color: var(--color-yellow-dark-2); - border-color: var(--color-yellow-dark-2); -} - -/* olive */ - -.ui.olive.labels .label, -.ui.ui.ui.olive.label, -.ui.olive.button, -.ui.olive.buttons .button, -.ui.olive.button:focus, -.ui.olive.buttons .button:focus { - background: var(--color-olive); -} - -.ui.olive.button:hover, -.ui.olive.buttons .button:hover { - background: var(--color-olive-dark-1); -} - -.ui.olive.button:active, -.ui.olive.buttons .button:active { - background: var(--color-olive-dark-2); -} - -.ui.basic.olive.buttons .button, -.ui.basic.olive.button, -.ui.basic.olive.buttons .button:focus, -.ui.basic.olive.button:focus { - color: var(--color-olive); - border-color: var(--color-olive); -} - -.ui.basic.olive.buttons .button:hover, -.ui.basic.olive.button:hover { - color: var(--color-olive-dark-1); - border-color: var(--color-olive-dark-1); -} - -.ui.basic.olive.buttons .button:active, -.ui.basic.olive.button:active { - color: var(--color-olive-dark-2); - border-color: var(--color-olive-dark-2); -} - -/* green */ - -.ui.green.labels .label, -.ui.ui.ui.green.label, -.ui.green.button, -.ui.green.buttons .button, -.ui.green.button:focus, -.ui.green.buttons .button:focus { - background: var(--color-green); -} - -.ui.green.button:hover, -.ui.green.buttons .button:hover { - background: var(--color-green-dark-1); -} - -.ui.green.button:active, -.ui.green.buttons .button:active { - background: var(--color-green-dark-2); -} - -.ui.basic.green.buttons .button, -.ui.basic.green.button, -.ui.basic.green.buttons .button:focus, -.ui.basic.green.button:focus { - color: var(--color-green); - border-color: var(--color-green); -} - -.ui.basic.green.buttons .button:hover, -.ui.basic.green.button:hover { - color: var(--color-green-dark-1); - border-color: var(--color-green-dark-1); -} - -.ui.basic.green.buttons .button:active, -.ui.basic.green.button:active { - color: var(--color-green-dark-2); - border-color: var(--color-green-dark-2); -} - -/* teal */ - -.ui.teal.labels .label, -.ui.ui.ui.teal.label, -.ui.teal.button, -.ui.teal.buttons .button, -.ui.teal.button:focus, -.ui.teal.buttons .button:focus { - background: var(--color-teal); -} - -.ui.teal.button:hover, -.ui.teal.buttons .button:hover { - background: var(--color-teal-dark-1); -} - -.ui.teal.button:active, -.ui.teal.buttons .button:active { - background: var(--color-teal-dark-2); -} - -.ui.basic.teal.buttons .button, -.ui.basic.teal.button, -.ui.basic.teal.buttons .button:focus, -.ui.basic.teal.button:focus { - color: var(--color-teal); - border-color: var(--color-teal); -} - -.ui.basic.teal.buttons .button:hover, -.ui.basic.teal.button:hover { - color: var(--color-teal-dark-1); - border-color: var(--color-teal-dark-1); -} - -.ui.basic.teal.buttons .button:active, -.ui.basic.teal.button:active { - color: var(--color-teal-dark-2); - border-color: var(--color-teal-dark-2); -} - -/* blue */ - -.ui.blue.labels .label, -.ui.ui.ui.blue.label, -.ui.blue.button, -.ui.blue.buttons .button, -.ui.blue.button:focus, -.ui.blue.buttons .button:focus { - background: var(--color-blue); -} - -.ui.blue.button:hover, -.ui.blue.buttons .button:hover { - background: var(--color-blue-dark-1); -} - -.ui.blue.button:active, -.ui.blue.buttons .button:active { - background: var(--color-blue-dark-2); -} - -.ui.basic.blue.buttons .button, -.ui.basic.blue.button, -.ui.basic.blue.buttons .button:focus, -.ui.basic.blue.button:focus { - color: var(--color-blue); - border-color: var(--color-blue); -} - -.ui.basic.blue.buttons .button:hover, -.ui.basic.blue.button:hover { - color: var(--color-blue-dark-1); - border-color: var(--color-blue-dark-1); -} - -.ui.basic.blue.buttons .button:active, -.ui.basic.blue.button:active { - color: var(--color-blue-dark-2); - border-color: var(--color-blue-dark-2); -} - -/* violet */ - -.ui.violet.labels .label, -.ui.ui.ui.violet.label, -.ui.violet.button, -.ui.violet.buttons .button, -.ui.violet.button:focus, -.ui.violet.buttons .button:focus { - background: var(--color-violet); -} - -.ui.violet.button:hover, -.ui.violet.buttons .button:hover { - background: var(--color-violet-dark-1); -} - -.ui.violet.button:active, -.ui.violet.buttons .button:active { - background: var(--color-violet-dark-2); -} - -.ui.basic.violet.buttons .button, -.ui.basic.violet.button, -.ui.basic.violet.buttons .button:focus, -.ui.basic.violet.button:focus { - color: var(--color-violet); - border-color: var(--color-violet); -} - -.ui.basic.violet.buttons .button:hover, -.ui.basic.violet.button:hover { - color: var(--color-violet-dark-1); - border-color: var(--color-violet-dark-1); -} - -.ui.basic.violet.buttons .button:active, -.ui.basic.violet.button:active { - color: var(--color-violet-dark-2); - border-color: var(--color-violet-dark-2); -} - -/* purple */ - -.ui.purple.labels .label, -.ui.ui.ui.purple.label, -.ui.purple.button, -.ui.purple.buttons .button, -.ui.purple.button:focus, -.ui.purple.buttons .button:focus { - background: var(--color-purple); -} - -.ui.purple.button:hover, -.ui.purple.buttons .button:hover { - background: var(--color-purple-dark-1); -} - -.ui.purple.button:active, -.ui.purple.buttons .button:active { - background: var(--color-purple-dark-2); -} - -.ui.basic.purple.buttons .button, -.ui.basic.purple.button, -.ui.basic.purple.buttons .button:focus, -.ui.basic.purple.button:focus { - color: var(--color-purple); - border-color: var(--color-purple); -} - -.ui.basic.purple.buttons .button:hover, -.ui.basic.purple.button:hover { - color: var(--color-purple-dark-1); - border-color: var(--color-purple-dark-1); -} - -.ui.basic.purple.buttons .button:active, -.ui.basic.purple.button:active { - color: var(--color-purple-dark-2); - border-color: var(--color-purple-dark-2); -} - -/* pink */ - -.ui.pink.labels .label, -.ui.ui.ui.pink.label, -.ui.pink.button, -.ui.pink.buttons .button, -.ui.pink.button:focus, -.ui.pink.buttons .button:focus { - background: var(--color-pink); -} - -.ui.pink.button:hover, -.ui.pink.buttons .button:hover { - background: var(--color-pink-dark-1); -} - -.ui.pink.button:active, -.ui.pink.buttons .button:active { - background: var(--color-pink-dark-2); -} - -.ui.basic.pink.buttons .button, -.ui.basic.pink.button, -.ui.basic.pink.buttons .button:focus, -.ui.basic.pink.button:focus { - color: var(--color-pink); - border-color: var(--color-pink); -} - -.ui.basic.pink.buttons .button:hover, -.ui.basic.pink.button:hover { - color: var(--color-pink-dark-1); - border-color: var(--color-pink-dark-1); -} - -.ui.basic.pink.buttons .button:active, -.ui.basic.pink.button:active { - color: var(--color-pink-dark-2); - border-color: var(--color-pink-dark-2); -} - -/* brown */ - -.ui.brown.labels .label, -.ui.ui.ui.brown.label, -.ui.brown.button, -.ui.brown.buttons .button, -.ui.brown.button:focus, -.ui.brown.buttons .button:focus { - background: var(--color-brown); -} - -.ui.brown.button:hover, -.ui.brown.buttons .button:hover { - background: var(--color-brown-dark-1); -} - -.ui.brown.button:active, -.ui.brown.buttons .button:active { - background: var(--color-brown-dark-2); -} - -.ui.basic.brown.buttons .button, -.ui.basic.brown.button, -.ui.basic.brown.buttons .button:focus, -.ui.basic.brown.button:focus { - color: var(--color-brown); - border-color: var(--color-brown); -} - -.ui.basic.brown.buttons .button:hover, -.ui.basic.brown.button:hover { - color: var(--color-brown-dark-1); - border-color: var(--color-brown-dark-1); -} - -.ui.basic.brown.buttons .button:active, -.ui.basic.brown.button:active { - color: var(--color-brown-dark-2); - border-color: var(--color-brown-dark-2); -} - -/* negative */ - -.ui.negative.buttons .button, -.ui.negative.button, -.ui.negative.buttons .button:focus, -.ui.negative.button:focus { - background: var(--color-red); -} - -.ui.negative.buttons .button:hover, -.ui.negative.button:hover { - background: var(--color-red-dark-1); -} - -.ui.negative.buttons .button:active, -.ui.negative.button:active { - background: var(--color-red-dark-2); -} - -.ui.basic.negative.buttons .button, -.ui.basic.negative.button, -.ui.basic.negative.buttons .button:focus, -.ui.basic.negative.button:focus { - color: var(--color-red); - border-color: var(--color-red); -} - -.ui.basic.negative.buttons .button:hover, -.ui.basic.negative.button:hover { - color: var(--color-red-dark-1); - border-color: var(--color-red-dark-1); -} - -.ui.basic.negative.buttons .button:active, -.ui.basic.negative.button:active { - color: var(--color-red-dark-2); - border-color: var(--color-red-dark-2); -} - -/* positive */ - -.ui.positive.buttons .button, -.ui.positive.button, -.ui.positive.buttons .button:focus, -.ui.positive.button:focus { - background: var(--color-green); -} - -.ui.positive.buttons .button:hover, -.ui.positive.button:hover { - background: var(--color-green-dark-1); -} - -.ui.positive.buttons .button:active, -.ui.positive.button:active { - background: var(--color-green-dark-2); -} - -.ui.basic.positive.buttons .button, -.ui.basic.positive.button, -.ui.basic.positive.buttons .button:focus, -.ui.basic.positive.button:focus { - color: var(--color-green); - border-color: var(--color-green); -} - -.ui.basic.positive.buttons .button:hover, -.ui.basic.positive.button:hover { - color: var(--color-green-dark-1); - border-color: var(--color-green-dark-1); -} - -.ui.basic.positive.buttons .button:active, -.ui.basic.positive.button:active { - color: var(--color-green-dark-2); - border-color: var(--color-green-dark-2); -} diff --git a/web_src/css/modules/modal.css b/web_src/css/modules/modal.css index 54a4ef81ca..a2acfeaa15 100644 --- a/web_src/css/modules/modal.css +++ b/web_src/css/modules/modal.css @@ -10,6 +10,10 @@ top: 1.2em; } +.ui.modal > .close.inside { + color: inherit; +} + .ui.modal > .close.icon[height="16"] { top: 0.7em; /* fomantic uses absolute layout, so if we have special icon size, it needs this trick to align vertically */ color: var(--color-text-dark); diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 52f9d5a6ca..887789115e 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -654,15 +654,15 @@ td .commit-summary { padding: 2px .5rem; } -.repository.view.issue .issue-title .index { +.issue-title .index { color: var(--color-text-light-2); } -.repository.view.issue .issue-title .label { +.issue-title .label { margin-right: 10px; } -.repository.view.issue .issue-title .edit-zone { +.issue-title .edit-zone { margin-top: 10px; } @@ -1164,14 +1164,6 @@ td .commit-summary { font-size: 14px; } -.repository.compare.pull .title .issue-title { - margin-bottom: 0.5rem; -} - -.repository.compare.pull .title .issue-title .index { - color: var(--color-text-light-2); -} - .repository .ui.dropdown.filter > .menu { margin-top: 1px; } diff --git a/web_src/fomantic/build/semantic.css b/web_src/fomantic/build/semantic.css index 8ce9ee24ea..7c404bdb30 100644 --- a/web_src/fomantic/build/semantic.css +++ b/web_src/fomantic/build/semantic.css @@ -8,2324 +8,6 @@ * http://opensource.org/licenses/MIT * */ -/*! - * # Fomantic-UI - Button - * http://github.com/fomantic/Fomantic-UI/ - * - * - * Released under the MIT license - * http://opensource.org/licenses/MIT - * - */ - -/******************************* - Button -*******************************/ - -.ui.button { - cursor: pointer; - display: inline-block; - min-height: 1em; - outline: none; - border: none; - vertical-align: baseline; - background: #E0E1E2 none; - color: rgba(0, 0, 0, 0.6); - font-family: var(--fonts-regular); - margin: 0 0.25em 0 0; - padding: 0.78571429em 1.5em 0.78571429em; - text-transform: none; - text-shadow: none; - font-weight: 500; - line-height: 1em; - font-style: normal; - text-align: center; - text-decoration: none; - border-radius: 0.28571429rem; - box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, box-shadow 0.1s ease, background 0.1s ease; - will-change: auto; - -webkit-tap-highlight-color: transparent; -} - -/******************************* - States -*******************************/ - -/*-------------- - Hover ----------------*/ - -.ui.button:hover { - background-color: #CACBCD; - background-image: none; - box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; - color: rgba(0, 0, 0, 0.8); -} - -.ui.button:hover .icon { - opacity: 0.85; -} - -/*-------------- - Focus ----------------*/ - -.ui.button:focus { - background-color: #CACBCD; - color: rgba(0, 0, 0, 0.8); - background-image: none; - box-shadow: ''; -} - -.ui.button:focus .icon { - opacity: 0.85; -} - -/*-------------- - Down ----------------*/ - -.ui.button:active, -.ui.active.button:active { - background-color: #BABBBC; - background-image: ''; - color: rgba(0, 0, 0, 0.9); - box-shadow: 0 0 0 1px transparent inset, none; -} - -/*-------------- - Active ----------------*/ - -.ui.active.button { - background-color: #C0C1C2; - background-image: none; - box-shadow: 0 0 0 1px transparent inset; - color: rgba(0, 0, 0, 0.95); -} - -.ui.active.button:hover { - background-color: #C0C1C2; - background-image: none; - color: rgba(0, 0, 0, 0.95); -} - -.ui.active.button:active { - background-color: #C0C1C2; - background-image: none; -} - -/*-------------- - Loading ----------------*/ - -/* Specificity hack */ - -.ui.loading.loading.loading.loading.loading.loading.button { - position: relative; - cursor: default; - text-shadow: none !important; - color: transparent; - opacity: 1; - pointer-events: auto; - transition: all 0s linear, opacity 0.1s ease; -} - -.ui.loading.button:before { - position: absolute; - content: ''; - top: 50%; - left: 50%; - margin: -0.64285714em 0 0 -0.64285714em; - width: 1.28571429em; - height: 1.28571429em; - border-radius: 500rem; - border: 0.2em solid rgba(0, 0, 0, 0.15); -} - -.ui.loading.button:after { - position: absolute; - content: ''; - top: 50%; - left: 50%; - margin: -0.64285714em 0 0 -0.64285714em; - width: 1.28571429em; - height: 1.28571429em; - border-radius: 500rem; - animation: loader 0.6s infinite linear; - border: 0.2em solid currentColor; - color: #FFFFFF; - box-shadow: 0 0 0 1px transparent; -} - -.ui.labeled.icon.loading.button .icon { - background-color: transparent; - box-shadow: none; -} - -.ui.basic.loading.button:not(.inverted):before { - border-color: rgba(0, 0, 0, 0.1); -} - -.ui.basic.loading.button:not(.inverted):after { - border-color: #767676; -} - -/*------------------- - Disabled - --------------------*/ - -.ui.buttons .disabled.button:not(.basic), -.ui.disabled.button, -.ui.button:disabled, -.ui.disabled.button:hover, -.ui.disabled.active.button { - cursor: default; - opacity: var(--opacity-disabled) !important; - background-image: none; - box-shadow: none; - pointer-events: none !important; -} - -/* Basic Group With Disabled */ - -.ui.basic.buttons .ui.disabled.button { - border-color: rgba(34, 36, 38, 0.5); -} - -/******************************* - Types -*******************************/ - -/*------------------- - Labeled Button - --------------------*/ - -.ui.labeled.button:not(.icon) { - display: inline-flex; - flex-direction: row; - background: none; - padding: 0 !important; - border: none; - box-shadow: none; -} - -.ui.labeled.button > .button { - margin: 0; -} - -.ui.labeled.button > .label { - display: flex; - align-items: center; - margin: 0 0 0 -1px !important; - font-size: 1em; - padding: ''; - border-color: rgba(34, 36, 38, 0.15); -} - -/* Tag */ - -.ui.labeled.button > .tag.label:before { - width: 1.85em; - height: 1.85em; -} - -/* Right */ - -.ui.labeled.button:not([class*="left labeled"]) > .button { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.ui.labeled.button:not([class*="left labeled"]) > .label { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -/* Left Side */ - -.ui[class*="left labeled"].button > .button { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.ui[class*="left labeled"].button > .label { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -/*-------------- - Icon ----------------*/ - -.ui.button > .icon:not(.button) { - height: auto; - opacity: 0.8; - transition: opacity 0.1s ease; - color: ''; -} - -.ui.button:not(.icon) > .icon:not(.button):not(.dropdown), -.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) { - margin: 0 0.42857143em 0 -0.21428571em; - vertical-align: baseline; -} - -.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) > .icon { - vertical-align: baseline; -} - -.ui.button:not(.icon) > .right.icon:not(.button):not(.dropdown) { - margin: 0 -0.21428571em 0 0.42857143em; -} - -/******************************* - Variations -*******************************/ - -/*------------------- - Floated - --------------------*/ - -.ui[class*="left floated"].buttons, -.ui[class*="left floated"].button { - float: left; - margin-left: 0; - margin-right: 0.25em; -} - -.ui[class*="right floated"].buttons, -.ui[class*="right floated"].button { - float: right; - margin-right: 0; - margin-left: 0.25em; -} - -/*------------------- - Compact - --------------------*/ - -.ui.compact.buttons .button, -.ui.compact.button { - padding: 0.58928571em 1.125em 0.58928571em; -} - -.ui.compact.icon.buttons .button, -.ui.compact.icon.button { - padding: 0.58928571em 0.58928571em 0.58928571em; -} - -.ui.compact.labeled.icon.buttons .button, -.ui.compact.labeled.icon.button { - padding: 0.58928571em 3.69642857em 0.58928571em; -} - -.ui.compact.labeled.icon.buttons .button > .icon, -.ui.compact.labeled.icon.button > .icon { - padding: 0.58928571em 0 0.58928571em 0; -} - -/*------------------- - Sizes ---------------------*/ - -.ui.buttons .button, -.ui.buttons .or, -.ui.button { - font-size: 1rem; -} - -.ui.mini.buttons .dropdown, -.ui.mini.buttons .dropdown .menu > .item, -.ui.mini.buttons .button, -.ui.mini.buttons .or, -.ui.ui.ui.ui.mini.button { - font-size: 0.78571429rem; -} - -.ui.tiny.buttons .dropdown, -.ui.tiny.buttons .dropdown .menu > .item, -.ui.tiny.buttons .button, -.ui.tiny.buttons .or, -.ui.ui.ui.ui.tiny.button { - font-size: 0.85714286rem; -} - -.ui.small.buttons .dropdown, -.ui.small.buttons .dropdown .menu > .item, -.ui.small.buttons .button, -.ui.small.buttons .or, -.ui.ui.ui.ui.small.button { - font-size: 0.92857143rem; -} - -.ui.large.buttons .dropdown, -.ui.large.buttons .dropdown .menu > .item, -.ui.large.buttons .button, -.ui.large.buttons .or, -.ui.ui.ui.ui.large.button { - font-size: 1.14285714rem; -} - -.ui.big.buttons .dropdown, -.ui.big.buttons .dropdown .menu > .item, -.ui.big.buttons .button, -.ui.big.buttons .or, -.ui.ui.ui.ui.big.button { - font-size: 1.28571429rem; -} - -.ui.huge.buttons .dropdown, -.ui.huge.buttons .dropdown .menu > .item, -.ui.huge.buttons .button, -.ui.huge.buttons .or, -.ui.ui.ui.ui.huge.button { - font-size: 1.42857143rem; -} - -.ui.massive.buttons .dropdown, -.ui.massive.buttons .dropdown .menu > .item, -.ui.massive.buttons .button, -.ui.massive.buttons .or, -.ui.ui.ui.ui.massive.button { - font-size: 1.71428571rem; -} - -/*-------------- - Icon Only ----------------*/ - -.ui.icon.buttons .button, -.ui.icon.button:not(.animated):not(.compact) { - padding: 0.78571429em 0.78571429em 0.78571429em; -} - -.ui.animated.icon.button > .content > .icon, -.ui.icon.buttons .button > .icon, -.ui.icon.button > .icon { - opacity: 0.9; - margin: 0 !important; - vertical-align: top; -} - -.ui.animated.button > .content > .icon { - vertical-align: top; -} - -/*------------------- - Basic - --------------------*/ - -.ui.basic.buttons .button, -.ui.basic.button { - background: transparent none; - color: rgba(0, 0, 0, 0.6); - font-weight: normal; - border-radius: 0.28571429rem; - text-transform: none; - text-shadow: none !important; - box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.15) inset; -} - -.ui.basic.buttons { - box-shadow: none; - border: 1px solid rgba(34, 36, 38, 0.15); - border-radius: 0.28571429rem; -} - -.ui.basic.buttons .button { - border-radius: 0; -} - -.ui.basic.buttons .button:hover, -.ui.basic.button:hover { - background: #FFFFFF; - color: rgba(0, 0, 0, 0.8); - box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.35) inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.basic.buttons .button:focus, -.ui.basic.button:focus { - background: #FFFFFF; - color: rgba(0, 0, 0, 0.8); - box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.35) inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.basic.buttons .button:active, -.ui.basic.button:active { - background: #F8F8F8; - color: rgba(0, 0, 0, 0.9); - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, 0 1px 4px 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.basic.buttons .active.button, -.ui.basic.active.button { - background: rgba(0, 0, 0, 0.05); - box-shadow: ''; - color: rgba(0, 0, 0, 0.95); -} - -.ui.basic.buttons .active.button:hover, -.ui.basic.active.button:hover { - background-color: rgba(0, 0, 0, 0.05); -} - -/* Vertical */ - -.ui.basic.buttons .button:hover { - box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.35) inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset inset; -} - -.ui.basic.buttons .button:active { - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, 0 1px 4px 0 rgba(34, 36, 38, 0.15) inset inset; -} - -.ui.basic.buttons .active.button { - box-shadow: ''; -} - -/* Basic Group */ - -.ui.basic.buttons .button { - border-left: 1px solid rgba(34, 36, 38, 0.15); - box-shadow: none; -} - -.ui.basic.vertical.buttons .button { - border-left: none; - border-left-width: 0; - border-top: 1px solid rgba(34, 36, 38, 0.15); -} - -.ui.basic.vertical.buttons .button:first-child { - border-top-width: 0; -} - -/*-------------- - Labeled Icon - ---------------*/ - -.ui.labeled.icon.buttons .button, -.ui.labeled.icon.button { - position: relative; - padding-left: 4.07142857em !important; - padding-right: 1.5em !important; -} - -/* Left Labeled */ - -.ui.labeled.icon.buttons > .button > .icon, -.ui.labeled.icon.button > .icon { - position: absolute; - top: 0; - left: 0; - height: 100%; - line-height: 1; - border-radius: 0; - border-top-left-radius: inherit; - border-bottom-left-radius: inherit; - text-align: center; - animation: none; - padding: 0.78571429em 0 0.78571429em 0; - margin: 0; - width: 2.57142857em; - background-color: rgba(0, 0, 0, 0.05); - color: ''; - box-shadow: -1px 0 0 0 transparent inset; -} - -/* Right Labeled */ - -.ui[class*="right labeled"].icon.button { - padding-right: 4.07142857em !important; - padding-left: 1.5em !important; -} - -.ui[class*="right labeled"].icon.button > .icon { - left: auto; - right: 0; - border-radius: 0; - border-top-right-radius: inherit; - border-bottom-right-radius: inherit; - box-shadow: 1px 0 0 0 transparent inset; -} - -.ui.labeled.icon.buttons > .button > .icon:before, -.ui.labeled.icon.button > .icon:before, -.ui.labeled.icon.buttons > .button > .icon:after, -.ui.labeled.icon.button > .icon:after { - display: block; - position: relative; - width: 100%; - top: 0; - text-align: center; -} - -.ui.labeled.icon.buttons .button > .icon { - border-radius: 0; -} - -.ui.labeled.icon.buttons .button:first-child > .icon { - border-top-left-radius: 0.28571429rem; - border-bottom-left-radius: 0.28571429rem; -} - -.ui.labeled.icon.buttons .button:last-child > .icon { - border-top-right-radius: 0.28571429rem; - border-bottom-right-radius: 0.28571429rem; -} - -.ui.vertical.labeled.icon.buttons .button:first-child > .icon { - border-radius: 0; - border-top-left-radius: 0.28571429rem; -} - -.ui.vertical.labeled.icon.buttons .button:last-child > .icon { - border-radius: 0; - border-bottom-left-radius: 0.28571429rem; -} - -/* Loading Icon in Labeled Button */ - -.ui.labeled.icon.button > .loading.icon:before { - animation: loader 2s linear infinite; -} - -/*-------------- - Toggle - ---------------*/ - -/* Toggle (Modifies active state to give affordances) */ - -.ui.toggle.buttons .active.button, -.ui.buttons .button.toggle.active, -.ui.button.toggle.active { - background-color: #21BA45; - box-shadow: none; - text-shadow: none; - color: #FFFFFF; -} - -.ui.button.toggle.active:hover { - background-color: #16ab39; - text-shadow: none; - color: #FFFFFF; -} - -/*-------------- - Circular - ---------------*/ - -.ui.circular.button { - border-radius: 10em; -} - -.ui.circular.button > .icon { - width: 1em; - vertical-align: baseline; -} - -/*------------------- - Or Buttons - --------------------*/ - -.ui.buttons .or { - position: relative; - width: 0.3em; - height: 2.57142857em; - z-index: 3; -} - -.ui.buttons .or:before { - position: absolute; - text-align: center; - border-radius: 500rem; - content: 'or'; - top: 50%; - left: 50%; - background-color: #FFFFFF; - text-shadow: none; - margin-top: -0.89285714em; - margin-left: -0.89285714em; - width: 1.78571429em; - height: 1.78571429em; - line-height: 1.78571429em; - color: rgba(0, 0, 0, 0.4); - font-style: normal; - font-weight: 500; - box-shadow: 0 0 0 1px transparent inset; -} - -.ui.buttons .or[data-text]:before { - content: attr(data-text); -} - -/* Fluid Or */ - -.ui.fluid.buttons .or { - width: 0 !important; -} - -.ui.fluid.buttons .or:after { - display: none; -} - -/*------------------- - Fluid - --------------------*/ - -.ui.fluid.buttons, -.ui.fluid.button { - width: 100%; -} - -.ui.fluid.button { - display: block; -} - -.ui.two.buttons { - width: 100%; -} - -.ui.two.buttons > .button { - width: 50%; -} - -.ui.three.buttons { - width: 100%; -} - -.ui.three.buttons > .button { - width: 33.333%; -} - -.ui.four.buttons { - width: 100%; -} - -.ui.four.buttons > .button { - width: 25%; -} - -.ui.five.buttons { - width: 100%; -} - -.ui.five.buttons > .button { - width: 20%; -} - -.ui.six.buttons { - width: 100%; -} - -.ui.six.buttons > .button { - width: 16.666%; -} - -.ui.seven.buttons { - width: 100%; -} - -.ui.seven.buttons > .button { - width: 14.285%; -} - -.ui.eight.buttons { - width: 100%; -} - -.ui.eight.buttons > .button { - width: 12.5%; -} - -.ui.nine.buttons { - width: 100%; -} - -.ui.nine.buttons > .button { - width: 11.11%; -} - -.ui.ten.buttons { - width: 100%; -} - -.ui.ten.buttons > .button { - width: 10%; -} - -.ui.eleven.buttons { - width: 100%; -} - -.ui.eleven.buttons > .button { - width: 9.09%; -} - -.ui.twelve.buttons { - width: 100%; -} - -.ui.twelve.buttons > .button { - width: 8.3333%; -} - -/* Fluid Vertical Buttons */ - -.ui.fluid.vertical.buttons, -.ui.fluid.vertical.buttons > .button { - display: flex; - width: auto; - justify-content: center; -} - -.ui.two.vertical.buttons > .button { - height: 50%; -} - -.ui.three.vertical.buttons > .button { - height: 33.333%; -} - -.ui.four.vertical.buttons > .button { - height: 25%; -} - -.ui.five.vertical.buttons > .button { - height: 20%; -} - -.ui.six.vertical.buttons > .button { - height: 16.666%; -} - -.ui.seven.vertical.buttons > .button { - height: 14.285%; -} - -.ui.eight.vertical.buttons > .button { - height: 12.5%; -} - -.ui.nine.vertical.buttons > .button { - height: 11.11%; -} - -.ui.ten.vertical.buttons > .button { - height: 10%; -} - -.ui.eleven.vertical.buttons > .button { - height: 9.09%; -} - -.ui.twelve.vertical.buttons > .button { - height: 8.3333%; -} - -/*------------------- - Colors ---------------------*/ - -.ui.primary.buttons .button, -.ui.primary.button { - background-color: #2185D0; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.primary.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.primary.buttons .button:hover, -.ui.primary.button:hover { - background-color: #1678c2; - color: #FFFFFF; - text-shadow: none; -} - -.ui.primary.buttons .button:focus, -.ui.primary.button:focus { - background-color: #0d71bb; - color: #FFFFFF; - text-shadow: none; -} - -.ui.primary.buttons .button:active, -.ui.primary.button:active { - background-color: #1a69a4; - color: #FFFFFF; - text-shadow: none; -} - -.ui.primary.buttons .active.button, -.ui.primary.buttons .active.button:active, -.ui.primary.active.button, -.ui.primary.button .active.button:active { - background-color: #1279c6; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.primary.buttons .button, -.ui.basic.primary.button { - background: transparent; - box-shadow: 0 0 0 1px #2185D0 inset; - color: #2185D0; -} - -.ui.basic.primary.buttons .button:hover, -.ui.basic.primary.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #1678c2 inset; - color: #1678c2; -} - -.ui.basic.primary.buttons .button:focus, -.ui.basic.primary.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #0d71bb inset; - color: #1678c2; -} - -.ui.basic.primary.buttons .active.button, -.ui.basic.primary.active.button { - background: transparent; - box-shadow: 0 0 0 1px #1279c6 inset; - color: #1a69a4; -} - -.ui.basic.primary.buttons .button:active, -.ui.basic.primary.button:active { - box-shadow: 0 0 0 1px #1a69a4 inset; - color: #1a69a4; -} - -.ui.buttons:not(.vertical) > .basic.primary.button:not(:first-child) { - margin-left: -1px; -} - -.ui.secondary.buttons .button, -.ui.secondary.button { - background-color: #1B1C1D; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.secondary.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.secondary.buttons .button:hover, -.ui.secondary.button:hover { - background-color: #27292a; - color: #FFFFFF; - text-shadow: none; -} - -.ui.secondary.buttons .button:focus, -.ui.secondary.button:focus { - background-color: #2e3032; - color: #FFFFFF; - text-shadow: none; -} - -.ui.secondary.buttons .button:active, -.ui.secondary.button:active { - background-color: #343637; - color: #FFFFFF; - text-shadow: none; -} - -.ui.secondary.buttons .active.button, -.ui.secondary.buttons .active.button:active, -.ui.secondary.active.button, -.ui.secondary.button .active.button:active { - background-color: #27292a; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.secondary.buttons .button, -.ui.basic.secondary.button { - background: transparent; - box-shadow: 0 0 0 1px #1B1C1D inset; - color: #1B1C1D; -} - -.ui.basic.secondary.buttons .button:hover, -.ui.basic.secondary.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #27292a inset; - color: #27292a; -} - -.ui.basic.secondary.buttons .button:focus, -.ui.basic.secondary.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #2e3032 inset; - color: #27292a; -} - -.ui.basic.secondary.buttons .active.button, -.ui.basic.secondary.active.button { - background: transparent; - box-shadow: 0 0 0 1px #27292a inset; - color: #343637; -} - -.ui.basic.secondary.buttons .button:active, -.ui.basic.secondary.button:active { - box-shadow: 0 0 0 1px #343637 inset; - color: #343637; -} - -.ui.buttons:not(.vertical) > .basic.secondary.button:not(:first-child) { - margin-left: -1px; -} - -.ui.red.buttons .button, -.ui.red.button { - background-color: #DB2828; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.red.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.red.buttons .button:hover, -.ui.red.button:hover { - background-color: #d01919; - color: #FFFFFF; - text-shadow: none; -} - -.ui.red.buttons .button:focus, -.ui.red.button:focus { - background-color: #ca1010; - color: #FFFFFF; - text-shadow: none; -} - -.ui.red.buttons .button:active, -.ui.red.button:active { - background-color: #b21e1e; - color: #FFFFFF; - text-shadow: none; -} - -.ui.red.buttons .active.button, -.ui.red.buttons .active.button:active, -.ui.red.active.button, -.ui.red.button .active.button:active { - background-color: #d41515; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.red.buttons .button, -.ui.basic.red.button { - background: transparent; - box-shadow: 0 0 0 1px #DB2828 inset; - color: #DB2828; -} - -.ui.basic.red.buttons .button:hover, -.ui.basic.red.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #d01919 inset; - color: #d01919; -} - -.ui.basic.red.buttons .button:focus, -.ui.basic.red.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #ca1010 inset; - color: #d01919; -} - -.ui.basic.red.buttons .active.button, -.ui.basic.red.active.button { - background: transparent; - box-shadow: 0 0 0 1px #d41515 inset; - color: #b21e1e; -} - -.ui.basic.red.buttons .button:active, -.ui.basic.red.button:active { - box-shadow: 0 0 0 1px #b21e1e inset; - color: #b21e1e; -} - -.ui.buttons:not(.vertical) > .basic.red.button:not(:first-child) { - margin-left: -1px; -} - -.ui.orange.buttons .button, -.ui.orange.button { - background-color: #F2711C; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.orange.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.orange.buttons .button:hover, -.ui.orange.button:hover { - background-color: #f26202; - color: #FFFFFF; - text-shadow: none; -} - -.ui.orange.buttons .button:focus, -.ui.orange.button:focus { - background-color: #e55b00; - color: #FFFFFF; - text-shadow: none; -} - -.ui.orange.buttons .button:active, -.ui.orange.button:active { - background-color: #cf590c; - color: #FFFFFF; - text-shadow: none; -} - -.ui.orange.buttons .active.button, -.ui.orange.buttons .active.button:active, -.ui.orange.active.button, -.ui.orange.button .active.button:active { - background-color: #f56100; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.orange.buttons .button, -.ui.basic.orange.button { - background: transparent; - box-shadow: 0 0 0 1px #F2711C inset; - color: #F2711C; -} - -.ui.basic.orange.buttons .button:hover, -.ui.basic.orange.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #f26202 inset; - color: #f26202; -} - -.ui.basic.orange.buttons .button:focus, -.ui.basic.orange.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #e55b00 inset; - color: #f26202; -} - -.ui.basic.orange.buttons .active.button, -.ui.basic.orange.active.button { - background: transparent; - box-shadow: 0 0 0 1px #f56100 inset; - color: #cf590c; -} - -.ui.basic.orange.buttons .button:active, -.ui.basic.orange.button:active { - box-shadow: 0 0 0 1px #cf590c inset; - color: #cf590c; -} - -.ui.buttons:not(.vertical) > .basic.orange.button:not(:first-child) { - margin-left: -1px; -} - -.ui.yellow.buttons .button, -.ui.yellow.button { - background-color: #FBBD08; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.yellow.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.yellow.buttons .button:hover, -.ui.yellow.button:hover { - background-color: #eaae00; - color: #FFFFFF; - text-shadow: none; -} - -.ui.yellow.buttons .button:focus, -.ui.yellow.button:focus { - background-color: #daa300; - color: #FFFFFF; - text-shadow: none; -} - -.ui.yellow.buttons .button:active, -.ui.yellow.button:active { - background-color: #cd9903; - color: #FFFFFF; - text-shadow: none; -} - -.ui.yellow.buttons .active.button, -.ui.yellow.buttons .active.button:active, -.ui.yellow.active.button, -.ui.yellow.button .active.button:active { - background-color: #eaae00; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.yellow.buttons .button, -.ui.basic.yellow.button { - background: transparent; - box-shadow: 0 0 0 1px #FBBD08 inset; - color: #FBBD08; -} - -.ui.basic.yellow.buttons .button:hover, -.ui.basic.yellow.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #eaae00 inset; - color: #eaae00; -} - -.ui.basic.yellow.buttons .button:focus, -.ui.basic.yellow.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #daa300 inset; - color: #eaae00; -} - -.ui.basic.yellow.buttons .active.button, -.ui.basic.yellow.active.button { - background: transparent; - box-shadow: 0 0 0 1px #eaae00 inset; - color: #cd9903; -} - -.ui.basic.yellow.buttons .button:active, -.ui.basic.yellow.button:active { - box-shadow: 0 0 0 1px #cd9903 inset; - color: #cd9903; -} - -.ui.buttons:not(.vertical) > .basic.yellow.button:not(:first-child) { - margin-left: -1px; -} - -.ui.olive.buttons .button, -.ui.olive.button { - background-color: #B5CC18; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.olive.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.olive.buttons .button:hover, -.ui.olive.button:hover { - background-color: #a7bd0d; - color: #FFFFFF; - text-shadow: none; -} - -.ui.olive.buttons .button:focus, -.ui.olive.button:focus { - background-color: #a0b605; - color: #FFFFFF; - text-shadow: none; -} - -.ui.olive.buttons .button:active, -.ui.olive.button:active { - background-color: #8d9e13; - color: #FFFFFF; - text-shadow: none; -} - -.ui.olive.buttons .active.button, -.ui.olive.buttons .active.button:active, -.ui.olive.active.button, -.ui.olive.button .active.button:active { - background-color: #aac109; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.olive.buttons .button, -.ui.basic.olive.button { - background: transparent; - box-shadow: 0 0 0 1px #B5CC18 inset; - color: #B5CC18; -} - -.ui.basic.olive.buttons .button:hover, -.ui.basic.olive.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #a7bd0d inset; - color: #a7bd0d; -} - -.ui.basic.olive.buttons .button:focus, -.ui.basic.olive.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #a0b605 inset; - color: #a7bd0d; -} - -.ui.basic.olive.buttons .active.button, -.ui.basic.olive.active.button { - background: transparent; - box-shadow: 0 0 0 1px #aac109 inset; - color: #8d9e13; -} - -.ui.basic.olive.buttons .button:active, -.ui.basic.olive.button:active { - box-shadow: 0 0 0 1px #8d9e13 inset; - color: #8d9e13; -} - -.ui.buttons:not(.vertical) > .basic.olive.button:not(:first-child) { - margin-left: -1px; -} - -.ui.green.buttons .button, -.ui.green.button { - background-color: #21BA45; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.green.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.green.buttons .button:hover, -.ui.green.button:hover { - background-color: #16ab39; - color: #FFFFFF; - text-shadow: none; -} - -.ui.green.buttons .button:focus, -.ui.green.button:focus { - background-color: #0ea432; - color: #FFFFFF; - text-shadow: none; -} - -.ui.green.buttons .button:active, -.ui.green.button:active { - background-color: #198f35; - color: #FFFFFF; - text-shadow: none; -} - -.ui.green.buttons .active.button, -.ui.green.buttons .active.button:active, -.ui.green.active.button, -.ui.green.button .active.button:active { - background-color: #13ae38; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.green.buttons .button, -.ui.basic.green.button { - background: transparent; - box-shadow: 0 0 0 1px #21BA45 inset; - color: #21BA45; -} - -.ui.basic.green.buttons .button:hover, -.ui.basic.green.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #16ab39 inset; - color: #16ab39; -} - -.ui.basic.green.buttons .button:focus, -.ui.basic.green.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #0ea432 inset; - color: #16ab39; -} - -.ui.basic.green.buttons .active.button, -.ui.basic.green.active.button { - background: transparent; - box-shadow: 0 0 0 1px #13ae38 inset; - color: #198f35; -} - -.ui.basic.green.buttons .button:active, -.ui.basic.green.button:active { - box-shadow: 0 0 0 1px #198f35 inset; - color: #198f35; -} - -.ui.buttons:not(.vertical) > .basic.green.button:not(:first-child) { - margin-left: -1px; -} - -.ui.teal.buttons .button, -.ui.teal.button { - background-color: #00B5AD; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.teal.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.teal.buttons .button:hover, -.ui.teal.button:hover { - background-color: #009c95; - color: #FFFFFF; - text-shadow: none; -} - -.ui.teal.buttons .button:focus, -.ui.teal.button:focus { - background-color: #008c86; - color: #FFFFFF; - text-shadow: none; -} - -.ui.teal.buttons .button:active, -.ui.teal.button:active { - background-color: #00827c; - color: #FFFFFF; - text-shadow: none; -} - -.ui.teal.buttons .active.button, -.ui.teal.buttons .active.button:active, -.ui.teal.active.button, -.ui.teal.button .active.button:active { - background-color: #009c95; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.teal.buttons .button, -.ui.basic.teal.button { - background: transparent; - box-shadow: 0 0 0 1px #00B5AD inset; - color: #00B5AD; -} - -.ui.basic.teal.buttons .button:hover, -.ui.basic.teal.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #009c95 inset; - color: #009c95; -} - -.ui.basic.teal.buttons .button:focus, -.ui.basic.teal.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #008c86 inset; - color: #009c95; -} - -.ui.basic.teal.buttons .active.button, -.ui.basic.teal.active.button { - background: transparent; - box-shadow: 0 0 0 1px #009c95 inset; - color: #00827c; -} - -.ui.basic.teal.buttons .button:active, -.ui.basic.teal.button:active { - box-shadow: 0 0 0 1px #00827c inset; - color: #00827c; -} - -.ui.buttons:not(.vertical) > .basic.teal.button:not(:first-child) { - margin-left: -1px; -} - -.ui.blue.buttons .button, -.ui.blue.button { - background-color: #2185D0; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.blue.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.blue.buttons .button:hover, -.ui.blue.button:hover { - background-color: #1678c2; - color: #FFFFFF; - text-shadow: none; -} - -.ui.blue.buttons .button:focus, -.ui.blue.button:focus { - background-color: #0d71bb; - color: #FFFFFF; - text-shadow: none; -} - -.ui.blue.buttons .button:active, -.ui.blue.button:active { - background-color: #1a69a4; - color: #FFFFFF; - text-shadow: none; -} - -.ui.blue.buttons .active.button, -.ui.blue.buttons .active.button:active, -.ui.blue.active.button, -.ui.blue.button .active.button:active { - background-color: #1279c6; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.blue.buttons .button, -.ui.basic.blue.button { - background: transparent; - box-shadow: 0 0 0 1px #2185D0 inset; - color: #2185D0; -} - -.ui.basic.blue.buttons .button:hover, -.ui.basic.blue.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #1678c2 inset; - color: #1678c2; -} - -.ui.basic.blue.buttons .button:focus, -.ui.basic.blue.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #0d71bb inset; - color: #1678c2; -} - -.ui.basic.blue.buttons .active.button, -.ui.basic.blue.active.button { - background: transparent; - box-shadow: 0 0 0 1px #1279c6 inset; - color: #1a69a4; -} - -.ui.basic.blue.buttons .button:active, -.ui.basic.blue.button:active { - box-shadow: 0 0 0 1px #1a69a4 inset; - color: #1a69a4; -} - -.ui.buttons:not(.vertical) > .basic.blue.button:not(:first-child) { - margin-left: -1px; -} - -.ui.violet.buttons .button, -.ui.violet.button { - background-color: #6435C9; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.violet.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.violet.buttons .button:hover, -.ui.violet.button:hover { - background-color: #5829bb; - color: #FFFFFF; - text-shadow: none; -} - -.ui.violet.buttons .button:focus, -.ui.violet.button:focus { - background-color: #4f20b5; - color: #FFFFFF; - text-shadow: none; -} - -.ui.violet.buttons .button:active, -.ui.violet.button:active { - background-color: #502aa1; - color: #FFFFFF; - text-shadow: none; -} - -.ui.violet.buttons .active.button, -.ui.violet.buttons .active.button:active, -.ui.violet.active.button, -.ui.violet.button .active.button:active { - background-color: #5626bf; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.violet.buttons .button, -.ui.basic.violet.button { - background: transparent; - box-shadow: 0 0 0 1px #6435C9 inset; - color: #6435C9; -} - -.ui.basic.violet.buttons .button:hover, -.ui.basic.violet.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #5829bb inset; - color: #5829bb; -} - -.ui.basic.violet.buttons .button:focus, -.ui.basic.violet.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #4f20b5 inset; - color: #5829bb; -} - -.ui.basic.violet.buttons .active.button, -.ui.basic.violet.active.button { - background: transparent; - box-shadow: 0 0 0 1px #5626bf inset; - color: #502aa1; -} - -.ui.basic.violet.buttons .button:active, -.ui.basic.violet.button:active { - box-shadow: 0 0 0 1px #502aa1 inset; - color: #502aa1; -} - -.ui.buttons:not(.vertical) > .basic.violet.button:not(:first-child) { - margin-left: -1px; -} - -.ui.purple.buttons .button, -.ui.purple.button { - background-color: #A333C8; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.purple.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.purple.buttons .button:hover, -.ui.purple.button:hover { - background-color: #9627ba; - color: #FFFFFF; - text-shadow: none; -} - -.ui.purple.buttons .button:focus, -.ui.purple.button:focus { - background-color: #8f1eb4; - color: #FFFFFF; - text-shadow: none; -} - -.ui.purple.buttons .button:active, -.ui.purple.button:active { - background-color: #82299f; - color: #FFFFFF; - text-shadow: none; -} - -.ui.purple.buttons .active.button, -.ui.purple.buttons .active.button:active, -.ui.purple.active.button, -.ui.purple.button .active.button:active { - background-color: #9724be; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.purple.buttons .button, -.ui.basic.purple.button { - background: transparent; - box-shadow: 0 0 0 1px #A333C8 inset; - color: #A333C8; -} - -.ui.basic.purple.buttons .button:hover, -.ui.basic.purple.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #9627ba inset; - color: #9627ba; -} - -.ui.basic.purple.buttons .button:focus, -.ui.basic.purple.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #8f1eb4 inset; - color: #9627ba; -} - -.ui.basic.purple.buttons .active.button, -.ui.basic.purple.active.button { - background: transparent; - box-shadow: 0 0 0 1px #9724be inset; - color: #82299f; -} - -.ui.basic.purple.buttons .button:active, -.ui.basic.purple.button:active { - box-shadow: 0 0 0 1px #82299f inset; - color: #82299f; -} - -.ui.buttons:not(.vertical) > .basic.purple.button:not(:first-child) { - margin-left: -1px; -} - -.ui.pink.buttons .button, -.ui.pink.button { - background-color: #E03997; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.pink.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.pink.buttons .button:hover, -.ui.pink.button:hover { - background-color: #e61a8d; - color: #FFFFFF; - text-shadow: none; -} - -.ui.pink.buttons .button:focus, -.ui.pink.button:focus { - background-color: #e10f85; - color: #FFFFFF; - text-shadow: none; -} - -.ui.pink.buttons .button:active, -.ui.pink.button:active { - background-color: #c71f7e; - color: #FFFFFF; - text-shadow: none; -} - -.ui.pink.buttons .active.button, -.ui.pink.buttons .active.button:active, -.ui.pink.active.button, -.ui.pink.button .active.button:active { - background-color: #ea158d; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.pink.buttons .button, -.ui.basic.pink.button { - background: transparent; - box-shadow: 0 0 0 1px #E03997 inset; - color: #E03997; -} - -.ui.basic.pink.buttons .button:hover, -.ui.basic.pink.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #e61a8d inset; - color: #e61a8d; -} - -.ui.basic.pink.buttons .button:focus, -.ui.basic.pink.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #e10f85 inset; - color: #e61a8d; -} - -.ui.basic.pink.buttons .active.button, -.ui.basic.pink.active.button { - background: transparent; - box-shadow: 0 0 0 1px #ea158d inset; - color: #c71f7e; -} - -.ui.basic.pink.buttons .button:active, -.ui.basic.pink.button:active { - box-shadow: 0 0 0 1px #c71f7e inset; - color: #c71f7e; -} - -.ui.buttons:not(.vertical) > .basic.pink.button:not(:first-child) { - margin-left: -1px; -} - -.ui.brown.buttons .button, -.ui.brown.button { - background-color: #A5673F; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.brown.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.brown.buttons .button:hover, -.ui.brown.button:hover { - background-color: #975b33; - color: #FFFFFF; - text-shadow: none; -} - -.ui.brown.buttons .button:focus, -.ui.brown.button:focus { - background-color: #90532b; - color: #FFFFFF; - text-shadow: none; -} - -.ui.brown.buttons .button:active, -.ui.brown.button:active { - background-color: #805031; - color: #FFFFFF; - text-shadow: none; -} - -.ui.brown.buttons .active.button, -.ui.brown.buttons .active.button:active, -.ui.brown.active.button, -.ui.brown.button .active.button:active { - background-color: #995a31; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.brown.buttons .button, -.ui.basic.brown.button { - background: transparent; - box-shadow: 0 0 0 1px #A5673F inset; - color: #A5673F; -} - -.ui.basic.brown.buttons .button:hover, -.ui.basic.brown.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #975b33 inset; - color: #975b33; -} - -.ui.basic.brown.buttons .button:focus, -.ui.basic.brown.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #90532b inset; - color: #975b33; -} - -.ui.basic.brown.buttons .active.button, -.ui.basic.brown.active.button { - background: transparent; - box-shadow: 0 0 0 1px #995a31 inset; - color: #805031; -} - -.ui.basic.brown.buttons .button:active, -.ui.basic.brown.button:active { - box-shadow: 0 0 0 1px #805031 inset; - color: #805031; -} - -.ui.buttons:not(.vertical) > .basic.brown.button:not(:first-child) { - margin-left: -1px; -} - -.ui.grey.buttons .button, -.ui.grey.button { - background-color: #767676; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.grey.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.grey.buttons .button:hover, -.ui.grey.button:hover { - background-color: #838383; - color: #FFFFFF; - text-shadow: none; -} - -.ui.grey.buttons .button:focus, -.ui.grey.button:focus { - background-color: #8a8a8a; - color: #FFFFFF; - text-shadow: none; -} - -.ui.grey.buttons .button:active, -.ui.grey.button:active { - background-color: #909090; - color: #FFFFFF; - text-shadow: none; -} - -.ui.grey.buttons .active.button, -.ui.grey.buttons .active.button:active, -.ui.grey.active.button, -.ui.grey.button .active.button:active { - background-color: #696969; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.grey.buttons .button, -.ui.basic.grey.button { - background: transparent; - box-shadow: 0 0 0 1px #767676 inset; - color: #767676; -} - -.ui.basic.grey.buttons .button:hover, -.ui.basic.grey.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #838383 inset; - color: #838383; -} - -.ui.basic.grey.buttons .button:focus, -.ui.basic.grey.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #8a8a8a inset; - color: #838383; -} - -.ui.basic.grey.buttons .active.button, -.ui.basic.grey.active.button { - background: transparent; - box-shadow: 0 0 0 1px #696969 inset; - color: #909090; -} - -.ui.basic.grey.buttons .button:active, -.ui.basic.grey.button:active { - box-shadow: 0 0 0 1px #909090 inset; - color: #909090; -} - -.ui.buttons:not(.vertical) > .basic.grey.button:not(:first-child) { - margin-left: -1px; -} - -.ui.black.buttons .button, -.ui.black.button { - background-color: #1B1C1D; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.black.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.black.buttons .button:hover, -.ui.black.button:hover { - background-color: #27292a; - color: #FFFFFF; - text-shadow: none; -} - -.ui.black.buttons .button:focus, -.ui.black.button:focus { - background-color: #2f3032; - color: #FFFFFF; - text-shadow: none; -} - -.ui.black.buttons .button:active, -.ui.black.button:active { - background-color: #343637; - color: #FFFFFF; - text-shadow: none; -} - -.ui.black.buttons .active.button, -.ui.black.buttons .active.button:active, -.ui.black.active.button, -.ui.black.button .active.button:active { - background-color: #0f0f10; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.black.buttons .button, -.ui.basic.black.button { - background: transparent; - box-shadow: 0 0 0 1px #1B1C1D inset; - color: #1B1C1D; -} - -.ui.basic.black.buttons .button:hover, -.ui.basic.black.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #27292a inset; - color: #27292a; -} - -.ui.basic.black.buttons .button:focus, -.ui.basic.black.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #2f3032 inset; - color: #27292a; -} - -.ui.basic.black.buttons .active.button, -.ui.basic.black.active.button { - background: transparent; - box-shadow: 0 0 0 1px #0f0f10 inset; - color: #343637; -} - -.ui.basic.black.buttons .button:active, -.ui.basic.black.button:active { - box-shadow: 0 0 0 1px #343637 inset; - color: #343637; -} - -.ui.buttons:not(.vertical) > .basic.black.button:not(:first-child) { - margin-left: -1px; -} - -/*--------------- - Positive -----------------*/ - -/* Standard */ - -.ui.positive.buttons .button, -.ui.positive.button { - background-color: #21BA45; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.positive.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.positive.buttons .button:hover, -.ui.positive.button:hover { - background-color: #16ab39; - color: #FFFFFF; - text-shadow: none; -} - -.ui.positive.buttons .button:focus, -.ui.positive.button:focus { - background-color: #0ea432; - color: #FFFFFF; - text-shadow: none; -} - -.ui.positive.buttons .button:active, -.ui.positive.button:active { - background-color: #198f35; - color: #FFFFFF; - text-shadow: none; -} - -.ui.positive.buttons .active.button, -.ui.positive.buttons .active.button:active, -.ui.positive.active.button, -.ui.positive.button .active.button:active { - background-color: #13ae38; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.positive.buttons .button, -.ui.basic.positive.button { - background: transparent; - box-shadow: 0 0 0 1px #21BA45 inset; - color: #21BA45; -} - -.ui.basic.positive.buttons .button:hover, -.ui.basic.positive.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #16ab39 inset; - color: #16ab39; -} - -.ui.basic.positive.buttons .button:focus, -.ui.basic.positive.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #0ea432 inset; - color: #16ab39; -} - -.ui.basic.positive.buttons .active.button, -.ui.basic.positive.active.button { - background: transparent; - box-shadow: 0 0 0 1px #13ae38 inset; - color: #198f35; -} - -.ui.basic.positive.buttons .button:active, -.ui.basic.positive.button:active { - box-shadow: 0 0 0 1px #198f35 inset; - color: #198f35; -} - -.ui.buttons:not(.vertical) > .basic.positive.button:not(:first-child) { - margin-left: -1px; -} - -/*--------------- - Negative -----------------*/ - -/* Standard */ - -.ui.negative.buttons .button, -.ui.negative.button { - background-color: #DB2828; - color: #FFFFFF; - text-shadow: none; - background-image: none; -} - -.ui.negative.button { - box-shadow: 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.negative.buttons .button:hover, -.ui.negative.button:hover { - background-color: #d01919; - color: #FFFFFF; - text-shadow: none; -} - -.ui.negative.buttons .button:focus, -.ui.negative.button:focus { - background-color: #ca1010; - color: #FFFFFF; - text-shadow: none; -} - -.ui.negative.buttons .button:active, -.ui.negative.button:active { - background-color: #b21e1e; - color: #FFFFFF; - text-shadow: none; -} - -.ui.negative.buttons .active.button, -.ui.negative.buttons .active.button:active, -.ui.negative.active.button, -.ui.negative.button .active.button:active { - background-color: #d41515; - color: #FFFFFF; - text-shadow: none; -} - -/* Basic */ - -.ui.basic.negative.buttons .button, -.ui.basic.negative.button { - background: transparent; - box-shadow: 0 0 0 1px #DB2828 inset; - color: #DB2828; -} - -.ui.basic.negative.buttons .button:hover, -.ui.basic.negative.button:hover { - background: transparent; - box-shadow: 0 0 0 1px #d01919 inset; - color: #d01919; -} - -.ui.basic.negative.buttons .button:focus, -.ui.basic.negative.button:focus { - background: transparent; - box-shadow: 0 0 0 1px #ca1010 inset; - color: #d01919; -} - -.ui.basic.negative.buttons .active.button, -.ui.basic.negative.active.button { - background: transparent; - box-shadow: 0 0 0 1px #d41515 inset; - color: #b21e1e; -} - -.ui.basic.negative.buttons .button:active, -.ui.basic.negative.button:active { - box-shadow: 0 0 0 1px #b21e1e inset; - color: #b21e1e; -} - -.ui.buttons:not(.vertical) > .basic.negative.button:not(:first-child) { - margin-left: -1px; -} - -/******************************* - Groups - *******************************/ - -.ui.buttons { - display: inline-flex; - flex-direction: row; - font-size: 0; - vertical-align: baseline; - margin: 0 0.25em 0 0; -} - -.ui.buttons:not(.basic):not(.inverted) { - box-shadow: none; -} - -/* Clearfix */ - -.ui.buttons:after { - content: "."; - display: block; - height: 0; - clear: both; - visibility: hidden; -} - -/* Standard Group */ - -.ui.buttons .button { - flex: 1 0 auto; - border-radius: 0; - margin: 0 0 0 0; -} - -.ui.buttons:not(.basic):not(.inverted) > .button:not(.basic):not(.inverted) { - box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34, 36, 38, 0.15) inset; -} - -.ui.buttons .button:first-child { - border-left: none; - margin-left: 0; - border-top-left-radius: 0.28571429rem; - border-bottom-left-radius: 0.28571429rem; -} - -.ui.buttons .button:last-child { - border-top-right-radius: 0.28571429rem; - border-bottom-right-radius: 0.28571429rem; -} - -/* Vertical Style */ - -.ui.vertical.buttons { - display: inline-flex; - flex-direction: column; -} - -.ui.vertical.buttons .button { - display: block; - float: none; - width: 100%; - margin: 0 0 0 0; - box-shadow: none; - border-radius: 0; -} - -.ui.vertical.buttons .button:first-child { - border-top-left-radius: 0.28571429rem; - border-top-right-radius: 0.28571429rem; -} - -.ui.vertical.buttons .button:last-child { - margin-bottom: 0; - border-bottom-left-radius: 0.28571429rem; - border-bottom-right-radius: 0.28571429rem; -} - -.ui.vertical.buttons .button:only-child { - border-radius: 0.28571429rem; -} - -/******************************* - Theme Overrides -*******************************/ - -/******************************* - Site Overrides -*******************************/ /*! * # Fomantic-UI - Dimmer * http://github.com/fomantic/Fomantic-UI/ diff --git a/web_src/fomantic/semantic.json b/web_src/fomantic/semantic.json index 5b3a480d53..489ca7b9b7 100644 --- a/web_src/fomantic/semantic.json +++ b/web_src/fomantic/semantic.json @@ -22,7 +22,6 @@ "admin": false, "components": [ "api", - "button", "dimmer", "dropdown", "form", diff --git a/web_src/js/components/PullRequestMergeForm.vue b/web_src/js/components/PullRequestMergeForm.vue index bd0901a7b5..9efa8840ac 100644 --- a/web_src/js/components/PullRequestMergeForm.vue +++ b/web_src/js/components/PullRequestMergeForm.vue @@ -138,7 +138,7 @@ export default {
-
+
- very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label + very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label
diff --git a/web_src/css/modules/label.css b/web_src/css/modules/label.css index 696080b667..2032b2c84b 100644 --- a/web_src/css/modules/label.css +++ b/web_src/css/modules/label.css @@ -6,7 +6,6 @@ align-items: center; gap: .25rem; min-width: 0; - max-width: 100%; /* since we are using "flex" to align label contents, we also need to limit the x-axis, a label shouldn't be wider than 100% */ vertical-align: middle; line-height: 1; background: var(--color-label-bg); From 708e87e17df2b6a03eca3cac026a51beed296b5b Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 15 Apr 2024 02:40:53 +0000 Subject: [PATCH 094/247] [skip ci] Updated licenses and gitignores --- options/license/BSD-2-clause-first-lines | 27 ++++++++++++++++++++++++ options/license/Sun-PPP-2000 | 13 ++++++++++++ options/license/pkgconf | 7 ++++++ 3 files changed, 47 insertions(+) create mode 100644 options/license/BSD-2-clause-first-lines create mode 100644 options/license/Sun-PPP-2000 create mode 100644 options/license/pkgconf diff --git a/options/license/BSD-2-clause-first-lines b/options/license/BSD-2-clause-first-lines new file mode 100644 index 0000000000..3774caf24a --- /dev/null +++ b/options/license/BSD-2-clause-first-lines @@ -0,0 +1,27 @@ +Copyright (C) 2006,2007,2009 NTT (Nippon Telegraph and Telephone +Corporation). All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer as the first lines of this file unmodified. + +2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY NTT "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL NTT BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/options/license/Sun-PPP-2000 b/options/license/Sun-PPP-2000 new file mode 100644 index 0000000000..914c19544a --- /dev/null +++ b/options/license/Sun-PPP-2000 @@ -0,0 +1,13 @@ +Copyright (c) 2000 by Sun Microsystems, Inc. +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation is hereby granted, provided that the above copyright +notice appears in all copies. + +SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF +THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR +ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR +DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES diff --git a/options/license/pkgconf b/options/license/pkgconf new file mode 100644 index 0000000000..b8b2ffd996 --- /dev/null +++ b/options/license/pkgconf @@ -0,0 +1,7 @@ +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +This software is provided 'as is' and without any warranty, express or +implied. In no event shall the authors be liable for any damages arising +from the use of this software. From 994920c677b04a720726d982e4d6212664b82a43 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Apr 2024 10:24:36 +0200 Subject: [PATCH 095/247] Kill all gitea processes before air build (#30477) So it happened to me multiple times that air leaves zombie processes after termination. I think ultimately it's some kind of bug in air, but we can work around. The change in the delay is unrelated to the zombie processes but seems to help a bit with duplicate changes resulting in duplicate `make generate` as seen here: Screenshot 2024-04-14 at 17 05 47 --------- Co-authored-by: delvh --- .air.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.air.toml b/.air.toml index de97bd8b29..3740c4d4aa 100644 --- a/.air.toml +++ b/.air.toml @@ -2,9 +2,10 @@ root = "." tmp_dir = ".air" [build] +pre_cmd = ["killall -9 gitea 2>/dev/null || true"] # kill off potential zombie processes from previous runs cmd = "make --no-print-directory backend" bin = "gitea" -delay = 1000 +delay = 2000 include_ext = ["go", "tmpl"] include_file = ["main.go"] include_dir = ["cmd", "models", "modules", "options", "routers", "services"] From 1508a85f6235814271ea927d651bcbcd8c9f5f18 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Apr 2024 10:49:48 +0200 Subject: [PATCH 096/247] Fix overflow on issue dependency (#30484) Small tweak here to prevent this and likely other events from overflowing in the timeline: Screenshot 2024-04-14 at 22 53 17 Co-authored-by: Giteabot --- web_src/css/repo.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 887789115e..0f6bf482b5 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -1063,6 +1063,12 @@ td .commit-summary { margin-left: 15px; } +.repository.view.issue .comment-list .event .detail .text { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + .repository.view.issue .comment-list .event .segments { box-shadow: none; } From c63060b130d34e3f03f28f4dccbf04d381a95c17 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 15 Apr 2024 22:11:07 +0800 Subject: [PATCH 097/247] Fix code owners will not be mentioned when a pull request comes from a forked repository (#30476) Fix #30277 Caused by #29783 --- services/issue/pull.go | 8 ++++---- tests/integration/pull_create_test.go | 25 +++++++++++++++++++++++++ tests/integration/pull_review_test.go | 10 +++++++++- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/services/issue/pull.go b/services/issue/pull.go index b7b63a7024..4a0009e82f 100644 --- a/services/issue/pull.go +++ b/services/issue/pull.go @@ -51,14 +51,14 @@ func PullRequestCodeOwnersReview(ctx context.Context, issue *issues_model.Issue, return nil, err } - if pr.HeadRepo.IsFork { - return nil, nil - } - if err := pr.LoadBaseRepo(ctx); err != nil { return nil, err } + if pr.BaseRepo.IsFork { + return nil, nil + } + repo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo) if err != nil { return nil, err diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 029ea65d71..609bd73fd5 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -4,6 +4,7 @@ package integration import ( + "fmt" "net/http" "net/http/httptest" "net/url" @@ -57,6 +58,30 @@ func testPullCreate(t *testing.T, session *TestSession, user, repo string, toSel return resp } +func testPullCreateDirectly(t *testing.T, session *TestSession, baseRepoOwner, baseRepoName, baseBranch, headRepoOwner, headRepoName, headBranch, title string) *httptest.ResponseRecorder { + headCompare := headBranch + if headRepoOwner != "" { + if headRepoName != "" { + headCompare = fmt.Sprintf("%s/%s:%s", headRepoOwner, headRepoName, headBranch) + } else { + headCompare = fmt.Sprintf("%s:%s", headRepoOwner, headBranch) + } + } + req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/compare/%s...%s", baseRepoOwner, baseRepoName, baseBranch, headCompare)) + resp := session.MakeRequest(t, req, http.StatusOK) + + // Submit the form for creating the pull + htmlDoc := NewHTMLParser(t, resp.Body) + link, exists := htmlDoc.doc.Find("form.ui.form").Attr("action") + assert.True(t, exists, "The template has changed") + req = NewRequestWithValues(t, "POST", link, map[string]string{ + "_csrf": htmlDoc.GetCSRF(), + "title": title, + }) + resp = session.MakeRequest(t, req, http.StatusOK) + return resp +} + func TestPullCreate(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user1") diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go index 9a5877697c..2d8b3cb4ab 100644 --- a/tests/integration/pull_review_test.go +++ b/tests/integration/pull_review_test.go @@ -161,10 +161,18 @@ func TestPullView_CodeOwner(t *testing.T) { assert.NoError(t, err) session := loginUser(t, "user5") - testPullCreate(t, session, "user5", "test_codeowner", true, forkedRepo.DefaultBranch, "codeowner-basebranch-forked", "Test Pull Request2") + + // create a pull request on the forked repository, code reviewers should not be mentioned + testPullCreateDirectly(t, session, "user5", "test_codeowner", forkedRepo.DefaultBranch, "", "", "codeowner-basebranch-forked", "Test Pull Request on Forked Repository") pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"}) unittest.AssertExistsIf(t, false, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8}) + + // create a pull request to base repository, code reviewers should be mentioned + testPullCreateDirectly(t, session, repo.OwnerName, repo.Name, repo.DefaultBranch, forkedRepo.OwnerName, forkedRepo.Name, "codeowner-basebranch-forked", "Test Pull Request3") + + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"}) + unittest.AssertExistsIf(t, true, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8}) }) }) } From 2dc7e9e5fe66a361021e41046f7a88e61a45300b Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Apr 2024 19:20:32 +0200 Subject: [PATCH 098/247] Fix button color on red and green buttons (#30500) Previously these colors were provided by fomantic css. I missed them. Fixes: https://github.com/go-gitea/gitea/issues/30499 Regressed by: https://github.com/go-gitea/gitea/pull/30475 --- web_src/css/modules/button.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web_src/css/modules/button.css b/web_src/css/modules/button.css index 47f55df7fa..87b9ddf292 100644 --- a/web_src/css/modules/button.css +++ b/web_src/css/modules/button.css @@ -249,6 +249,7 @@ .ui.red.button, .ui.red.buttons .button { + color: var(--color-white); background: var(--color-red); } @@ -283,6 +284,7 @@ .ui.green.button, .ui.green.buttons .button { + color: var(--color-white); background: var(--color-green); } From 3b40ebf895307a705738df3c5aba31843f0be74d Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Apr 2024 20:22:53 +0200 Subject: [PATCH 099/247] Remove active border on pointing menu (#30486) It looks better when these menus don't flash a border-bottom on click. --- web_src/css/modules/menu.css | 1 - 1 file changed, 1 deletion(-) diff --git a/web_src/css/modules/menu.css b/web_src/css/modules/menu.css index 2581d8fab2..a392ffb5e9 100644 --- a/web_src/css/modules/menu.css +++ b/web_src/css/modules/menu.css @@ -588,7 +588,6 @@ .ui.secondary.pointing.menu .dropdown.item:active, .ui.secondary.pointing.menu a.item:active { background-color: transparent; - border-color: var(--color-secondary); } .ui.secondary.pointing.menu .active.item { From 2c80421243ed1fd6f53c3e1a84c06648524f7c66 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 16 Apr 2024 04:08:31 +0900 Subject: [PATCH 100/247] Convert max file name length to 255 (#30489) Quick/Partly fix #29907 In Linux and MacOS, by default the max file name length is 255. In windows, it depends on the version and settings, and has no file name length limitation, but has path length limitation. By default it is 260, considering path length is longer than filename, so I think it is ok to do this. For Windows, see https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation?tabs=registry For Linux, see https://github.com/torvalds/linux/blob/master/include/uapi/linux/limits.h#L12-L13 For MacOS, see https://discussions.apple.com/thread/254788848?sortBy=best --- templates/repo/editor/edit.tmpl | 2 +- templates/repo/editor/upload.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index 46f82c47d4..d52e5a047a 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -15,7 +15,7 @@ {{range $i, $v := .TreeNames}} {{if eq $i $l}} - + {{svg "octicon-info"}} {{else}} {{$v}} diff --git a/templates/repo/editor/upload.tmpl b/templates/repo/editor/upload.tmpl index 0a7c49dae3..5725020406 100644 --- a/templates/repo/editor/upload.tmpl +++ b/templates/repo/editor/upload.tmpl @@ -13,7 +13,7 @@ {{range $i, $v := .TreeNames}} {{if eq $i $l}} - + {{svg "octicon-info"}} {{else}} {{$v}} From b9f69b4a4d1d6b5b1f94852f6dfcae41b30658ff Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Apr 2024 21:46:52 +0200 Subject: [PATCH 101/247] Fix various overflows on actions view (#30344) Fix a number of text overflow issues in actions view and run list. Also improve mobile view of run list. Fixes: https://github.com/go-gitea/gitea/issues/30328 Screenshot 2024-04-08 at 23 10 16 Screenshot 2024-04-08 at 23 17 46 Screenshot 2024-04-08 at 23 49 05 Screenshot 2024-04-08 at 23 55 30 --- templates/repo/actions/runs_list.tmpl | 14 ++++++------- web_src/css/actions.css | 26 +++++++++++++++++++++++- web_src/js/components/RepoActionView.vue | 16 ++++++++++----- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index ac5049cf56..20330b5d62 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -1,4 +1,4 @@ -
+
{{if not .Runs}}
{{svg "octicon-no-entry" 48}} @@ -28,14 +28,14 @@
{{if .RefLink}} - {{.PrettyRef}} + {{.PrettyRef}} {{else}} - {{.PrettyRef}} + {{.PrettyRef}} {{end}} -
-
-
{{svg "octicon-calendar" 16}}{{TimeSinceUnix .Updated ctx.Locale}}
-
{{svg "octicon-stopwatch" 16}}{{.Duration}}
+
+
{{svg "octicon-calendar" 16}}{{TimeSinceUnix .Updated ctx.Locale}}
+
{{svg "octicon-stopwatch" 16}}{{.Duration}}
+
{{end}} diff --git a/web_src/css/actions.css b/web_src/css/actions.css index 1d5bea2395..0ab09f537a 100644 --- a/web_src/css/actions.css +++ b/web_src/css/actions.css @@ -44,9 +44,10 @@ } .run-list-item-right { - flex: 0 0 min(20%, 130px); + width: 130px; display: flex; flex-direction: column; + flex-shrink: 0; gap: 3px; color: var(--color-text-light); } @@ -57,3 +58,26 @@ gap: .25rem; align-items: center; } + +.run-list .flex-item-trailing { + flex-wrap: nowrap; + width: 280px; + flex: 0 0 280px; +} + +.run-list-ref { + display: inline-block !important; +} + +@media (max-width: 767.98px) { + .run-list .flex-item-trailing { + flex-direction: column; + align-items: flex-end; + width: auto; + flex-basis: auto; + } + .run-list-item-right, + .run-list-ref { + max-width: 110px; + } +} diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 06c42f0b35..16ce3fc80d 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -377,7 +377,7 @@ export function initRepositoryActionView() { -
@@ -386,8 +386,8 @@ export function initRepositoryActionView() { {{ run.commit.shortSHA }} {{ run.commit.localePushedBy }} {{ run.commit.pusher.displayName }} - - {{ run.commit.branch.name }} + + {{ run.commit.branch.name }}
@@ -426,8 +426,8 @@ export function initRepositoryActionView() {
-
-

+
+

{{ currentJob.title }}

@@ -503,6 +503,7 @@ export function initRepositoryActionView() { display: flex; align-items: center; justify-content: space-between; + gap: 8px; } .action-info-summary-title { @@ -513,6 +514,7 @@ export function initRepositoryActionView() { font-size: 20px; margin: 0 0 0 8px; flex: 1; + overflow-wrap: anywhere; } .action-commit-summary { @@ -728,6 +730,10 @@ export function initRepositoryActionView() { font-size: 12px; } +.job-info-header-left { + flex: 1; +} + .job-step-container { max-height: 100%; border-radius: 0 0 var(--border-radius) var(--border-radius); From 3b045ee165c8ba06c99c28d57b849fb53a502e84 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 16 Apr 2024 00:23:51 +0000 Subject: [PATCH 102/247] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 0edd6c5dd7..74ff775cc8 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -25,6 +25,7 @@ enable_javascript=このウェブサイトにはJavaScriptが必要です。 toc=目次 licenses=ライセンス return_to_gitea=Giteaに戻る +more_items=その他の項目 username=ユーザー名 email=メールアドレス @@ -1003,6 +1004,7 @@ fork_visibility_helper=フォークしたリポジトリの公開/非公開は fork_branch=フォークにクローンされるブランチ all_branches=すべてのブランチ fork_no_valid_owners=このリポジトリには有効なオーナーがいないため、フォークできません。 +fork.blocked_user=リポジトリのオーナーがあなたをブロックしているため、リポジトリをフォークできません。 use_template=このテンプレートを使用 open_with_editor=%s で開く download_zip=ZIPファイルをダウンロード @@ -1179,6 +1181,7 @@ watch=ウォッチ unstar=スター取消 star=スター fork=フォーク +action.blocked_user=リポジトリのオーナーがあなたをブロックしているため、アクションを実行できません。 download_archive=リポジトリをダウンロード more_operations=その他の操作 @@ -1427,6 +1430,8 @@ issues.new.assignees=担当者 issues.new.clear_assignees=担当者をクリア issues.new.no_assignees=担当者なし issues.new.no_reviewers=レビューアなし +issues.new.blocked_user=リポジトリのオーナーがあなたをブロックしているため、イシューを作成できません。 +issues.edit.blocked_user=投稿者またはリポジトリのオーナーがあなたをブロックしているため、内容を編集できません。 issues.choose.get_started=始める issues.choose.open_external_link=オープン issues.choose.blank=デフォルト @@ -1541,6 +1546,7 @@ issues.close_comment_issue=コメントしてクローズ issues.reopen_issue=再オープンする issues.reopen_comment_issue=コメントして再オープン issues.create_comment=コメントする +issues.comment.blocked_user=投稿者またはリポジトリのオーナーがあなたをブロックしているため、コメントの作成や編集はできません。 issues.closed_at=`がイシューをクローズ %[2]s` issues.reopened_at=`がイシューを再オープン %[2]s` issues.commit_ref_at=`がコミットでこのイシューを参照 %[2]s` @@ -1739,6 +1745,7 @@ compare.compare_head=比較 pulls.desc=プルリクエストとコードレビューの有効化。 pulls.new=新しいプルリクエスト +pulls.new.blocked_user=リポジトリのオーナーがあなたをブロックしているため、プルリクエストを作成できません。 pulls.view=プルリクエストを表示 pulls.compare_changes=新規プルリクエスト pulls.allow_edits_from_maintainers=メンテナーからの編集を許可する @@ -1960,6 +1967,7 @@ wiki.original_git_entry_tooltip=フレンドリーリンクを使用する代わ activity=アクティビティ activity.navbar.pulse=Pulse +activity.navbar.code_frequency=コード更新頻度 activity.navbar.contributors=貢献者 activity.navbar.recent_commits=最近のコミット activity.period.filter_label=期間: @@ -2080,6 +2088,8 @@ settings.branches.add_new_rule=新しいルールを追加 settings.advanced_settings=拡張設定 settings.wiki_desc=Wikiを有効にする settings.use_internal_wiki=ビルトインのWikiを使用する +settings.default_wiki_branch_name=デフォルトのWikiブランチ名 +settings.failed_to_change_default_wiki_branch=デフォルトのWikiブランチを変更できませんでした。 settings.use_external_wiki=外部のWikiを使用する settings.external_wiki_url=外部WikiのURL settings.external_wiki_url_error=外部WikiのURLが有効なURLではありません。 @@ -2110,6 +2120,9 @@ settings.pulls.default_allow_edits_from_maintainers=デフォルトでメンテ settings.releases_desc=リリースを有効にする settings.packages_desc=リポジトリパッケージレジストリを有効にする settings.projects_desc=プロジェクトを有効にする +settings.projects_mode_desc=プロジェクト モード (表示するプロジェクトの種類) +settings.projects_mode_repo=リポジトリのプロジェクトのみ +settings.projects_mode_owner=ユーザーや組織のプロジェクトのみ settings.projects_mode_all=すべてのプロジェクト settings.actions_desc=Actionsを有効にする settings.admin_settings=管理者用設定 @@ -2136,6 +2149,7 @@ settings.convert_fork_succeed=フォークを通常のリポジトリに変換 settings.transfer=オーナー移転 settings.transfer.rejected=リポジトリの移転は拒否されました。 settings.transfer.success=リポジトリの移転が成功しました。 +settings.transfer.blocked_user=新しいオーナーがあなたをブロックしているため、リポジトリを移転できません。 settings.transfer_abort=転送をキャンセル settings.transfer_abort_invalid=存在しないリポジトリの移転はキャンセルできません。 settings.transfer_abort_success=%s へのリポジトリ移転は正常にキャンセルされました。 @@ -2181,6 +2195,7 @@ settings.add_collaborator_success=共同作業者を追加しました。 settings.add_collaborator_inactive_user=アクティベートされていないユーザーを共同作業者として追加することはできません。 settings.add_collaborator_owner=共同作業者としてオーナーを追加することはできません。 settings.add_collaborator_duplicate=共同作業者として既にこのリポジトリに追加されています。 +settings.add_collaborator.blocked_user=共同作業者がリポジトリのオーナーによってブロックされているか、またはブロックしています。 settings.delete_collaborator=削除 settings.collaborator_deletion=共同作業者の削除 settings.collaborator_deletion_desc=共同作業者を削除し、このリポジトリへのアクセス権を取り消します。 続行しますか? @@ -2619,12 +2634,14 @@ find_file.no_matching=一致するファイルが見つかりません error.csv.too_large=このファイルは大きすぎるため表示できません。 error.csv.unexpected=このファイルは %d 行目の %d 文字目に予期しない文字が含まれているため表示できません。 error.csv.invalid_field_count=このファイルは %d 行目のフィールドの数が正しくないため表示できません。 +error.broken_git_hook=このリポジトリのGitフックが壊れているようです。 ドキュメントに従って修正し、その後いくつかのコミットをプッシュして状態を最新にしてください。 [graphs] component_loading=%sを読み込み中... component_loading_failed=%sを読み込めませんでした component_loading_info=少し時間がかかるかもしれません… component_failed_to_load=予期しないエラーが発生しました。 +code_frequency.what=コード更新頻度 contributors.what=実績 recent_commits.what=最近のコミット @@ -2753,6 +2770,7 @@ teams.invite.by=%s からの招待 teams.invite.description=下のボタンをクリックしてチームに参加してください。 [admin] +maintenance=メンテナンス dashboard=ダッシュボード self_check=セルフチェック identity_access=アイデンティティとアクセス @@ -2776,6 +2794,7 @@ settings=管理設定 dashboard.new_version_hint=Gitea %s が入手可能になりました。 現在実行しているのは %s です。 詳細は ブログ を確認してください。 dashboard.statistic=サマリー +dashboard.maintenance_operations=メンテナンス操作 dashboard.system_status=システム状況 dashboard.operation_name=操作の名称 dashboard.operation_switch=切り替え @@ -3282,6 +3301,7 @@ notices.op=操作 notices.delete_success=システム通知を削除しました。 self_check.no_problem_found=今のところ問題は見つかっていません。 +self_check.startup_warnings=起動時の警告: self_check.database_collation_mismatch=データベースに想定される照合順序: %s self_check.database_collation_case_insensitive=データベースは照合順序 %s を使用しており、大文字小文字を区別しません。 Giteaはその照合順序でも動作するかもしれませんが、まれに期待どおり動作しないケースがあるかもしれません。 self_check.database_inconsistent_collation_columns=データベースは照合順序 %s を使用していますが、以下のカラムはそれと一致しない照合順序を使用しており、予期せぬ問題を引き起こす可能性があります。 From c70e442ce4b99e2a1f1bf216afcfa1ad78d1925a Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 16 Apr 2024 11:45:04 +0800 Subject: [PATCH 103/247] feat(api): implement branch/commit comparison API (#30349) - Add new `Compare` struct to represent comparison between two commits - Introduce new API endpoint `/compare/*` to get commit comparison information - Create new file `repo_compare.go` with the `Compare` struct definition - Add new file `compare.go` in `routers/api/v1/repo` to handle comparison logic - Add new file `compare.go` in `routers/common` to define `CompareInfo` struct - Refactor `ParseCompareInfo` function to use `common.CompareInfo` struct - Update Swagger documentation to include the new API endpoint for commit comparison - Remove duplicate `CompareInfo` struct from `routers/web/repo/compare.go` - Adjust base path in Swagger template to be relative (`/api/v1`) GitHub API https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#compare-two-commits --------- Signed-off-by: Bo-Yi Wu Co-authored-by: Lunny Xiao --- modules/structs/repo_compare.go | 10 +++ routers/api/v1/api.go | 2 + routers/api/v1/repo/compare.go | 99 ++++++++++++++++++++++ routers/api/v1/swagger/repo.go | 6 ++ routers/common/compare.go | 21 +++++ routers/web/repo/compare.go | 18 +--- templates/swagger/v1_json.tmpl | 70 +++++++++++++++ tests/integration/api_repo_compare_test.go | 38 +++++++++ 8 files changed, 250 insertions(+), 14 deletions(-) create mode 100644 modules/structs/repo_compare.go create mode 100644 routers/api/v1/repo/compare.go create mode 100644 routers/common/compare.go create mode 100644 tests/integration/api_repo_compare_test.go diff --git a/modules/structs/repo_compare.go b/modules/structs/repo_compare.go new file mode 100644 index 0000000000..8a12498705 --- /dev/null +++ b/modules/structs/repo_compare.go @@ -0,0 +1,10 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package structs + +// Compare represents a comparison between two commits. +type Compare struct { + TotalCommits int `json:"total_commits"` // Total number of commits in the comparison. + Commits []*Commit `json:"commits"` // List of commits in the comparison. +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index e870378c4b..1fc7682966 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1066,6 +1066,8 @@ func Routes() *web.Route { m.Post("/migrate", reqToken(), bind(api.MigrateRepoOptions{}), repo.Migrate) m.Group("/{username}/{reponame}", func() { + m.Get("/compare/*", reqRepoReader(unit.TypeCode), repo.CompareDiff) + m.Combo("").Get(reqAnyRepoReader(), repo.Get). Delete(reqToken(), reqOwner(), repo.Delete). Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), repo.Edit) diff --git a/routers/api/v1/repo/compare.go b/routers/api/v1/repo/compare.go new file mode 100644 index 0000000000..549b9b7fa9 --- /dev/null +++ b/routers/api/v1/repo/compare.go @@ -0,0 +1,99 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "net/http" + "strings" + + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/gitrepo" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/convert" +) + +// CompareDiff compare two branches or commits +func CompareDiff(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/compare/{basehead} Get commit comparison information + // --- + // summary: Get commit comparison information + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: basehead + // in: path + // description: compare two branches or commits + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/Compare" + // "404": + // "$ref": "#/responses/notFound" + + if ctx.Repo.GitRepo == nil { + gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository) + if err != nil { + ctx.Error(http.StatusInternalServerError, "OpenRepository", err) + return + } + ctx.Repo.GitRepo = gitRepo + defer gitRepo.Close() + } + + infoPath := ctx.Params("*") + infos := []string{ctx.Repo.Repository.DefaultBranch, ctx.Repo.Repository.DefaultBranch} + if infoPath != "" { + infos = strings.SplitN(infoPath, "...", 2) + if len(infos) != 2 { + if infos = strings.SplitN(infoPath, "..", 2); len(infos) != 2 { + infos = []string{ctx.Repo.Repository.DefaultBranch, infoPath} + } + } + } + + _, _, headGitRepo, ci, _, _ := parseCompareInfo(ctx, api.CreatePullRequestOption{ + Base: infos[0], + Head: infos[1], + }) + if ctx.Written() { + return + } + defer headGitRepo.Close() + + verification := ctx.FormString("verification") == "" || ctx.FormBool("verification") + files := ctx.FormString("files") == "" || ctx.FormBool("files") + + apiCommits := make([]*api.Commit, 0, len(ci.Commits)) + userCache := make(map[string]*user_model.User) + for i := 0; i < len(ci.Commits); i++ { + apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ci.Commits[i], userCache, + convert.ToCommitOptions{ + Stat: true, + Verification: verification, + Files: files, + }) + if err != nil { + ctx.ServerError("toCommit", err) + return + } + apiCommits = append(apiCommits, apiCommit) + } + + ctx.JSON(http.StatusOK, &api.Compare{ + TotalCommits: len(ci.Commits), + Commits: apiCommits, + }) +} diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go index 3e23aa4d5a..c3219f28d6 100644 --- a/routers/api/v1/swagger/repo.go +++ b/routers/api/v1/swagger/repo.go @@ -414,3 +414,9 @@ type swaggerRepoNewIssuePinsAllowed struct { // in:body Body api.NewIssuePinsAllowed `json:"body"` } + +// swagger:response Compare +type swaggerCompare struct { + // in:body + Body api.Compare `json:"body"` +} diff --git a/routers/common/compare.go b/routers/common/compare.go new file mode 100644 index 0000000000..4d1cc2f0d8 --- /dev/null +++ b/routers/common/compare.go @@ -0,0 +1,21 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package common + +import ( + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" +) + +// CompareInfo represents the collected results from ParseCompareInfo +type CompareInfo struct { + HeadUser *user_model.User + HeadRepo *repo_model.Repository + HeadGitRepo *git.Repository + CompareInfo *git.CompareInfo + BaseBranch string + HeadBranch string + DirectComparison bool +} diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index cfb0e859bd..035a92f228 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -35,6 +35,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/gitdiff" @@ -185,21 +186,10 @@ func setCsvCompareContext(ctx *context.Context) { } } -// CompareInfo represents the collected results from ParseCompareInfo -type CompareInfo struct { - HeadUser *user_model.User - HeadRepo *repo_model.Repository - HeadGitRepo *git.Repository - CompareInfo *git.CompareInfo - BaseBranch string - HeadBranch string - DirectComparison bool -} - // ParseCompareInfo parse compare info between two commit for preparing comparing references -func ParseCompareInfo(ctx *context.Context) *CompareInfo { +func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { baseRepo := ctx.Repo.Repository - ci := &CompareInfo{} + ci := &common.CompareInfo{} fileOnly := ctx.FormBool("file-only") @@ -576,7 +566,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { // PrepareCompareDiff renders compare diff page func PrepareCompareDiff( ctx *context.Context, - ci *CompareInfo, + ci *common.CompareInfo, whitespaceBehavior git.TrustedCmdArgs, ) bool { var ( diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index b5677c77e0..254b7daf17 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -5340,6 +5340,51 @@ } } }, + "/repos/{owner}/{repo}/compare/{basehead}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Get", + "commit", + "comparison" + ], + "summary": "Get commit comparison information", + "operationId": "information", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "compare two branches or commits", + "name": "basehead", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/Compare" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/contents": { "get": { "produces": [ @@ -18717,6 +18762,25 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "Compare": { + "type": "object", + "title": "Compare represents a comparison between two commits.", + "properties": { + "commits": { + "type": "array", + "items": { + "$ref": "#/definitions/Commit" + }, + "x-go-name": "Commits" + }, + "total_commits": { + "type": "integer", + "format": "int64", + "x-go-name": "TotalCommits" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "ContentsResponse": { "description": "ContentsResponse contains information about a repo's entry's (dir, file, symlink, submodule) metadata and content", "type": "object", @@ -24678,6 +24742,12 @@ } } }, + "Compare": { + "description": "", + "schema": { + "$ref": "#/definitions/Compare" + } + }, "ContentsListResponse": { "description": "ContentsListResponse", "schema": { diff --git a/tests/integration/api_repo_compare_test.go b/tests/integration/api_repo_compare_test.go new file mode 100644 index 0000000000..f3188eb49f --- /dev/null +++ b/tests/integration/api_repo_compare_test.go @@ -0,0 +1,38 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "net/http" + "testing" + + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" +) + +func TestAPICompareBranches(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + // Login as User2. + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + repoName := "repo20" + + req := NewRequestf(t, "GET", "/api/v1/repos/user2/%s/compare/add-csv...remove-files-b", repoName). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + + var apiResp *api.Compare + DecodeJSON(t, resp, &apiResp) + + assert.Equal(t, 2, apiResp.TotalCommits) + assert.Len(t, apiResp.Commits, 2) +} From cf9061f44a439aa7775e301a7467dbda22a06eaa Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Tue, 16 Apr 2024 14:13:00 +0900 Subject: [PATCH 104/247] Fix empty field `login_name` in API response JSON when creating user (#30511) Fix #30508 ps: if `sourceID` is not set, `LoginName` will be ignored --- routers/api/v1/admin/user.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 87a5b28fad..be907805d6 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -30,7 +30,7 @@ import ( user_service "code.gitea.io/gitea/services/user" ) -func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64, loginName string) { +func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64) { if sourceID == 0 { return } @@ -47,7 +47,6 @@ func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64 u.LoginType = source.Type u.LoginSource = source.ID - u.LoginName = loginName } // CreateUser create a user @@ -83,12 +82,13 @@ func CreateUser(ctx *context.APIContext) { Passwd: form.Password, MustChangePassword: true, LoginType: auth.Plain, + LoginName: form.LoginName, } if form.MustChangePassword != nil { u.MustChangePassword = *form.MustChangePassword } - parseAuthSource(ctx, u, form.SourceID, form.LoginName) + parseAuthSource(ctx, u, form.SourceID) if ctx.Written() { return } From 6ba0c371c21237376c292ee92ec067b4a1ef1218 Mon Sep 17 00:00:00 2001 From: SimonErm <33630884+SimonErm@users.noreply.github.com> Date: Tue, 16 Apr 2024 07:41:39 +0200 Subject: [PATCH 105/247] Allow `preferred_username` as username source for OIDC (#30454) This PR adds the preferred_username claim as a possible username source for the oauth2_client. Closes #21518 --- custom/conf/app.example.ini | 3 ++- docs/content/administration/config-cheat-sheet.en-us.md | 5 +++-- modules/setting/oauth2.go | 4 +++- routers/web/auth/auth.go | 7 +++++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 918252044b..32b51fd7c6 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1553,8 +1553,9 @@ LEVEL = Info ;; The source of the username for new oauth2 accounts: ;; userid = use the userid / sub attribute ;; nickname = use the nickname attribute +;; preferred_username = use the preferred_username attribute ;; email = use the username part of the email attribute -;; Note: `nickname` and `email` options will normalize input strings using the following criteria: +;; Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria: ;; - diacritics are removed ;; - the characters in the set `['´\x60]` are removed ;; - the characters in the set `[\s~+]` are replaced with `-` diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 9de7511964..ff8bcb066c 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -608,9 +608,10 @@ And the following unique queues: - `ENABLE_AUTO_REGISTRATION`: **false**: Automatically create user accounts for new oauth2 users. - `USERNAME`: **nickname**: The source of the username for new oauth2 accounts: - `userid` - use the userid / sub attribute - - `nickname` - use the nickname attribute + - `nickname` - use the nickname + - `preferred_username` - use the preferred_username - `email` - use the username part of the email attribute - - Note: `nickname` and `email` options will normalize input strings using the following criteria: + - Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria: - diacritics are removed - the characters in the set `['´\x60]` are removed - the characters in the set `[\s~+]` are replaced with `-` diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 830472db32..6930197b22 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -22,11 +22,13 @@ const ( OAuth2UsernameNickname OAuth2UsernameType = "nickname" // OAuth2UsernameEmail username of oauth2 email field will be used as gitea name OAuth2UsernameEmail OAuth2UsernameType = "email" + // OAuth2UsernameEmail username of oauth2 preferred_username field will be used as gitea name + OAuth2UsernamePreferredUsername OAuth2UsernameType = "preferred_username" ) func (username OAuth2UsernameType) isValid() bool { switch username { - case OAuth2UsernameUserid, OAuth2UsernameNickname, OAuth2UsernameEmail: + case OAuth2UsernameUserid, OAuth2UsernameNickname, OAuth2UsernameEmail, OAuth2UsernamePreferredUsername: return true } return false diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 8b5cd986b8..9ef32ebdb1 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -386,6 +386,13 @@ func getUserName(gothUser *goth.User) (string, error) { switch setting.OAuth2Client.Username { case setting.OAuth2UsernameEmail: return user_model.NormalizeUserName(strings.Split(gothUser.Email, "@")[0]) + case setting.OAuth2UsernamePreferredUsername: + preferredUsername, exists := gothUser.RawData["preferred_username"] + if exists { + return user_model.NormalizeUserName(preferredUsername.(string)) + } else { + return "", fmt.Errorf("preferred_username is missing in received user data but configured as username source for user_id %q. Check if OPENID_CONNECT_SCOPES contains profile", gothUser.UserID) + } case setting.OAuth2UsernameNickname: return user_model.NormalizeUserName(gothUser.NickName) default: // OAuth2UsernameUserid From 58b204b813cd3a97db904d889d552e64a7e398ff Mon Sep 17 00:00:00 2001 From: Tobias Balle-Petersen Date: Tue, 16 Apr 2024 08:08:48 +0200 Subject: [PATCH 106/247] Update API to return 'source_id' for users (#29718) Using the API, a user's _source_id_ can be set in the _CreateUserOption_ model, but the field is not returned in the _User_ model. This PR updates the _User_ model to include the field _source_id_ (The ID of the Authentication Source). --- modules/structs/user.go | 2 ++ services/convert/user.go | 1 + templates/swagger/v1_json.tmpl | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/modules/structs/user.go b/modules/structs/user.go index 21ecc1479e..ca6ab79944 100644 --- a/modules/structs/user.go +++ b/modules/structs/user.go @@ -20,6 +20,8 @@ type User struct { // the user's authentication sign-in name. // default: empty LoginName string `json:"login_name"` + // The ID of the user's Authentication Source + SourceID int64 `json:"source_id"` // the user's full name FullName string `json:"full_name"` // swagger:strfmt email diff --git a/services/convert/user.go b/services/convert/user.go index 3521dd2f90..1a2733d91e 100644 --- a/services/convert/user.go +++ b/services/convert/user.go @@ -75,6 +75,7 @@ func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *ap if authed { result.IsAdmin = user.IsAdmin result.LoginName = user.LoginName + result.SourceID = user.LoginSource result.LastLogin = user.LastLoginUnix.AsTime() result.Language = user.Language result.IsActive = user.IsActive diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 254b7daf17..532b8880bc 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -24260,6 +24260,12 @@ "type": "boolean", "x-go-name": "Restricted" }, + "source_id": { + "description": "The ID of the user's Authentication Source", + "type": "integer", + "format": "int64", + "x-go-name": "SourceID" + }, "starred_repos_count": { "type": "integer", "format": "int64", From a658e2f277af435517f022355af697bdf588708e Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 16 Apr 2024 10:52:45 +0200 Subject: [PATCH 107/247] Fix long branch name overflows (#30345) Fixes: https://github.com/go-gitea/gitea/issues/27971 Fixes: https://github.com/go-gitea/gitea/pull/28010 Screenshot 2024-04-09 at 00 19 57 Also fixes a similar issue in issue list where CSS was there but not active because of missing `display: block`. Screenshot 2024-04-09 at 00 18 25 --- templates/repo/branch_dropdown.tmpl | 4 ++-- .../repo/issue/branch_selector_field.tmpl | 6 +++--- templates/repo/issue/view_title.tmpl | 2 +- templates/shared/issuelist.tmpl | 15 ++++++++------ web_src/css/base.css | 2 ++ web_src/css/repo.css | 20 ++++++------------- web_src/css/repo/issue-list.css | 6 ++++-- .../js/components/RepoBranchTagSelector.vue | 4 ++-- 8 files changed, 29 insertions(+), 30 deletions(-) diff --git a/templates/repo/branch_dropdown.tmpl b/templates/repo/branch_dropdown.tmpl index 6c2e08a985..7b39830df8 100644 --- a/templates/repo/branch_dropdown.tmpl +++ b/templates/repo/branch_dropdown.tmpl @@ -71,7 +71,7 @@ {{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}}