Merge branch 'main' into telackey/sort

This commit is contained in:
Thomas E Lackey 2025-03-11 11:33:47 -05:00 committed by GitHub
commit 1216ff96e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
51 changed files with 13833 additions and 25616 deletions

View File

@ -79,18 +79,7 @@ cpu.out
/public/assets/fonts
/public/assets/img/avatar
/vendor
/web_src/fomantic/node_modules
/web_src/fomantic/build/*
!/web_src/fomantic/build/semantic.js
!/web_src/fomantic/build/semantic.css
!/web_src/fomantic/build/themes
/web_src/fomantic/build/themes/*
!/web_src/fomantic/build/themes/default
/web_src/fomantic/build/themes/default/assets/*
!/web_src/fomantic/build/themes/default/assets/fonts
/web_src/fomantic/build/themes/default/assets/fonts/*
!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2
!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2
/web_src/fomantic
/VERSION
/.air
/.go-licenses

2
.gitattributes vendored
View File

@ -5,7 +5,5 @@
/public/assets/img/svg/*.svg linguist-generated
/templates/swagger/v1_json.tmpl linguist-generated
/vendor/** -text -eol linguist-vendored
/web_src/fomantic/build/** linguist-generated
/web_src/fomantic/_site/globals/site.variables linguist-language=Less
/web_src/js/vendor/** -text -eol linguist-vendored
Dockerfile.* linguist-language=Dockerfile

12
.gitignore vendored
View File

@ -84,18 +84,6 @@ cpu.out
/public/assets/fonts
/public/assets/licenses.txt
/vendor
/web_src/fomantic/node_modules
/web_src/fomantic/build/*
!/web_src/fomantic/build/semantic.js
!/web_src/fomantic/build/semantic.css
!/web_src/fomantic/build/themes
/web_src/fomantic/build/themes/*
!/web_src/fomantic/build/themes/default
/web_src/fomantic/build/themes/default/assets/*
!/web_src/fomantic/build/themes/default/assets/fonts
/web_src/fomantic/build/themes/default/assets/fonts/*
!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2
!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2
/VERSION
/.air
/.go-licenses

View File

@ -115,8 +115,6 @@ LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...)
FOMANTIC_WORK_DIR := web_src/fomantic
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
WEBPACK_CONFIGS := webpack.config.js tailwind.config.js
WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css
@ -140,7 +138,7 @@ TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags
TEST_TAGS ?= $(TAGS_SPLIT) sqlite sqlite_unlock_notify
TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMANTIC_WORK_DIR)/node_modules $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) $(GO_LICENSE_TMP_DIR)
TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) $(GO_LICENSE_TMP_DIR)
GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css
@ -847,19 +845,6 @@ update-py: node-check | node_modules ## update py dependencies
poetry install
@touch .venv
.PHONY: fomantic
fomantic: ## build fomantic files
rm -rf $(FOMANTIC_WORK_DIR)/build
cd $(FOMANTIC_WORK_DIR) && npm install --no-save
cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config
cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/
$(SED_INPLACE) -e 's/ overrideBrowserslist\r/ overrideBrowserslist: ["defaults"]\r/g' $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/tasks/config/tasks.js
cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build
# fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event
$(SED_INPLACE) -e 's/clickEvent[ \t]*=/clickEvent = "click", unstableClickEvent =/g' $(FOMANTIC_WORK_DIR)/build/semantic.js
$(SED_INPLACE) -e 's/\r//g' $(FOMANTIC_WORK_DIR)/build/semantic.css $(FOMANTIC_WORK_DIR)/build/semantic.js
rm -f $(FOMANTIC_WORK_DIR)/build/*.min.*
.PHONY: webpack
webpack: $(WEBPACK_DEST) ## build webpack files

View File

@ -194,7 +194,7 @@ func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) err
// CancelPreviousJobs cancels all previous jobs of the same repository, reference, workflow, and event.
// It's useful when a new run is triggered, and all previous runs needn't be continued anymore.
func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) error {
func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) ([]*ActionRunJob, error) {
// Find all runs in the specified repository, reference, and workflow with non-final status
runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{
RepoID: repoID,
@ -204,14 +204,16 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
Status: []Status{StatusRunning, StatusWaiting, StatusBlocked},
})
if err != nil {
return err
return nil, err
}
// If there are no runs found, there's no need to proceed with cancellation, so return nil.
if total == 0 {
return nil
return nil, nil
}
cancelledJobs := make([]*ActionRunJob, 0, total)
// Iterate over each found run and cancel its associated jobs.
for _, run := range runs {
// Find all jobs associated with the current run.
@ -219,7 +221,7 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
RunID: run.ID,
})
if err != nil {
return err
return cancelledJobs, err
}
// Iterate over each job and attempt to cancel it.
@ -238,27 +240,29 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
// Update the job's status and stopped time in the database.
n, err := UpdateRunJob(ctx, job, builder.Eq{"task_id": 0}, "status", "stopped")
if err != nil {
return err
return cancelledJobs, err
}
// If the update affected 0 rows, it means the job has changed in the meantime, so we need to try again.
if n == 0 {
return fmt.Errorf("job has changed, try again")
return cancelledJobs, fmt.Errorf("job has changed, try again")
}
cancelledJobs = append(cancelledJobs, job)
// Continue with the next job.
continue
}
// If the job has an associated task, try to stop the task, effectively cancelling the job.
if err := StopTask(ctx, job.TaskID, StatusCancelled); err != nil {
return err
return cancelledJobs, err
}
cancelledJobs = append(cancelledJobs, job)
}
}
// Return nil to indicate successful cancellation of all running and waiting jobs.
return nil
return cancelledJobs, nil
}
// InsertRun inserts a run

View File

@ -117,21 +117,22 @@ func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error {
return committer.Commit()
}
func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) error {
func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) ([]*ActionRunJob, error) {
// If actions disabled when there is schedule task, this will remove the outdated schedule tasks
// There is no other place we can do this because the app.ini will be changed manually
if err := DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil {
return fmt.Errorf("DeleteCronTaskByRepo: %v", err)
return nil, fmt.Errorf("DeleteCronTaskByRepo: %v", err)
}
// cancel running cron jobs of this repository and delete old schedules
if err := CancelPreviousJobs(
jobs, err := CancelPreviousJobs(
ctx,
repo.ID,
repo.DefaultBranch,
"",
webhook_module.HookEventSchedule,
); err != nil {
return fmt.Errorf("CancelPreviousJobs: %v", err)
)
if err != nil {
return jobs, fmt.Errorf("CancelPreviousJobs: %v", err)
}
return nil
return jobs, nil
}

View File

@ -21,6 +21,7 @@ type materialIconRulesData struct {
FileNames map[string]string `json:"fileNames"`
FolderNames map[string]string `json:"folderNames"`
FileExtensions map[string]string `json:"fileExtensions"`
LanguageIDs map[string]string `json:"languageIds"`
}
type MaterialIconProvider struct {
@ -107,25 +108,40 @@ func (m *MaterialIconProvider) FileIcon(ctx reqctx.RequestContext, entry *git.Tr
return svg.RenderHTML("octicon-file")
}
func (m *MaterialIconProvider) findIconNameWithLangID(s string) string {
if _, ok := m.svgs[s]; ok {
return s
}
if s, ok := m.rules.LanguageIDs[s]; ok {
if _, ok = m.svgs[s]; ok {
return s
}
}
return ""
}
func (m *MaterialIconProvider) FindIconName(name string, isDir bool) string {
iconsData := m.rules
fileNameLower := strings.ToLower(path.Base(name))
if isDir {
if s, ok := iconsData.FolderNames[fileNameLower]; ok {
if s, ok := m.rules.FolderNames[fileNameLower]; ok {
return s
}
return "folder"
}
if s, ok := iconsData.FileNames[fileNameLower]; ok {
return s
if s, ok := m.rules.FileNames[fileNameLower]; ok {
if s = m.findIconNameWithLangID(s); s != "" {
return s
}
}
for i := len(fileNameLower) - 1; i >= 0; i-- {
if fileNameLower[i] == '.' {
ext := fileNameLower[i+1:]
if s, ok := iconsData.FileExtensions[ext]; ok {
return s
if s, ok := m.rules.FileExtensions[ext]; ok {
if s = m.findIconNameWithLangID(s); s != "" {
return s
}
}
}
}

View File

@ -21,4 +21,6 @@ func TestFindIconName(t *testing.T) {
p := fileicon.DefaultMaterialIconProvider()
assert.Equal(t, "php", p.FindIconName("foo.php", false))
assert.Equal(t, "php", p.FindIconName("foo.PHP", false))
assert.Equal(t, "javascript", p.FindIconName("foo.js", false))
assert.Equal(t, "visualstudio", p.FindIconName("foo.vba", false))
}

View File

@ -7038,107 +7038,201 @@
"gnu": "gnuplot",
"yaml-tmlanguage": "yaml",
"tmlanguage": "xml",
"git": "git",
"git-commit": "git",
"git-rebase": "git",
"ignore": "git",
"github-actions-workflow": "github-actions-workflow",
"yaml": "yaml",
"spring-boot-properties-yaml": "yaml",
"ansible": "yaml",
"ansible-jinja": "yaml",
"matlab": "matlab",
"makefile": "settings",
"spring-boot-properties": "settings",
"diff": "diff",
"razor": "razor",
"aspnetcorerazor": "razor",
"python": "python",
"javascript": "javascript",
"typescript": "typescript",
"handlebars": "handlebars",
"perl": "perl",
"perl6": "perl",
"haxe": "haxe",
"hxml": "haxe",
"puppet": "puppet",
"elixir": "elixir",
"livescript": "livescript",
"erlang": "erlang",
"julia": "julia",
"purescript": "purescript",
"stylus": "stylus",
"robotframework": "robot",
"testoutput": "visualstudio",
"solidity": "solidity",
"autoit": "autoit",
"terraform": "terraform",
"cucumber": "cucumber",
"postcss": "postcss",
"lang-cfml": "coldfusion",
"haskell": "haskell",
"ruby": "ruby",
"php": "php",
"hack": "hack",
"javascriptreact": "react",
"processing": "processing",
"django-html": "django",
"django-txt": "django",
"html": "html",
"gdscript": "godot",
"gdresource": "godot-assets",
"viml": "vim",
"prolog": "prolog",
"pawn": "pawn",
"reason": "reason",
"reason_lisp": "reason",
"doctex": "tex",
"latex": "tex",
"latex-expl3": "tex",
"apex": "salesforce",
"dockercompose": "docker",
"shellscript": "console",
"objective-c": "objective-c",
"objective-cpp": "objective-cpp",
"coffeescript": "coffee",
"fsharp": "fsharp",
"editorconfig": "editorconfig",
"cljx": "clojure",
"clojure": "clojure",
"pip-requirements": "python-misc",
"vue-postcss": "vue",
"vue-html": "vue",
"bibtex": "lib",
"bibtex-style": "lib",
"jupyter": "jupyter",
"plaintext": "document",
"powershell": "powershell",
"rsweave": "r",
"rust": "rust",
"ssh_config": "lock",
"typescriptreact": "react_ts",
"search-result": "search",
"rescript": "rescript",
"twee3": "twine",
"twee3-harlowe-3": "twine",
"twee3-chapbook-1": "twine",
"twee3-sugarcube-2": "twine",
"grain": "grain",
"lolcode": "lolcode",
"idris": "idris",
"text-gemini": "gemini",
"wolfram": "wolframlanguage",
"shaderlab": "shader",
"cadence": "cadence",
"stylable": "stylable",
"capnb": "cds",
"cds-markdown-injection": "cds",
"concourse-pipeline-yaml": "concourse",
"concourse-task-yaml": "concourse",
"systemd-conf": "systemd",
"systemd-unit-file": "systemd",
"hosts": "hosts",
"ahk2": "ahk2",
"gnuplot": "gnuplot"
"edn": "clojure",
"cppm": "cpp",
"ccm": "cpp",
"cxxm": "cpp",
"c++m": "cpp",
"ipp": "cpp",
"ixx": "cpp",
"tpp": "cpp",
"txx": "cpp",
"hpp.in": "cpp",
"h.in": "cpp",
"diff": "diff",
"rej": "diff",
"fsscript": "fsharp",
"gitignore_global": "ignore",
"gitignore": "ignore",
"git-blame-ignore-revs": "ignore",
"gvy": "groovy",
"nf": "groovy",
"handlebars": "handlebars",
"hjs": "handlebars",
"hlsli": "hlsl",
"fx": "hlsl",
"fxh": "hlsl",
"vsh": "hlsl",
"psh": "hlsl",
"cginc": "hlsl",
"compute": "hlsl",
"html": "html",
"shtml": "html",
"xht": "html",
"aspx": "html",
"jshtm": "html",
"volt": "html",
"rhtml": "html",
"directory": "properties",
"gitattributes": "properties",
"gitconfig": "properties",
"gitmodules": "properties",
"editorconfig": "properties",
"repo": "properties",
"jav": "java",
"js": "javascript",
"es6": "javascript",
"cjs": "javascript",
"pac": "javascript",
"bowerrc": "json",
"jscsrc": "json",
"webmanifest": "json",
"ts.map": "json",
"har": "json",
"jslintrc": "json",
"jsonld": "json",
"geojson": "json",
"vuerc": "json",
"eslintrc": "jsonc",
"eslintrc.json": "jsonc",
"jsfmtrc": "jsonc",
"jshintrc": "jsonc",
"hintrc": "jsonc",
"babelrc": "jsonc",
"jmd": "juliamarkdown",
"cls": "tex",
"bbx": "tex",
"cbx": "tex",
"ctx": "latex",
"mak": "makefile",
"mkd": "markdown",
"mdwn": "markdown",
"mdown": "markdown",
"markdn": "markdown",
"mdtxt": "markdown",
"mdtext": "markdown",
"workbook": "markdown",
"npmignore": "ignore",
"npmrc": "properties",
"m": "objective-c",
"mm": "objective-cpp",
"pod": "perl",
"t": "perl",
"psgi": "perl",
"rakumod": "raku",
"rakutest": "raku",
"rakudoc": "raku",
"nqp": "raku",
"p6": "raku",
"pl6": "raku",
"pm6": "raku",
"php": "php",
"php4": "php",
"php5": "php",
"phtml": "php",
"ctp": "php",
"psrc": "powershell",
"rpy": "python",
"pyw": "python",
"cpy": "python",
"gyp": "python",
"gypi": "python",
"pyi": "python",
"ipy": "python",
"pyt": "python",
"rhistory": "r",
"rprofile": "r",
"rt": "r",
"razor": "razor",
"rbx": "ruby",
"rjs": "ruby",
"gemspec": "ruby",
"rake": "ruby",
"ru": "ruby",
"podspec": "ruby",
"rbi": "ruby",
"bashrc": "shellscript",
"bash_aliases": "shellscript",
"bash_profile": "shellscript",
"bash_login": "shellscript",
"ebuild": "shellscript",
"eclass": "shellscript",
"profile": "shellscript",
"bash_logout": "shellscript",
"xprofile": "shellscript",
"xsession": "shellscript",
"xsessionrc": "shellscript",
"zshrc": "shellscript",
"zprofile": "shellscript",
"zlogin": "shellscript",
"zlogout": "shellscript",
"zshenv": "shellscript",
"zsh-theme": "shellscript",
"cshrc": "shellscript",
"tcshrc": "shellscript",
"yashrc": "shellscript",
"yash_profile": "shellscript",
"dsql": "sql",
"ts": "typescript",
"cts": "typescript",
"mts": "typescript",
"brs": "vb",
"bas": "vb",
"vba": "vb",
"ascx": "xml",
"atom": "xml",
"axml": "xml",
"axaml": "xml",
"bpmn": "xml",
"csl": "xml",
"csproj.user": "xml",
"dita": "xml",
"ditamap": "xml",
"ent": "xml",
"dtml": "xml",
"fxml": "xml",
"isml": "xml",
"jmx": "xml",
"launch": "xml",
"menu": "xml",
"nuspec": "xml",
"opml": "xml",
"owl": "xml",
"proj": "xml",
"pt": "xml",
"publishsettings": "xml",
"pubxml": "xml",
"pubxml.user": "xml",
"rdf": "xml",
"rng": "xml",
"rss": "xml",
"shproj": "xml",
"storyboard": "xml",
"targets": "xml",
"tld": "xml",
"tmx": "xml",
"vbproj": "xml",
"vbproj.user": "xml",
"wsdl": "xml",
"wxi": "xml",
"wxl": "xml",
"wxs": "xml",
"xbl": "xml",
"xib": "xml",
"xliff": "xml",
"xpdl": "xml",
"xul": "xml",
"xoml": "xml",
"yaml": "yaml",
"yml": "yaml",
"eyaml": "yaml",
"eyml": "yaml",
"cff": "yaml",
"yaml-tmpreferences": "yaml",
"yaml-tmtheme": "yaml",
"winget": "yaml"
},
"fileNames": {
".pug-lintrc": "pug",
@ -9015,7 +9109,11 @@
"caddyfile": "caddy",
"pklproject": "pkl",
"pklproject.deps.json": "pkl",
".github/funding.yml": "github-sponsors"
".github/funding.yml": "github-sponsors",
"language-configuration.json": "jsonc",
"icon-theme.json": "jsonc",
"color-theme.json": "jsonc",
"*.log.?": "log"
},
"languageIds": {
"git": "git",

View File

@ -12,7 +12,6 @@ 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"
@ -1049,7 +1048,7 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
ctx.APIErrorInternal(err)
return err
}
if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil {
if err := actions_service.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)

View File

@ -11,7 +11,6 @@ import (
"strings"
"time"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
@ -906,7 +905,7 @@ func SettingsPost(ctx *context.Context) {
return
}
if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil {
if err := actions_service.CleanRepoScheduleTasks(ctx, repo); err != nil {
log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
}

View File

@ -10,10 +10,12 @@ import (
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
webhook_module "code.gitea.io/gitea/modules/webhook"
)
// StopZombieTasks stops the task which have running status, but haven't been updated for a long time
@ -32,6 +34,24 @@ func StopEndlessTasks(ctx context.Context) error {
})
}
func notifyWorkflowJobStatusUpdate(ctx context.Context, jobs []*actions_model.ActionRunJob) {
if len(jobs) > 0 {
CreateCommitStatus(ctx, jobs...)
}
}
func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) error {
jobs, err := actions_model.CancelPreviousJobs(ctx, repoID, ref, workflowID, event)
notifyWorkflowJobStatusUpdate(ctx, jobs)
return err
}
func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) error {
jobs, err := actions_model.CleanRepoScheduleTasks(ctx, repo)
notifyWorkflowJobStatusUpdate(ctx, jobs)
return err
}
func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error {
tasks, err := db.Find[actions_model.ActionTask](ctx, opts)
if err != nil {
@ -67,7 +87,7 @@ func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error {
remove()
}
CreateCommitStatus(ctx, jobs...)
notifyWorkflowJobStatusUpdate(ctx, jobs)
return nil
}

View File

@ -136,7 +136,7 @@ func notify(ctx context.Context, input *notifyInput) error {
return nil
}
if unit_model.TypeActions.UnitGlobalDisabled() {
if err := actions_model.CleanRepoScheduleTasks(ctx, input.Repo); err != nil {
if err := CleanRepoScheduleTasks(ctx, input.Repo); err != nil {
log.Error("CleanRepoScheduleTasks: %v", err)
}
return nil
@ -341,7 +341,7 @@ func handleWorkflows(
// cancel running jobs if the event is push or pull_request_sync
if run.Event == webhook_module.HookEventPush ||
run.Event == webhook_module.HookEventPullRequestSync {
if err := actions_model.CancelPreviousJobs(
if err := CancelPreviousJobs(
ctx,
run.RepoID,
run.Ref,
@ -472,7 +472,7 @@ func handleSchedules(
log.Error("CountSchedules: %v", err)
return err
} else if count > 0 {
if err := actions_model.CleanRepoScheduleTasks(ctx, input.Repo); err != nil {
if err := CleanRepoScheduleTasks(ctx, input.Repo); err != nil {
log.Error("CleanRepoScheduleTasks: %v", err)
}
}

View File

@ -55,7 +55,7 @@ func startTasks(ctx context.Context) error {
// cancel running jobs if the event is push
if row.Schedule.Event == webhook_module.HookEventPush {
// cancel running jobs of the same workflow
if err := actions_model.CancelPreviousJobs(
if err := CancelPreviousJobs(
ctx,
row.RepoID,
row.Schedule.Ref,

View File

@ -256,7 +256,7 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
}
// cancel running jobs of the same workflow
if err := actions_model.CancelPreviousJobs(
if err := CancelPreviousJobs(
ctx,
run.RepoID,
run.Ref,

View File

@ -30,6 +30,7 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook"
actions_service "code.gitea.io/gitea/services/actions"
notify_service "code.gitea.io/gitea/services/notify"
release_service "code.gitea.io/gitea/services/release"
files_service "code.gitea.io/gitea/services/repository/files"
@ -452,7 +453,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_m
log.Error("DeleteCronTaskByRepo: %v", err)
}
// cancel running cron jobs of this repository and delete old schedules
if err := actions_model.CancelPreviousJobs(
if err := actions_service.CancelPreviousJobs(
ctx,
repo.ID,
from,
@ -639,7 +640,7 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR
log.Error("DeleteCronTaskByRepo: %v", err)
}
// cancel running cron jobs of this repository and delete old schedules
if err := actions_model.CancelPreviousJobs(
if err := actions_service.CancelPreviousJobs(
ctx,
repo.ID,
oldDefaultBranchName,

View File

@ -7,7 +7,6 @@ import (
"context"
"slices"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
@ -29,7 +28,7 @@ func UpdateRepositoryUnits(ctx context.Context, repo *repo_model.Repository, uni
}
if slices.Contains(deleteUnitTypes, unit.TypeActions) {
if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil {
if err := actions_service.CleanRepoScheduleTasks(ctx, repo); err != nil {
log.Error("CleanRepoScheduleTasks: %v", err)
}
}

View File

@ -7,28 +7,28 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/tests"
ap "github.com/go-ap/activitypub"
"github.com/stretchr/testify/assert"
)
func TestActivityPubPerson(t *testing.T) {
setting.Federation.Enabled = true
testWebRoutes = routers.NormalRoutes()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
defer tests.PrepareTestEnv(t)()
defer test.MockVariableValue(&setting.Federation.Enabled, true)()
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
t.Run("ExistingPerson", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
onGiteaRun(t, func(*testing.T, *url.URL) {
userID := 2
username := "user2"
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/user-id/%v", userID))
@ -56,41 +56,18 @@ func TestActivityPubPerson(t *testing.T) {
assert.NotNil(t, pubKeyPem)
assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem)
})
}
func TestActivityPubMissingPerson(t *testing.T) {
setting.Federation.Enabled = true
testWebRoutes = routers.NormalRoutes()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
onGiteaRun(t, func(*testing.T, *url.URL) {
t.Run("MissingPerson", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/api/v1/activitypub/user-id/999999999")
resp := MakeRequest(t, req, http.StatusNotFound)
assert.Contains(t, resp.Body.String(), "user does not exist")
})
}
t.Run("MissingPersonInbox", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
srv := httptest.NewServer(testWebRoutes)
defer srv.Close()
defer test.MockVariableValue(&setting.AppURL, srv.URL+"/")()
func TestActivityPubPersonInbox(t *testing.T) {
setting.Federation.Enabled = true
testWebRoutes = routers.NormalRoutes()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
srv := httptest.NewServer(testWebRoutes)
defer srv.Close()
onGiteaRun(t, func(*testing.T, *url.URL) {
appURL := setting.AppURL
setting.AppURL = srv.URL + "/"
defer func() {
setting.Database.LogSQL = false
setting.AppURL = appURL
}()
username1 := "user1"
ctx := t.Context()
user1, err := user_model.GetUserByName(ctx, username1)

View File

@ -5,7 +5,6 @@ package integration
import (
"net/http"
"net/url"
"strings"
"testing"
@ -19,10 +18,12 @@ import (
)
func TestAPIAdminOrgCreate(t *testing.T) {
onGiteaRun(t, func(*testing.T, *url.URL) {
session := loginUser(t, "user1")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin)
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user1")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin)
t.Run("CreateOrg", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
org := api.CreateOrgOption{
UserName: "user2_org",
FullName: "User2's organization",
@ -51,13 +52,8 @@ func TestAPIAdminOrgCreate(t *testing.T) {
FullName: org.FullName,
})
})
}
func TestAPIAdminOrgCreateBadVisibility(t *testing.T) {
onGiteaRun(t, func(*testing.T, *url.URL) {
session := loginUser(t, "user1")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin)
t.Run("CreateBadVisibility", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
org := api.CreateOrgOption{
UserName: "user2_org",
FullName: "User2's organization",
@ -70,22 +66,21 @@ func TestAPIAdminOrgCreateBadVisibility(t *testing.T) {
AddTokenAuth(token)
MakeRequest(t, req, http.StatusUnprocessableEntity)
})
}
func TestAPIAdminOrgCreateNotAdmin(t *testing.T) {
defer tests.PrepareTestEnv(t)()
nonAdminUsername := "user2"
session := loginUser(t, nonAdminUsername)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
org := api.CreateOrgOption{
UserName: "user2_org",
FullName: "User2's organization",
Description: "This organization created by admin for user2",
Website: "https://try.gitea.io",
Location: "Shanghai",
Visibility: "public",
}
req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs", &org).
AddTokenAuth(token)
MakeRequest(t, req, http.StatusForbidden)
t.Run("CreateNotAdmin", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
nonAdminUsername := "user2"
session := loginUser(t, nonAdminUsername)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
org := api.CreateOrgOption{
UserName: "user2_org",
FullName: "User2's organization",
Description: "This organization created by admin for user2",
Website: "https://try.gitea.io",
Location: "Shanghai",
Visibility: "public",
}
req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs", &org).
AddTokenAuth(token)
MakeRequest(t, req, http.StatusForbidden)
})
}

View File

@ -5,35 +5,31 @@ package integration
import (
"net/http"
"net/url"
"testing"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
func TestNodeinfo(t *testing.T) {
setting.Federation.Enabled = true
testWebRoutes = routers.NormalRoutes()
defer func() {
setting.Federation.Enabled = false
testWebRoutes = routers.NormalRoutes()
}()
defer tests.PrepareTestEnv(t)()
defer test.MockVariableValue(&setting.Federation.Enabled, true)()
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
onGiteaRun(t, func(*testing.T, *url.URL) {
req := NewRequest(t, "GET", "/api/v1/nodeinfo")
resp := MakeRequest(t, req, http.StatusOK)
VerifyJSONSchema(t, resp, "nodeinfo_2.1.json")
req := NewRequest(t, "GET", "/api/v1/nodeinfo")
resp := MakeRequest(t, req, http.StatusOK)
VerifyJSONSchema(t, resp, "nodeinfo_2.1.json")
var nodeinfo api.NodeInfo
DecodeJSON(t, resp, &nodeinfo)
assert.True(t, nodeinfo.OpenRegistrations)
assert.Equal(t, "gitea", nodeinfo.Software.Name)
assert.Equal(t, 29, nodeinfo.Usage.Users.Total)
assert.Equal(t, 22, nodeinfo.Usage.LocalPosts)
assert.Equal(t, 3, nodeinfo.Usage.LocalComments)
})
var nodeinfo api.NodeInfo
DecodeJSON(t, resp, &nodeinfo)
assert.True(t, nodeinfo.OpenRegistrations)
assert.Equal(t, "gitea", nodeinfo.Software.Name)
assert.Equal(t, 29, nodeinfo.Usage.Users.Total)
assert.Equal(t, 22, nodeinfo.Usage.LocalPosts)
assert.Equal(t, 3, nodeinfo.Usage.LocalComments)
}

View File

@ -4,7 +4,6 @@
package integration
import (
"net/url"
"strings"
"testing"
@ -14,15 +13,17 @@ import (
"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 TestOrgCounts(t *testing.T) {
onGiteaRun(t, testOrgCounts)
defer tests.PrepareTestEnv(t)()
testOrgCounts(t)
}
func testOrgCounts(t *testing.T, u *url.URL) {
func testOrgCounts(t *testing.T) {
orgOwner := "user2"
orgName := "testOrg"
orgCollaborator := "user4"

View File

@ -8,12 +8,15 @@ import (
"testing"
pull_service "code.gitea.io/gitea/services/pull"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestListPullCommits(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user5")
req := NewRequest(t, "GET", "/user2/repo1/pulls/3/commits/list")
resp := session.MakeRequest(t, req, http.StatusOK)
@ -30,6 +33,7 @@ func TestListPullCommits(t *testing.T) {
assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", pullCommitList.LastReviewCommitSha)
t.Run("CommitBlobExcerpt", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req = NewRequest(t, "GET", "/user2/repo1/blob_excerpt/985f0301dba5e7b34be866819cd15ad3d8f508ee?last_left=0&last_right=0&left=2&right=2&left_hunk_size=2&right_hunk_size=2&path=README.md&style=split&direction=up")
resp = session.MakeRequest(t, req, http.StatusOK)
assert.Contains(t, resp.Body.String(), `<td class="lines-code lines-code-new"><code class="code-inner"># repo1</code>`)

View File

@ -10,78 +10,77 @@ import (
"io"
"mime/multipart"
"net/http"
"net/url"
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/avatar"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
func TestUserAvatar(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org
defer tests.PrepareTestEnv(t)()
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org
seed := user2.Email
if len(seed) == 0 {
seed = user2.Name
}
seed := user2.Email
if len(seed) == 0 {
seed = user2.Name
}
img, err := avatar.RandomImage([]byte(seed))
if err != nil {
assert.NoError(t, err)
return
}
img, err := avatar.RandomImage([]byte(seed))
if err != nil {
assert.NoError(t, err)
return
}
session := loginUser(t, "user2")
csrf := GetUserCSRFToken(t, session)
session := loginUser(t, "user2")
csrf := GetUserCSRFToken(t, session)
imgData := &bytes.Buffer{}
imgData := &bytes.Buffer{}
body := &bytes.Buffer{}
body := &bytes.Buffer{}
// Setup multi-part
writer := multipart.NewWriter(body)
writer.WriteField("source", "local")
part, err := writer.CreateFormFile("avatar", "avatar-for-testuseravatar.png")
if err != nil {
assert.NoError(t, err)
return
}
// Setup multi-part
writer := multipart.NewWriter(body)
writer.WriteField("source", "local")
part, err := writer.CreateFormFile("avatar", "avatar-for-testuseravatar.png")
if err != nil {
assert.NoError(t, err)
return
}
if err := png.Encode(imgData, img); err != nil {
assert.NoError(t, err)
return
}
if err := png.Encode(imgData, img); err != nil {
assert.NoError(t, err)
return
}
if _, err := io.Copy(part, imgData); err != nil {
assert.NoError(t, err)
return
}
if _, err := io.Copy(part, imgData); err != nil {
assert.NoError(t, err)
return
}
if err := writer.Close(); err != nil {
assert.NoError(t, err)
return
}
if err := writer.Close(); err != nil {
assert.NoError(t, err)
return
}
req := NewRequestWithBody(t, "POST", "/user/settings/avatar", body)
req.Header.Add("X-Csrf-Token", csrf)
req.Header.Add("Content-Type", writer.FormDataContentType())
req := NewRequestWithBody(t, "POST", "/user/settings/avatar", body)
req.Header.Add("X-Csrf-Token", csrf)
req.Header.Add("Content-Type", writer.FormDataContentType())
session.MakeRequest(t, req, http.StatusSeeOther)
session.MakeRequest(t, req, http.StatusSeeOther)
user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org
user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org
req = NewRequest(t, "GET", user2.AvatarLinkWithSize(db.DefaultContext, 0))
_ = session.MakeRequest(t, req, http.StatusOK)
req = NewRequest(t, "GET", user2.AvatarLinkWithSize(db.DefaultContext, 0))
_ = session.MakeRequest(t, req, http.StatusOK)
testGetAvatarRedirect(t, user2)
testGetAvatarRedirect(t, user2)
// Can't test if the response matches because the image is re-generated on upload but checking that this at least doesn't give a 404 should be enough.
})
// Can't test if the response matches because the image is re-generated on upload but checking that this at least doesn't give a 404 should be enough.
}
func testGetAvatarRedirect(t *testing.T, user *user_model.User) {

View File

@ -0,0 +1,570 @@
{
"pkg:bat": {
"bat": [
".bat",
".cmd"
]
},
"pkg:clojure": {
"clojure": [
".clj",
".cljs",
".cljc",
".cljx",
".clojure",
".edn"
]
},
"pkg:coffeescript": {
"coffeescript": [
".coffee",
".cson",
".iced"
]
},
"pkg:configuration-editing": {
"jsonc": [
".code-workspace",
"language-configuration.json",
"icon-theme.json",
"color-theme.json"
],
"json": [
".code-profile"
]
},
"pkg:cpp": {
"c": [
".c",
".i"
],
"cpp": [
".cpp",
".cppm",
".cc",
".ccm",
".cxx",
".cxxm",
".c++",
".c++m",
".hpp",
".hh",
".hxx",
".h++",
".h",
".ii",
".ino",
".inl",
".ipp",
".ixx",
".tpp",
".txx",
".hpp.in",
".h.in"
],
"cuda-cpp": [
".cu",
".cuh"
]
},
"pkg:csharp": {
"csharp": [
".cs",
".csx",
".cake"
]
},
"pkg:css": {
"css": [
".css"
]
},
"pkg:dart": {
"dart": [
".dart"
]
},
"pkg:diff": {
"diff": [
".diff",
".patch",
".rej"
]
},
"pkg:docker": {
"dockerfile": [
".dockerfile",
".containerfile"
]
},
"pkg:fsharp": {
"fsharp": [
".fs",
".fsi",
".fsx",
".fsscript"
]
},
"pkg:git-base": {
"ignore": [
".gitignore_global",
".gitignore",
".git-blame-ignore-revs"
]
},
"pkg:go": {
"go": [
".go"
]
},
"pkg:groovy": {
"groovy": [
".groovy",
".gvy",
".gradle",
".jenkinsfile",
".nf"
]
},
"pkg:handlebars": {
"handlebars": [
".handlebars",
".hbs",
".hjs"
]
},
"pkg:hlsl": {
"hlsl": [
".hlsl",
".hlsli",
".fx",
".fxh",
".vsh",
".psh",
".cginc",
".compute"
]
},
"pkg:html": {
"html": [
".html",
".htm",
".shtml",
".xhtml",
".xht",
".mdoc",
".jsp",
".asp",
".aspx",
".jshtm",
".volt",
".ejs",
".rhtml"
]
},
"pkg:ini": {
"ini": [
".ini"
],
"properties": [
".conf",
".properties",
".cfg",
".directory",
".gitattributes",
".gitconfig",
".gitmodules",
".editorconfig",
".repo"
]
},
"pkg:java": {
"java": [
".java",
".jav"
]
},
"pkg:javascript": {
"javascriptreact": [
".jsx"
],
"javascript": [
".js",
".es6",
".mjs",
".cjs",
".pac"
]
},
"pkg:json": {
"json": [
".json",
".bowerrc",
".jscsrc",
".webmanifest",
".js.map",
".css.map",
".ts.map",
".har",
".jslintrc",
".jsonld",
".geojson",
".ipynb",
".vuerc"
],
"jsonc": [
".jsonc",
".eslintrc",
".eslintrc.json",
".jsfmtrc",
".jshintrc",
".swcrc",
".hintrc",
".babelrc"
],
"jsonl": [
".jsonl",
".ndjson"
],
"snippets": [
".code-snippets"
]
},
"pkg:julia": {
"julia": [
".jl"
],
"juliamarkdown": [
".jmd"
]
},
"pkg:latex": {
"tex": [
".sty",
".cls",
".bbx",
".cbx"
],
"latex": [
".tex",
".ltx",
".ctx"
],
"bibtex": [
".bib"
]
},
"pkg:less": {
"less": [
".less"
]
},
"pkg:log": {
"log": [
".log",
"*.log.?"
]
},
"pkg:lua": {
"lua": [
".lua"
]
},
"pkg:make": {
"makefile": [
".mak",
".mk"
]
},
"pkg:markdown-basics": {
"markdown": [
".md",
".mkd",
".mdwn",
".mdown",
".markdown",
".markdn",
".mdtxt",
".mdtext",
".workbook"
]
},
"pkg:ms-vscode.js-debug": {
"wat": [
".wat",
".wasm"
]
},
"pkg:npm": {
"ignore": [
".npmignore"
],
"properties": [
".npmrc"
]
},
"pkg:objective-c": {
"objective-c": [
".m"
],
"objective-cpp": [
".mm"
]
},
"pkg:perl": {
"perl": [
".pl",
".pm",
".pod",
".t",
".PL",
".psgi"
],
"raku": [
".raku",
".rakumod",
".rakutest",
".rakudoc",
".nqp",
".p6",
".pl6",
".pm6"
]
},
"pkg:php": {
"php": [
".php",
".php4",
".php5",
".phtml",
".ctp"
]
},
"pkg:powershell": {
"powershell": [
".ps1",
".psm1",
".psd1",
".pssc",
".psrc"
]
},
"pkg:pug": {
"jade": [
".pug",
".jade"
]
},
"pkg:python": {
"python": [
".py",
".rpy",
".pyw",
".cpy",
".gyp",
".gypi",
".pyi",
".ipy",
".pyt"
]
},
"pkg:r": {
"r": [
".r",
".rhistory",
".rprofile",
".rt"
]
},
"pkg:razor": {
"razor": [
".cshtml",
".razor"
]
},
"pkg:restructuredtext": {
"restructuredtext": [
".rst"
]
},
"pkg:ruby": {
"ruby": [
".rb",
".rbx",
".rjs",
".gemspec",
".rake",
".ru",
".erb",
".podspec",
".rbi"
]
},
"pkg:rust": {
"rust": [
".rs"
]
},
"pkg:scss": {
"scss": [
".scss"
]
},
"pkg:search-result": {
"search-result": [
".code-search"
]
},
"pkg:shaderlab": {
"shaderlab": [
".shader"
]
},
"pkg:shellscript": {
"shellscript": [
".sh",
".bash",
".bashrc",
".bash_aliases",
".bash_profile",
".bash_login",
".ebuild",
".eclass",
".profile",
".bash_logout",
".xprofile",
".xsession",
".xsessionrc",
".Xsession",
".zsh",
".zshrc",
".zprofile",
".zlogin",
".zlogout",
".zshenv",
".zsh-theme",
".fish",
".ksh",
".csh",
".cshrc",
".tcshrc",
".yashrc",
".yash_profile"
]
},
"pkg:sql": {
"sql": [
".sql",
".dsql"
]
},
"pkg:swift": {
"swift": [
".swift"
]
},
"pkg:typescript-basics": {
"typescript": [
".ts",
".cts",
".mts"
],
"typescriptreact": [
".tsx"
],
"json": [
".tsbuildinfo"
]
},
"pkg:vb": {
"vb": [
".vb",
".brs",
".vbs",
".bas",
".vba"
]
},
"pkg:xml": {
"xml": [
".xml",
".xsd",
".ascx",
".atom",
".axml",
".axaml",
".bpmn",
".cpt",
".csl",
".csproj",
".csproj.user",
".dita",
".ditamap",
".dtd",
".ent",
".mod",
".dtml",
".fsproj",
".fxml",
".iml",
".isml",
".jmx",
".launch",
".menu",
".mxml",
".nuspec",
".opml",
".owl",
".proj",
".props",
".pt",
".publishsettings",
".pubxml",
".pubxml.user",
".rbxlx",
".rbxmx",
".rdf",
".rng",
".rss",
".shproj",
".storyboard",
".svg",
".targets",
".tld",
".tmx",
".vbproj",
".vbproj.user",
".vcxproj",
".vcxproj.filters",
".wsdl",
".wxi",
".wxl",
".wxs",
".xaml",
".xbl",
".xib",
".xlf",
".xliff",
".xpdl",
".xul",
".xoml"
],
"xsl": [
".xsl",
".xslt"
]
},
"pkg:yaml": {
"yaml": [
".yaml",
".yml",
".eyaml",
".eyml",
".cff",
".yaml-tmlanguage",
".yaml-tmpreferences",
".yaml-tmtheme",
".winget"
]
}
}

View File

@ -63,17 +63,32 @@ async function processMaterialFileIcons() {
}
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-svgs.json`, import.meta.url)), JSON.stringify(svgSymbols, null, 2));
const vscodeExtensionsJson = await readFile(fileURLToPath(new URL(`generate-svg-vscode-extensions.json`, import.meta.url)));
const vscodeExtensions = JSON.parse(vscodeExtensionsJson);
const iconRulesJson = await readFile(fileURLToPath(new URL(`../node_modules/material-icon-theme/dist/material-icons.json`, import.meta.url)));
const iconRules = JSON.parse(iconRulesJson);
// The rules are from VSCode material-icon-theme, we need to adjust them to our needs
// 1. We only use lowercase filenames to match (it should be good enough for most cases and more efficient)
// 2. We do not have a "Language ID" system: https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers
// * So we just treat the "Language ID" as file extension, it is not always true, but it is good enough for most cases.
// 2. We do not have a "Language ID" system:
// * https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers
// * https://github.com/microsoft/vscode/tree/1.98.0/extensions
delete iconRules.iconDefinitions;
for (const [k, v] of Object.entries(iconRules.fileNames)) iconRules.fileNames[k.toLowerCase()] = v;
for (const [k, v] of Object.entries(iconRules.folderNames)) iconRules.folderNames[k.toLowerCase()] = v;
for (const [k, v] of Object.entries(iconRules.fileExtensions)) iconRules.fileExtensions[k.toLowerCase()] = v;
for (const [k, v] of Object.entries(iconRules.languageIds)) iconRules.fileExtensions[k.toLowerCase()] = v;
// Use VSCode's "Language ID" mapping from its extensions
for (const [_, langIdExtMap] of Object.entries(vscodeExtensions)) {
for (const [langId, names] of Object.entries(langIdExtMap)) {
for (const name of names) {
const nameLower = name.toLowerCase();
if (nameLower[0] === '.') {
iconRules.fileExtensions[nameLower.substring(1)] ??= langId;
} else {
iconRules.fileNames[nameLower] ??= langId;
}
}
}
}
const iconRulesPretty = JSON.stringify(iconRules, null, 2);
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-rules.json`, import.meta.url)), iconRulesPretty);
}

View File

@ -273,6 +273,10 @@ textarea:focus,
width: 50%;
}
.ui.form.left-right-form .inline.field .ui.dropdown input.search {
width: 100%;
}
.ui.form.left-right-form .inline.field .inline-right {
display: inline-flex;
flex-direction: column;

View File

@ -18,6 +18,7 @@
@import "./modules/checkbox.css";
@import "./modules/dimmer.css";
@import "./modules/modal.css";
@import "./modules/tab.css";
@import "./modules/tippy.css";
@import "./modules/breadcrumb.css";

View File

@ -0,0 +1,7 @@
.ui.tab {
display: none;
}
.ui.tab.active {
display: block;
}

View File

@ -1,7 +0,0 @@
audit=false
fund=false
update-notifier=false
package-lock=true
save-exact=true
lockfile-version=3
optional=false

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,703 @@
/*!
* # Fomantic-UI - Modal
* http://github.com/fomantic/Fomantic-UI/
*
*
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
/*******************************
Modal
*******************************/
.ui.modal {
position: absolute;
display: none;
z-index: 1001;
text-align: left;
background: #FFFFFF;
border: none;
box-shadow: 1px 3px 3px 0 rgba(0, 0, 0, 0.2), 1px 3px 15px 2px rgba(0, 0, 0, 0.2);
transform-origin: 50% 25%;
flex: 0 0 auto;
border-radius: 0.28571429rem;
-webkit-user-select: text;
-moz-user-select: text;
user-select: text;
will-change: top, left, margin, transform, opacity;
}
.ui.modal > :first-child:not(.icon):not(.dimmer),
.ui.modal > i.icon:first-child + *,
.ui.modal > .dimmer:first-child + *:not(.icon),
.ui.modal > .dimmer:first-child + i.icon + * {
border-top-left-radius: 0.28571429rem;
border-top-right-radius: 0.28571429rem;
}
.ui.modal > :last-child {
border-bottom-left-radius: 0.28571429rem;
border-bottom-right-radius: 0.28571429rem;
}
.ui.modal > .ui.dimmer {
border-radius: inherit;
}
/*******************************
Content
*******************************/
/*--------------
Close
---------------*/
.ui.modal > .close {
cursor: pointer;
position: absolute;
top: -2.5rem;
right: -2.5rem;
z-index: 1;
opacity: 0.8;
font-size: 1.25em;
color: #FFFFFF;
width: 2.25rem;
height: 2.25rem;
padding: 0.625rem 0 0 0;
}
.ui.modal > .close:hover {
opacity: 1;
}
/*--------------
Header
---------------*/
.ui.modal > .header {
display: block;
font-family: var(--fonts-regular);
background: #FFFFFF;
margin: 0;
padding: 1.25rem 1.5rem;
box-shadow: none;
color: rgba(0, 0, 0, 0.85);
border-bottom: 1px solid rgba(34, 36, 38, 0.15);
}
.ui.modal > .header:not(.ui) {
font-size: 1.42857143rem;
line-height: 1.28571429em;
font-weight: 500;
}
/*--------------
Content
---------------*/
.ui.modal > .content {
display: block;
width: 100%;
font-size: 1em;
line-height: 1.4;
padding: 1.5rem;
background: #FFFFFF;
}
.ui.modal > .image.content {
display: flex;
flex-direction: row;
}
/* Image */
.ui.modal > .content > .image {
display: block;
flex: 0 1 auto;
width: '';
align-self: start;
max-width: 100%;
}
.ui.modal > [class*="top aligned"] {
align-self: start;
}
.ui.modal > [class*="middle aligned"] {
align-self: center;
}
.ui.modal > [class*="stretched"] {
align-self: stretch;
}
/* Description */
.ui.modal > .content > .description {
display: block;
flex: 1 0 auto;
min-width: 0;
align-self: start;
}
.ui.modal > .content > i.icon + .description,
.ui.modal > .content > .image + .description {
flex: 0 1 auto;
min-width: '';
width: auto;
padding-left: 2em;
}
/*rtl:ignore*/
.ui.modal > .content > .image > i.icon {
margin: 0;
opacity: 1;
width: auto;
line-height: 1;
font-size: 8rem;
}
/*--------------
Actions
---------------*/
.ui.modal > .actions {
background: #F9FAFB;
padding: 1rem 1rem;
border-top: 1px solid rgba(34, 36, 38, 0.15);
text-align: right;
}
.ui.modal .actions > .button:not(.fluid) {
margin-left: 0.75em;
}
.ui.basic.modal > .actions {
border-top: none;
}
/*-------------------
Responsive
--------------------*/
/* Modal Width */
@media only screen and (max-width: 767.98px) {
.ui.modal:not(.fullscreen) {
width: 95%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 768px) {
.ui.modal:not(.fullscreen) {
width: 88%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 992px) {
.ui.modal:not(.fullscreen) {
width: 850px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1200px) {
.ui.modal:not(.fullscreen) {
width: 900px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1920px) {
.ui.modal:not(.fullscreen) {
width: 950px;
margin: 0 0 0 0;
}
}
/* Tablet and Mobile */
@media only screen and (max-width: 991.98px) {
.ui.modal > .header {
padding-right: 2.25rem;
}
.ui.modal > .close {
top: 1.0535rem;
right: 1rem;
color: rgba(0, 0, 0, 0.87);
}
}
/* Mobile */
@media only screen and (max-width: 767.98px) {
.ui.modal > .header {
padding: 0.75rem 1rem !important;
padding-right: 2.25rem !important;
}
.ui.overlay.fullscreen.modal > .content.content.content {
min-height: calc(100vh - 8.1rem);
}
.ui.overlay.fullscreen.modal > .scrolling.content.content.content {
max-height: calc(100vh - 8.1rem);
}
.ui.modal > .content {
display: block;
padding: 1rem !important;
}
.ui.modal > .close {
top: 0.5rem !important;
right: 0.5rem !important;
}
/*rtl:ignore*/
.ui.modal .image.content {
flex-direction: column;
}
.ui.modal > .content > .image {
display: block;
max-width: 100%;
margin: 0 auto !important;
text-align: center;
padding: 0 0 1rem !important;
}
.ui.modal > .content > .image > i.icon {
font-size: 5rem;
text-align: center;
}
/*rtl:ignore*/
.ui.modal > .content > .description {
display: block;
width: 100% !important;
margin: 0 !important;
padding: 1rem 0 !important;
box-shadow: none;
}
/* Let Buttons Stack */
.ui.modal > .actions {
padding: 1rem 1rem 0rem !important;
}
.ui.modal .actions > .buttons,
.ui.modal .actions > .button {
margin-bottom: 1rem;
}
}
/*--------------
Coupling
---------------*/
.ui.inverted.dimmer > .ui.modal {
box-shadow: 1px 3px 10px 2px rgba(0, 0, 0, 0.2);
}
/*******************************
Types
*******************************/
.ui.basic.modal {
background-color: transparent;
border: none;
border-radius: 0;
box-shadow: none !important;
color: #FFFFFF;
}
.ui.basic.modal > .header,
.ui.basic.modal > .content,
.ui.basic.modal > .actions {
background-color: transparent;
}
.ui.basic.modal > .header {
color: #FFFFFF;
border-bottom: none;
}
.ui.basic.modal > .close {
top: 1rem;
right: 1.5rem;
color: #FFFFFF;
}
.ui.inverted.dimmer > .basic.modal {
color: rgba(0, 0, 0, 0.87);
}
.ui.inverted.dimmer > .ui.basic.modal > .header {
color: rgba(0, 0, 0, 0.85);
}
/* Resort to margin positioning if legacy */
.ui.legacy.legacy.modal,
.ui.legacy.legacy.page.dimmer > .ui.modal {
left: 50% !important;
}
.ui.legacy.legacy.modal:not(.aligned),
.ui.legacy.legacy.page.dimmer > .ui.modal:not(.aligned) {
top: 50%;
}
.ui.legacy.legacy.page.dimmer > .ui.scrolling.modal:not(.aligned),
.ui.page.dimmer > .ui.scrolling.legacy.legacy.modal:not(.aligned),
.ui.top.aligned.legacy.legacy.page.dimmer > .ui.modal:not(.aligned),
.ui.top.aligned.dimmer > .ui.legacy.legacy.modal:not(.aligned) {
top: auto;
}
.ui.legacy.overlay.fullscreen.modal {
margin-top: -2rem !important;
}
/*******************************
States
*******************************/
.ui.loading.modal {
display: block;
visibility: hidden;
z-index: -1;
}
.ui.active.modal {
display: block;
}
/*******************************
Variations
*******************************/
/*--------------
Aligned
---------------*/
.modals.dimmer .ui.top.aligned.modal {
top: 5vh;
}
.modals.dimmer .ui.bottom.aligned.modal {
bottom: 5vh;
}
@media only screen and (max-width: 767.98px) {
.modals.dimmer .ui.top.aligned.modal {
top: 1rem;
}
.modals.dimmer .ui.bottom.aligned.modal {
bottom: 1rem;
}
}
/*--------------
Scrolling
---------------*/
/* Scrolling Dimmer */
.scrolling.dimmable.dimmed {
overflow: hidden;
}
.scrolling.dimmable > .dimmer {
justify-content: flex-start;
position: fixed;
}
.scrolling.dimmable.dimmed > .dimmer {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.modals.dimmer .ui.scrolling.modal:not(.fullscreen) {
margin: 2rem auto;
}
/* Fix for Firefox, Edge, IE11 */
.modals.dimmer .ui.scrolling.modal:not([class*="overlay fullscreen"])::after {
content: '\00A0';
position: absolute;
height: 2rem;
}
/* Undetached Scrolling */
.scrolling.undetached.dimmable.dimmed {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.scrolling.undetached.dimmable.dimmed > .dimmer {
overflow: hidden;
}
.scrolling.undetached.dimmable .ui.scrolling.modal:not(.fullscreen) {
position: absolute;
left: 50%;
}
/* Scrolling Content */
.ui.modal > .scrolling.content {
max-height: calc(80vh - 10rem);
overflow: auto;
}
.ui.overlay.fullscreen.modal > .content {
min-height: calc(100vh - 9.1rem);
}
.ui.overlay.fullscreen.modal > .scrolling.content {
max-height: calc(100vh - 9.1rem);
}
/*--------------
Full Screen
---------------*/
.ui.fullscreen.modal {
width: 95%;
left: 2.5%;
margin: 1em auto;
}
.ui.overlay.fullscreen.modal {
width: 100%;
left: 0;
margin: 0 auto;
top: 0;
border-radius: 0;
}
.ui.modal > .close.inside + .header,
.ui.fullscreen.modal > .header {
padding-right: 2.25rem;
}
.ui.modal > .close.inside,
.ui.fullscreen.modal > .close {
top: 1.0535rem;
right: 1rem;
color: rgba(0, 0, 0, 0.87);
}
.ui.basic.fullscreen.modal > .close {
color: #FFFFFF;
}
/*--------------
Size
---------------*/
.ui.modal {
font-size: 1rem;
}
.ui.mini.modal > .header:not(.ui) {
font-size: 1.3em;
}
@media only screen and (max-width: 767.98px) {
.ui.mini.modal {
width: 95%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 768px) {
.ui.mini.modal {
width: 35.2%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 992px) {
.ui.mini.modal {
width: 340px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1200px) {
.ui.mini.modal {
width: 360px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1920px) {
.ui.mini.modal {
width: 380px;
margin: 0 0 0 0;
}
}
.ui.tiny.modal > .header:not(.ui) {
font-size: 1.3em;
}
@media only screen and (max-width: 767.98px) {
.ui.tiny.modal {
width: 95%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 768px) {
.ui.tiny.modal {
width: 52.8%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 992px) {
.ui.tiny.modal {
width: 510px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1200px) {
.ui.tiny.modal {
width: 540px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1920px) {
.ui.tiny.modal {
width: 570px;
margin: 0 0 0 0;
}
}
.ui.small.modal > .header:not(.ui) {
font-size: 1.3em;
}
@media only screen and (max-width: 767.98px) {
.ui.small.modal {
width: 95%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 768px) {
.ui.small.modal {
width: 70.4%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 992px) {
.ui.small.modal {
width: 680px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1200px) {
.ui.small.modal {
width: 720px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1920px) {
.ui.small.modal {
width: 760px;
margin: 0 0 0 0;
}
}
.ui.large.modal > .header:not(.ui) {
font-size: 1.6em;
}
@media only screen and (max-width: 767.98px) {
.ui.large.modal {
width: 95%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 768px) {
.ui.large.modal {
width: 88%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 992px) {
.ui.large.modal {
width: 1020px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1200px) {
.ui.large.modal {
width: 1080px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1920px) {
.ui.large.modal {
width: 1140px;
margin: 0 0 0 0;
}
}
.ui.big.modal > .header:not(.ui) {
font-size: 1.6em;
}
@media only screen and (max-width: 767.98px) {
.ui.big.modal {
width: 95%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 768px) {
.ui.big.modal {
width: 88%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 992px) {
.ui.big.modal {
width: 1190px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1200px) {
.ui.big.modal {
width: 1260px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1920px) {
.ui.big.modal {
width: 1330px;
margin: 0 0 0 0;
}
}
.ui.huge.modal > .header:not(.ui) {
font-size: 1.6em;
}
@media only screen and (max-width: 767.98px) {
.ui.huge.modal {
width: 95%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 768px) {
.ui.huge.modal {
width: 88%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 992px) {
.ui.huge.modal {
width: 1360px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1200px) {
.ui.huge.modal {
width: 1440px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1920px) {
.ui.huge.modal {
width: 1520px;
margin: 0 0 0 0;
}
}
.ui.massive.modal > .header:not(.ui) {
font-size: 1.8em;
}
@media only screen and (max-width: 767.98px) {
.ui.massive.modal {
width: 95%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 768px) {
.ui.massive.modal {
width: 88%;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 992px) {
.ui.massive.modal {
width: 1530px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1200px) {
.ui.massive.modal {
width: 1620px;
margin: 0 0 0 0;
}
}
@media only screen and (min-width: 1920px) {
.ui.massive.modal {
width: 1710px;
margin: 0 0 0 0;
}
}
/*******************************
Theme Overrides
*******************************/
/*******************************
Site Overrides
*******************************/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,520 @@
/*!
* # Fomantic-UI - Search
* http://github.com/fomantic/Fomantic-UI/
*
*
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
*/
/*******************************
Search
*******************************/
.ui.search {
position: relative;
}
.ui.search > .prompt {
margin: 0;
outline: none;
-webkit-appearance: none;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
text-shadow: none;
font-style: normal;
font-weight: normal;
line-height: 1.21428571em;
padding: 0.67857143em 1em;
font-size: 1em;
background: #FFFFFF;
border: 1px solid rgba(34, 36, 38, 0.15);
color: rgba(0, 0, 0, 0.87);
box-shadow: 0 0 0 0 transparent inset;
transition: background-color 0.1s ease, color 0.1s ease, box-shadow 0.1s ease, border-color 0.1s ease;
}
.ui.search .prompt {
border-radius: 500rem;
}
/*--------------
Icon
---------------*/
.ui.search .prompt ~ .search.icon {
cursor: pointer;
}
/*--------------
Results
---------------*/
.ui.search > .results {
display: none;
position: absolute;
top: 100%;
left: 0;
transform-origin: center top;
white-space: normal;
text-align: left;
text-transform: none;
background: #FFFFFF;
margin-top: 0.5em;
width: 18em;
border-radius: 0.28571429rem;
box-shadow: 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
border: 1px solid #D4D4D5;
z-index: 998;
}
.ui.search > .results > :first-child {
border-radius: 0.28571429rem 0.28571429rem 0 0;
}
.ui.search > .results > :last-child {
border-radius: 0 0 0.28571429rem 0.28571429rem;
}
/*--------------
Result
---------------*/
.ui.search > .results .result {
cursor: pointer;
display: block;
overflow: hidden;
font-size: 1em;
padding: 0.85714286em 1.14285714em;
color: rgba(0, 0, 0, 0.87);
line-height: 1.33;
border-bottom: 1px solid rgba(34, 36, 38, 0.1);
}
.ui.search > .results .result:last-child {
border-bottom: none !important;
}
/* Image */
.ui.search > .results .result .image {
float: right;
overflow: hidden;
background: none;
width: 5em;
height: 3em;
border-radius: 0.25em;
}
.ui.search > .results .result .image img {
display: block;
width: auto;
height: 100%;
}
/*--------------
Info
---------------*/
.ui.search > .results .result .image + .content {
margin: 0 6em 0 0;
}
.ui.search > .results .result .title {
margin: -0.14285714em 0 0;
font-family: var(--fonts-regular);
font-weight: 500;
font-size: 1em;
color: rgba(0, 0, 0, 0.85);
}
.ui.search > .results .result .description {
margin-top: 0;
font-size: 0.92857143em;
color: rgba(0, 0, 0, 0.4);
}
.ui.search > .results .result .price {
float: right;
color: #21BA45;
}
/*--------------
Message
---------------*/
.ui.search > .results > .message {
padding: 1em 1em;
}
.ui.search > .results > .message .header {
font-family: var(--fonts-regular);
font-size: 1rem;
font-weight: 500;
color: rgba(0, 0, 0, 0.87);
}
.ui.search > .results > .message .description {
margin-top: 0.25rem;
font-size: 1em;
color: rgba(0, 0, 0, 0.87);
}
/* View All Results */
.ui.search > .results > .action {
display: block;
border-top: none;
background: #F3F4F5;
padding: 0.92857143em 1em;
color: rgba(0, 0, 0, 0.87);
font-weight: 500;
text-align: center;
}
/*******************************
States
*******************************/
/*--------------------
Focus
---------------------*/
.ui.search > .prompt:focus {
border-color: rgba(34, 36, 38, 0.35);
background: #FFFFFF;
color: rgba(0, 0, 0, 0.95);
}
/*--------------------
Loading
---------------------*/
.ui.loading.search .input > i.icon: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.1);
}
.ui.loading.search .input > i.icon:after {
position: absolute;
content: '';
top: 50%;
left: 50%;
margin: -0.64285714em 0 0 -0.64285714em;
width: 1.28571429em;
height: 1.28571429em;
animation: loader 0.6s infinite linear;
border: 0.2em solid #767676;
border-radius: 500rem;
box-shadow: 0 0 0 1px transparent;
}
/*--------------
Hover
---------------*/
.ui.search > .results .result:hover,
.ui.category.search > .results .category .result:hover {
background: #F9FAFB;
}
.ui.search .action:hover:not(div) {
background: #E0E0E0;
}
/*--------------
Active
---------------*/
.ui.category.search > .results .category.active {
background: #F3F4F5;
}
.ui.category.search > .results .category.active > .name {
color: rgba(0, 0, 0, 0.87);
}
.ui.search > .results .result.active,
.ui.category.search > .results .category .result.active {
position: relative;
border-left-color: rgba(34, 36, 38, 0.1);
background: #F3F4F5;
box-shadow: none;
}
.ui.search > .results .result.active .title {
color: rgba(0, 0, 0, 0.85);
}
.ui.search > .results .result.active .description {
color: rgba(0, 0, 0, 0.85);
}
/*--------------------
Disabled
----------------------*/
/* Disabled */
.ui.disabled.search {
cursor: default;
pointer-events: none;
opacity: var(--opacity-disabled);
}
/*******************************
Types
*******************************/
/*--------------
Selection
---------------*/
.ui.search.selection .prompt {
border-radius: 0.28571429rem;
}
/* Remove input */
.ui.search.selection > .icon.input > .remove.icon {
pointer-events: none;
position: absolute;
left: auto;
opacity: 0;
color: '';
top: 0;
right: 0;
transition: color 0.1s ease, opacity 0.1s ease;
}
.ui.search.selection > .icon.input > .active.remove.icon {
cursor: pointer;
opacity: 0.8;
pointer-events: auto;
}
.ui.search.selection > .icon.input:not([class*="left icon"]) > .icon ~ .remove.icon {
right: 1.85714em;
}
.ui.search.selection > .icon.input > .remove.icon:hover {
opacity: 1;
color: #DB2828;
}
/*--------------
Category
---------------*/
.ui.category.search .results {
width: 28em;
}
.ui.category.search .results.animating,
.ui.category.search .results.visible {
display: table;
}
/* Category */
.ui.category.search > .results .category {
display: table-row;
background: #F3F4F5;
box-shadow: none;
transition: background 0.1s ease, border-color 0.1s ease;
}
/* Last Category */
.ui.category.search > .results .category:last-child {
border-bottom: none;
}
/* First / Last */
.ui.category.search > .results .category:first-child .name + .result {
border-radius: 0 0.28571429rem 0 0;
}
.ui.category.search > .results .category:last-child .result:last-child {
border-radius: 0 0 0.28571429rem 0;
}
/* Category Result Name */
.ui.category.search > .results .category > .name {
display: table-cell;
text-overflow: ellipsis;
width: 100px;
white-space: nowrap;
background: transparent;
font-family: var(--fonts-regular);
font-size: 1em;
padding: 0.4em 1em;
font-weight: 500;
color: rgba(0, 0, 0, 0.4);
border-bottom: 1px solid rgba(34, 36, 38, 0.1);
}
/* Category Result */
.ui.category.search > .results .category .results {
display: table-cell;
background: #FFFFFF;
border-left: 1px solid rgba(34, 36, 38, 0.15);
border-bottom: 1px solid rgba(34, 36, 38, 0.1);
}
.ui.category.search > .results .category .result {
border-bottom: 1px solid rgba(34, 36, 38, 0.1);
transition: background 0.1s ease, border-color 0.1s ease;
padding: 0.85714286em 1.14285714em;
}
/*******************************
Variations
*******************************/
/*-------------------
Scrolling
--------------------*/
.ui.scrolling.search > .results,
.ui.search.long > .results,
.ui.search.short > .results {
overflow-x: hidden;
overflow-y: auto;
backface-visibility: hidden;
-webkit-overflow-scrolling: touch;
}
@media only screen and (max-width: 767.98px) {
.ui.scrolling.search > .results {
max-height: 12.17714286em;
}
}
@media only screen and (min-width: 768px) {
.ui.scrolling.search > .results {
max-height: 18.26571429em;
}
}
@media only screen and (min-width: 992px) {
.ui.scrolling.search > .results {
max-height: 24.35428571em;
}
}
@media only screen and (min-width: 1920px) {
.ui.scrolling.search > .results {
max-height: 36.53142857em;
}
}
@media only screen and (max-width: 767.98px) {
.ui.search.short > .results {
max-height: 12.17714286em;
}
.ui.search[class*="very short"] > .results {
max-height: 9.13285714em;
}
.ui.search.long > .results {
max-height: 24.35428571em;
}
.ui.search[class*="very long"] > .results {
max-height: 36.53142857em;
}
}
@media only screen and (min-width: 768px) {
.ui.search.short > .results {
max-height: 18.26571429em;
}
.ui.search[class*="very short"] > .results {
max-height: 13.69928571em;
}
.ui.search.long > .results {
max-height: 36.53142857em;
}
.ui.search[class*="very long"] > .results {
max-height: 54.79714286em;
}
}
@media only screen and (min-width: 992px) {
.ui.search.short > .results {
max-height: 24.35428571em;
}
.ui.search[class*="very short"] > .results {
max-height: 18.26571429em;
}
.ui.search.long > .results {
max-height: 48.70857143em;
}
.ui.search[class*="very long"] > .results {
max-height: 73.06285714em;
}
}
@media only screen and (min-width: 1920px) {
.ui.search.short > .results {
max-height: 36.53142857em;
}
.ui.search[class*="very short"] > .results {
max-height: 27.39857143em;
}
.ui.search.long > .results {
max-height: 73.06285714em;
}
.ui.search[class*="very long"] > .results {
max-height: 109.59428571em;
}
}
/*-------------------
Left / Right
--------------------*/
.ui[class*="left aligned"].search > .results {
right: auto;
left: 0;
}
.ui[class*="right aligned"].search > .results {
right: 0;
left: auto;
}
/*--------------
Fluid
---------------*/
.ui.fluid.search .results {
width: 100%;
}
/*--------------
Sizes
---------------*/
.ui.search {
font-size: 1em;
}
.ui.mini.search {
font-size: 0.78571429em;
}
.ui.tiny.search {
font-size: 0.85714286em;
}
.ui.small.search {
font-size: 0.92857143em;
}
.ui.large.search {
font-size: 1.14285714em;
}
.ui.big.search {
font-size: 1.28571429em;
}
.ui.huge.search {
font-size: 1.42857143em;
}
.ui.massive.search {
font-size: 1.71428571em;
}
/*--------------
Mobile
---------------*/
@media only screen and (max-width: 767.98px) {
.ui.search .results {
max-width: calc(100vw - 2rem);
}
}
/*******************************
Theme Overrides
*******************************/
/*******************************
Site Overrides
*******************************/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
@import "./components/dropdown.css";
@import "./components/form.css";
@import "./components/modal.css";
@import "./components/search.css";

View File

@ -0,0 +1,10 @@
import './components/api.js';
import './components/dropdown.js';
import './components/modal.js';
import './components/search.js';
// Hard forked from Fomantic 2.8.7
// TODO: need to apply the patch from Makefile
// # fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event
// $(SED_INPLACE) -e 's/clickEvent[ \t]*=/clickEvent = "click", unstableClickEvent =/g' $(FOMANTIC_WORK_DIR)/build/semantic.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
{
"dependencies": {
"fomantic-ui": "2.8.7"
}
}

View File

@ -1,21 +1,4 @@
/*
████████╗██╗ ██╗███████╗███╗ ███╗███████╗███████╗
╚══██╔══╝██║ ██║██╔════╝████╗ ████║██╔════╝██╔════╝
██║ ███████║█████╗ ██╔████╔██║█████╗ ███████╗
██║ ██╔══██║██╔══╝ ██║╚██╔╝██║██╔══╝ ╚════██║
██║ ██║ ██║███████╗██║ ╚═╝ ██║███████╗███████║
╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝
*/
/*******************************
Theme Selection
*******************************/
/* To override a theme for an individual element
specify theme name below
*/
/* To override a theme for an individual element, specify theme name below */
/* Global */
@site : 'default';

View File

@ -77,7 +77,7 @@ export function initGlobalDropdown() {
}
export function initGlobalTabularMenu() {
fomanticQuery('.ui.menu.tabular:not(.custom) .item').tab({autoTabActivation: false});
fomanticQuery('.ui.menu.tabular:not(.custom) .item').tab();
}
// for performance considerations, it only uses performant syntax

View File

@ -75,7 +75,7 @@ class ImageDiff {
this.containerEl = containerEl;
containerEl.setAttribute('data-image-diff-loaded', 'true');
fomanticQuery(containerEl).find('.ui.menu.tabular .item').tab({autoTabActivation: false});
fomanticQuery(containerEl).find('.ui.menu.tabular .item').tab();
// the container may be hidden by "viewed" checkbox, so use the parent's width for reference
this.diffContainerWidth = Math.max(containerEl.closest('.diff-file-box').clientWidth - 300, 100);

View File

@ -7,14 +7,13 @@ import {initAriaModalPatch} from './fomantic/modal.ts';
import {initFomanticTransition} from './fomantic/transition.ts';
import {initFomanticDimmer} from './fomantic/dimmer.ts';
import {svg} from '../svg.ts';
import {initFomanticTab} from './fomantic/tab.ts';
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
export function initGiteaFomantic() {
// our extensions
$.fn.fomanticExt = {};
// Silence fomantic's error logging when tabs are used without a target content element
$.fn.tab.settings.silent = true;
// By default, use "exact match" for full text search
$.fn.dropdown.settings.fullTextSearch = 'exact';
// Do not use "cursor: pointer" for dropdown labels
@ -27,6 +26,7 @@ export function initGiteaFomantic() {
initFomanticTransition();
initFomanticDimmer();
initFomanticTab();
initFomanticApiPatch();
// Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future.

View File

@ -0,0 +1,19 @@
import $ from 'jquery';
import {queryElemSiblings} from '../../utils/dom.ts';
export function initFomanticTab() {
$.fn.tab = function (this: any) {
for (const elBtn of this) {
const tabName = elBtn.getAttribute('data-tab');
if (!tabName) continue;
elBtn.addEventListener('click', () => {
const elTab = document.querySelector(`.ui.tab[data-tab="${tabName}"]`);
queryElemSiblings(elTab, `.ui.tab`, (el) => el.classList.remove('active'));
queryElemSiblings(elBtn, `[data-tab]`, (el) => el.classList.remove('active'));
elBtn.classList.add('active');
elTab.classList.add('active');
});
}
return this;
};
}

View File

@ -77,10 +77,10 @@ export default {
entry: {
index: [
fileURLToPath(new URL('web_src/js/globals.ts', import.meta.url)),
fileURLToPath(new URL('web_src/fomantic/build/semantic.js', import.meta.url)),
fileURLToPath(new URL('web_src/fomantic/build/fomantic.js', import.meta.url)),
fileURLToPath(new URL('web_src/js/index.ts', import.meta.url)),
fileURLToPath(new URL('node_modules/easymde/dist/easymde.min.css', import.meta.url)),
fileURLToPath(new URL('web_src/fomantic/build/semantic.css', import.meta.url)),
fileURLToPath(new URL('web_src/fomantic/build/fomantic.css', import.meta.url)),
fileURLToPath(new URL('web_src/css/index.css', import.meta.url)),
],
webcomponents: [