mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-14 10:57:54 +02:00
Merge remote-tracking branch 'upstream/main' into ci-phase2-push
# Conflicts: # templates/base/head_navbar_icons.tmpl
This commit is contained in:
commit
0af095a419
@ -198,10 +198,11 @@ Here's how to run the test suite:
|
||||
|
||||
- E2E test environment variables
|
||||
|
||||
| Variable | Description |
|
||||
| :------------------------ | :---------------------------------------------------------------- |
|
||||
| ``GITEA_TEST_E2E_DEBUG`` | When set, show Gitea server output |
|
||||
| ``GITEA_TEST_E2E_FLAGS`` | Additional flags passed to Playwright, for example ``--ui`` |
|
||||
| Variable | Description |
|
||||
| :-------------------------------- | :---------------------------------------------------------- |
|
||||
| ``GITEA_TEST_E2E_DEBUG`` | When set, show Gitea server output |
|
||||
| ``GITEA_TEST_E2E_FLAGS`` | Additional flags passed to Playwright, for example ``--ui`` |
|
||||
| ``GITEA_TEST_E2E_TIMEOUT_FACTOR`` | Timeout multiplier (default: 3 on CI, 1 locally) |
|
||||
|
||||
## Translation
|
||||
|
||||
|
||||
63
Makefile
63
Makefile
@ -15,7 +15,7 @@ XGO_VERSION := go-1.25.x
|
||||
AIR_PACKAGE ?= github.com/air-verse/air@v1
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.9.2
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.2
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4
|
||||
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15
|
||||
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1
|
||||
@ -81,15 +81,6 @@ STORED_VERSION_FILE := VERSION
|
||||
GITHUB_REF_TYPE ?= branch
|
||||
GITHUB_REF_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
# Enable typescript support in Node.js before 22.18
|
||||
# TODO: Remove this once we can raise the minimum Node.js version to 22.18 (alpine >= 3.23)
|
||||
NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v 2>/dev/null | cut -c2- | sed 's/-.*//' | tr '.' ' '))
|
||||
ifeq ($(shell test "$(NODE_VERSION)" -lt "022018000"; echo $$?),0)
|
||||
NODE_VARS := NODE_OPTIONS="--experimental-strip-types"
|
||||
else
|
||||
NODE_VARS :=
|
||||
endif
|
||||
|
||||
ifneq ($(GITHUB_REF_TYPE),branch)
|
||||
VERSION ?= $(subst v,,$(GITHUB_REF_NAME))
|
||||
GITEA_VERSION ?= $(VERSION)
|
||||
@ -124,6 +115,7 @@ FRONTEND_SOURCES := $(shell find web_src/js web_src/css -type f)
|
||||
FRONTEND_CONFIGS := vite.config.ts tailwind.config.ts
|
||||
FRONTEND_DEST := public/assets/.vite/manifest.json
|
||||
FRONTEND_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts public/assets/.vite
|
||||
FRONTEND_DEV_LOG_LEVEL ?= warn
|
||||
|
||||
BINDATA_DEST_WILDCARD := modules/migration/bindata.* modules/public/bindata.* modules/options/bindata.* modules/templates/bindata.*
|
||||
|
||||
@ -293,33 +285,33 @@ lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backen
|
||||
|
||||
.PHONY: lint-js
|
||||
lint-js: node_modules ## lint js and ts files
|
||||
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY) $(ESLINT_FILES)
|
||||
$(NODE_VARS) pnpm exec vue-tsc
|
||||
pnpm exec eslint --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY) $(ESLINT_FILES)
|
||||
pnpm exec vue-tsc
|
||||
|
||||
.PHONY: lint-js-fix
|
||||
lint-js-fix: node_modules ## lint js and ts files and fix issues
|
||||
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY) $(ESLINT_FILES) --fix
|
||||
$(NODE_VARS) pnpm exec vue-tsc
|
||||
pnpm exec eslint --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY) $(ESLINT_FILES) --fix
|
||||
pnpm exec vue-tsc
|
||||
|
||||
.PHONY: lint-css
|
||||
lint-css: node_modules ## lint css files
|
||||
$(NODE_VARS) pnpm exec stylelint --color --max-warnings=0 $(STYLELINT_FILES)
|
||||
pnpm exec stylelint --color --max-warnings=0 $(STYLELINT_FILES)
|
||||
|
||||
.PHONY: lint-css-fix
|
||||
lint-css-fix: node_modules ## lint css files and fix issues
|
||||
$(NODE_VARS) pnpm exec stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix
|
||||
pnpm exec stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix
|
||||
|
||||
.PHONY: lint-swagger
|
||||
lint-swagger: node_modules ## lint swagger files
|
||||
$(NODE_VARS) pnpm exec spectral lint -q -F hint $(SWAGGER_SPEC)
|
||||
pnpm exec spectral lint -q -F hint $(SWAGGER_SPEC)
|
||||
|
||||
.PHONY: lint-md
|
||||
lint-md: node_modules ## lint markdown files
|
||||
$(NODE_VARS) pnpm exec markdownlint *.md
|
||||
pnpm exec markdownlint *.md
|
||||
|
||||
.PHONY: lint-md-fix
|
||||
lint-md-fix: node_modules ## lint markdown files and fix issues
|
||||
$(NODE_VARS) pnpm exec markdownlint --fix *.md
|
||||
pnpm exec markdownlint --fix *.md
|
||||
|
||||
.PHONY: lint-spell
|
||||
lint-spell: ## lint spelling
|
||||
@ -369,11 +361,11 @@ lint-yaml: .venv ## lint yaml files
|
||||
|
||||
.PHONY: lint-json
|
||||
lint-json: node_modules ## lint json files
|
||||
$(NODE_VARS) pnpm exec eslint -c eslint.json.config.ts --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY)
|
||||
pnpm exec eslint -c eslint.json.config.ts --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY)
|
||||
|
||||
.PHONY: lint-json-fix
|
||||
lint-json-fix: node_modules ## lint and fix json files
|
||||
$(NODE_VARS) pnpm exec eslint -c eslint.json.config.ts --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY) --fix
|
||||
pnpm exec eslint -c eslint.json.config.ts --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY) --fix
|
||||
|
||||
.PHONY: watch
|
||||
watch: ## watch everything and continuously rebuild
|
||||
@ -381,7 +373,7 @@ watch: ## watch everything and continuously rebuild
|
||||
|
||||
.PHONY: watch-frontend
|
||||
watch-frontend: node_modules ## start vite dev server for frontend
|
||||
NODE_ENV=development $(NODE_VARS) pnpm exec vite
|
||||
NODE_ENV=development pnpm exec vite --logLevel $(FRONTEND_DEV_LOG_LEVEL)
|
||||
|
||||
.PHONY: watch-backend
|
||||
watch-backend: ## watch backend files and continuously rebuild
|
||||
@ -397,7 +389,7 @@ test-backend: ## test backend files
|
||||
|
||||
.PHONY: test-frontend
|
||||
test-frontend: node_modules ## test frontend files
|
||||
$(NODE_VARS) pnpm exec vitest
|
||||
pnpm exec vitest
|
||||
|
||||
.PHONY: test-check
|
||||
test-check:
|
||||
@ -533,7 +525,7 @@ test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test
|
||||
.PHONY: playwright
|
||||
playwright: deps-frontend
|
||||
@# on GitHub Actions VMs, playwright's system deps are pre-installed
|
||||
@$(NODE_VARS) pnpm exec playwright install $(if $(GITHUB_ACTIONS),,--with-deps) chromium $(if $(CI),firefox) $(PLAYWRIGHT_FLAGS)
|
||||
@pnpm exec playwright install $(if $(GITHUB_ACTIONS),,--with-deps) chromium $(if $(CI),firefox) $(PLAYWRIGHT_FLAGS)
|
||||
|
||||
.PHONY: test-e2e
|
||||
test-e2e: playwright $(EXECUTABLE_E2E)
|
||||
@ -749,7 +741,7 @@ deps-tools: ## install tool dependencies
|
||||
wait
|
||||
|
||||
node_modules: pnpm-lock.yaml
|
||||
$(NODE_VARS) pnpm install --frozen-lockfile
|
||||
pnpm install --frozen-lockfile
|
||||
@touch node_modules
|
||||
|
||||
.venv: uv.lock
|
||||
@ -757,20 +749,25 @@ node_modules: pnpm-lock.yaml
|
||||
@touch .venv
|
||||
|
||||
.PHONY: update
|
||||
update: update-js update-py ## update js and py dependencies
|
||||
update: update-go update-js update-py ## update dependencies
|
||||
|
||||
.PHONY: update-go
|
||||
update-go: ## update go dependencies
|
||||
$(GO) get -u ./...
|
||||
$(MAKE) tidy
|
||||
|
||||
.PHONY: update-js
|
||||
update-js: node_modules ## update js dependencies
|
||||
$(NODE_VARS) pnpm exec updates -u -f package.json
|
||||
pnpm exec updates -u -f package.json
|
||||
rm -rf node_modules pnpm-lock.yaml
|
||||
$(NODE_VARS) pnpm install
|
||||
$(NODE_VARS) pnpm exec nolyfill install
|
||||
$(NODE_VARS) pnpm install
|
||||
pnpm install
|
||||
pnpm exec nolyfill install
|
||||
pnpm install
|
||||
@touch node_modules
|
||||
|
||||
.PHONY: update-py
|
||||
update-py: node_modules ## update py dependencies
|
||||
$(NODE_VARS) pnpm exec updates -u -f pyproject.toml
|
||||
pnpm exec updates -u -f pyproject.toml
|
||||
rm -rf .venv uv.lock
|
||||
uv sync
|
||||
@touch .venv
|
||||
@ -782,7 +779,7 @@ $(FRONTEND_DEST): $(FRONTEND_SOURCES) $(FRONTEND_CONFIGS) pnpm-lock.yaml
|
||||
@$(MAKE) -s node_modules
|
||||
@rm -rf $(FRONTEND_DEST_ENTRIES)
|
||||
@echo "Running vite build..."
|
||||
@$(NODE_VARS) pnpm exec vite build
|
||||
@pnpm exec vite build
|
||||
@touch $(FRONTEND_DEST)
|
||||
|
||||
.PHONY: svg
|
||||
@ -802,7 +799,7 @@ svg-check: svg
|
||||
|
||||
.PHONY: lockfile-check
|
||||
lockfile-check:
|
||||
$(NODE_VARS) pnpm install --frozen-lockfile
|
||||
pnpm install --frozen-lockfile
|
||||
@diff=$$(git diff --color=always pnpm-lock.yaml); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "pnpm-lock.yaml is inconsistent with package.json"; \
|
||||
|
||||
71
assets/go-licenses.json
generated
71
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
@ -16,7 +16,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-github/v74/github"
|
||||
"github.com/google/go-github/v84/github"
|
||||
"github.com/urfave/cli/v3"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@ -329,7 +329,7 @@ export default defineConfig([
|
||||
'github/no-innerText': [2],
|
||||
'github/no-then': [2],
|
||||
'github/no-useless-passive': [2],
|
||||
'github/prefer-observers': [2],
|
||||
'github/prefer-observers': [0],
|
||||
'github/require-passive-events': [2],
|
||||
'github/unescaped-html-literal': [2],
|
||||
'grouped-accessor-pairs': [2],
|
||||
@ -766,6 +766,7 @@ export default defineConfig([
|
||||
'unicorn/catch-error-name': [0],
|
||||
'unicorn/consistent-destructuring': [2],
|
||||
'unicorn/consistent-empty-array-spread': [2],
|
||||
'unicorn/consistent-template-literal-escape': [2],
|
||||
'unicorn/consistent-existence-index-check': [0],
|
||||
'unicorn/consistent-function-scoping': [0],
|
||||
'unicorn/custom-error-definition': [0],
|
||||
@ -821,6 +822,7 @@ export default defineConfig([
|
||||
'unicorn/no-unused-properties': [2],
|
||||
'unicorn/no-useless-collection-argument': [2],
|
||||
'unicorn/no-useless-fallback-in-spread': [2],
|
||||
'unicorn/no-useless-iterator-to-array': [2],
|
||||
'unicorn/no-useless-length-check': [2],
|
||||
'unicorn/no-useless-promise-resolve-reject': [2],
|
||||
'unicorn/no-useless-spread': [2],
|
||||
@ -870,6 +872,7 @@ export default defineConfig([
|
||||
'unicorn/prefer-response-static-json': [2],
|
||||
'unicorn/prefer-set-has': [0],
|
||||
'unicorn/prefer-set-size': [2],
|
||||
'unicorn/prefer-simple-condition-first': [0],
|
||||
'unicorn/prefer-spread': [0],
|
||||
'unicorn/prefer-string-raw': [0],
|
||||
'unicorn/prefer-string-replace-all': [0],
|
||||
@ -888,6 +891,7 @@ export default defineConfig([
|
||||
'unicorn/require-post-message-target-origin': [0],
|
||||
'unicorn/string-content': [0],
|
||||
'unicorn/switch-case-braces': [0],
|
||||
'unicorn/switch-case-break-position': [2],
|
||||
'unicorn/template-indent': [2],
|
||||
'unicorn/text-encoding-identifier-case': [0],
|
||||
'unicorn/throw-new-error': [2],
|
||||
@ -1013,7 +1017,7 @@ export default defineConfig([
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*', 'tools/**/*'],
|
||||
files: ['*', 'tools/**/*', 'tests/**/*'],
|
||||
languageOptions: {globals: globals.nodeBuiltin},
|
||||
},
|
||||
{
|
||||
|
||||
217
go.mod
217
go.mod
@ -9,7 +9,7 @@ godebug x509negativeserial=1
|
||||
|
||||
require (
|
||||
code.gitea.io/actions-proto-go v0.4.1
|
||||
code.gitea.io/sdk/gitea v0.23.2
|
||||
code.gitea.io/sdk/gitea v0.24.1
|
||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
||||
connectrpc.com/connect v1.19.1
|
||||
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed
|
||||
@ -18,22 +18,22 @@ require (
|
||||
gitea.com/go-chi/session v0.0.0-20251124165456-68e0254e989e
|
||||
gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
|
||||
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4
|
||||
github.com/42wim/httpsig v1.2.3
|
||||
github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920
|
||||
github.com/42wim/httpsig v1.2.4
|
||||
github.com/42wim/sshsig v0.0.0-20260317195500-b9f38cf0d432
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||
github.com/ProtonMail/go-crypto v1.3.0
|
||||
github.com/PuerkitoBio/goquery v1.11.0
|
||||
github.com/Azure/go-ntlmssp v0.1.0
|
||||
github.com/ProtonMail/go-crypto v1.4.1
|
||||
github.com/PuerkitoBio/goquery v1.12.0
|
||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0
|
||||
github.com/alecthomas/chroma/v2 v2.23.1
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.7
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.8
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.13
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||
github.com/blevesearch/bleve/v2 v2.5.7
|
||||
github.com/bohde/codel v0.2.0
|
||||
github.com/buildkite/terminal-to-html/v3 v3.16.8
|
||||
github.com/caddyserver/certmagic v0.25.1
|
||||
github.com/caddyserver/certmagic v0.25.2
|
||||
github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20251013092601-6327009efd21
|
||||
github.com/chi-middleware/proxy v1.1.1
|
||||
github.com/coder/websocket v1.8.14
|
||||
@ -50,42 +50,42 @@ require (
|
||||
github.com/gliderlabs/ssh v0.3.8
|
||||
github.com/go-chi/chi/v5 v5.2.5
|
||||
github.com/go-chi/cors v1.2.2
|
||||
github.com/go-co-op/gocron v1.37.0
|
||||
github.com/go-enry/go-enry/v2 v2.9.4
|
||||
github.com/go-git/go-billy/v5 v5.7.0
|
||||
github.com/go-git/go-git/v5 v5.16.5
|
||||
github.com/go-ldap/ldap/v3 v3.4.12
|
||||
github.com/go-redsync/redsync/v4 v4.15.0
|
||||
github.com/go-co-op/gocron/v2 v2.19.1
|
||||
github.com/go-enry/go-enry/v2 v2.9.5
|
||||
github.com/go-git/go-billy/v5 v5.8.0
|
||||
github.com/go-git/go-git/v5 v5.17.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.13
|
||||
github.com/go-redsync/redsync/v4 v4.16.0
|
||||
github.com/go-sql-driver/mysql v1.9.3
|
||||
github.com/go-webauthn/webauthn v0.13.4
|
||||
github.com/goccy/go-json v0.10.5
|
||||
github.com/go-webauthn/webauthn v0.16.1
|
||||
github.com/goccy/go-json v0.10.6
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/google/go-github/v74 v74.0.0
|
||||
github.com/google/go-github/v84 v84.0.0
|
||||
github.com/google/licenseclassifier/v2 v2.0.0
|
||||
github.com/google/pprof v0.0.0-20260202012954-cb029daf43ef
|
||||
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/feeds v1.2.0
|
||||
github.com/gorilla/sessions v1.4.0
|
||||
github.com/hashicorp/go-version v1.8.0
|
||||
github.com/hashicorp/go-version v1.9.0
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||
github.com/huandu/xstrings v1.5.0
|
||||
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056
|
||||
github.com/jhillyerd/enmime v1.3.0
|
||||
github.com/jhillyerd/enmime/v2 v2.3.0
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/klauspost/compress v1.18.3
|
||||
github.com/klauspost/compress v1.18.5
|
||||
github.com/klauspost/cpuid/v2 v2.3.0
|
||||
github.com/lib/pq v1.11.1
|
||||
github.com/lib/pq v1.12.1
|
||||
github.com/markbates/goth v1.82.0
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/mattn/go-sqlite3 v1.14.33
|
||||
github.com/meilisearch/meilisearch-go v0.36.0
|
||||
github.com/mattn/go-sqlite3 v1.14.38
|
||||
github.com/meilisearch/meilisearch-go v0.36.1
|
||||
github.com/mholt/archives v0.1.5
|
||||
github.com/microcosm-cc/bluemonday v1.0.27
|
||||
github.com/microsoft/go-mssqldb v1.9.6
|
||||
github.com/minio/minio-go/v7 v7.0.98
|
||||
github.com/msteinert/pam v1.2.0
|
||||
github.com/minio/minio-go/v7 v7.0.99
|
||||
github.com/msteinert/pam/v2 v2.1.0
|
||||
github.com/nektos/act v0.2.63
|
||||
github.com/niklasfasching/go-org v1.9.1
|
||||
github.com/olivere/elastic/v7 v7.0.32
|
||||
@ -94,38 +94,38 @@ require (
|
||||
github.com/pquerna/otp v1.5.0
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/quasoft/websspi v1.1.2
|
||||
github.com/redis/go-redis/v9 v9.17.3
|
||||
github.com/redis/go-redis/v9 v9.18.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
|
||||
github.com/sassoftware/go-rpmutils v0.4.0
|
||||
github.com/sergi/go-diff v1.4.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/tstranex/u2f v1.0.0
|
||||
github.com/ulikunitz/xz v0.5.15
|
||||
github.com/urfave/cli-docs/v3 v3.0.0-alpha6
|
||||
github.com/urfave/cli-docs/v3 v3.1.0
|
||||
github.com/urfave/cli/v3 v3.4.1
|
||||
github.com/wneessen/go-mail v0.7.2
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
github.com/yohcop/openid-go v1.0.1
|
||||
github.com/yuin/goldmark v1.7.16
|
||||
github.com/yuin/goldmark v1.8.2
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
gitlab.com/gitlab-org/api/client-go v0.142.4
|
||||
gitlab.com/gitlab-org/api/client-go v1.46.0
|
||||
go.yaml.in/yaml/v4 v4.0.0-rc.3
|
||||
golang.org/x/crypto v0.47.0
|
||||
golang.org/x/image v0.35.0
|
||||
golang.org/x/net v0.49.0
|
||||
golang.org/x/oauth2 v0.34.0
|
||||
golang.org/x/sync v0.19.0
|
||||
golang.org/x/sys v0.40.0
|
||||
golang.org/x/text v0.33.0
|
||||
google.golang.org/grpc v1.78.0
|
||||
golang.org/x/crypto v0.49.0
|
||||
golang.org/x/image v0.38.0
|
||||
golang.org/x/net v0.52.0
|
||||
golang.org/x/oauth2 v0.36.0
|
||||
golang.org/x/sync v0.20.0
|
||||
golang.org/x/sys v0.42.0
|
||||
golang.org/x/text v0.35.0
|
||||
google.golang.org/grpc v1.79.3
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/ini.v1 v1.67.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
mvdan.cc/xurls/v2 v2.6.0
|
||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
||||
strk.kbt.io/projects/go/libravatar v0.0.0-20260301104140-add494e31dab
|
||||
xorm.io/builder v0.3.13
|
||||
xorm.io/xorm v1.3.11
|
||||
)
|
||||
@ -134,75 +134,78 @@ require (
|
||||
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
||||
code.gitea.io/gitea-vet v0.2.3 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
|
||||
github.com/DataDog/zstd v1.5.7 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/RoaringBitmap/roaring/v2 v2.10.0 // indirect
|
||||
github.com/RoaringBitmap/roaring/v2 v2.16.0 // indirect
|
||||
github.com/STARRY-S/zip v0.2.3 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/andybalholm/brotli v1.2.1 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
|
||||
github.com/aws/smithy-go v1.24.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect
|
||||
github.com/aws/smithy-go v1.24.2 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.24.0 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.2.11 // indirect
|
||||
github.com/blevesearch/geo v0.2.4 // indirect
|
||||
github.com/blevesearch/go-faiss v1.0.26 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.24.4 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.3.7 // indirect
|
||||
github.com/blevesearch/geo v0.2.5 // indirect
|
||||
github.com/blevesearch/go-faiss v1.0.30 // indirect
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||
github.com/blevesearch/gtreap v0.1.1 // indirect
|
||||
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.13 // indirect
|
||||
github.com/blevesearch/mmap-go v1.2.0 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.4.5 // indirect
|
||||
github.com/blevesearch/segment v0.9.1 // indirect
|
||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
||||
github.com/blevesearch/vellum v1.1.0 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.4.2 // indirect
|
||||
github.com/blevesearch/zapx/v16 v16.2.8 // indirect
|
||||
github.com/blevesearch/vellum v1.2.0 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.4.3 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.4.3 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.4.3 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.4.3 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.4.3 // indirect
|
||||
github.com/blevesearch/zapx/v16 v16.3.2 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
|
||||
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.6.1 // indirect
|
||||
github.com/bodgit/windows v1.0.1 // indirect
|
||||
github.com/boombuler/barcode v1.1.0 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect
|
||||
github.com/caddyserver/zerossl v0.1.4 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.5 // indirect
|
||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||
github.com/cloudflare/circl v1.6.3 // indirect
|
||||
github.com/couchbase/go-couchbase v0.1.1 // indirect
|
||||
github.com/couchbase/gomemcached v0.3.3 // indirect
|
||||
github.com/couchbase/goutils v0.1.2 // indirect
|
||||
github.com/couchbase/gomemcached v0.3.4 // indirect
|
||||
github.com/couchbase/goutils v0.3.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/davidmz/go-pageant v1.0.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/fatih/color v1.19.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.1 // indirect
|
||||
github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||
github.com/go-enry/go-oniguruma v1.2.1 // indirect
|
||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-webauthn/x v0.1.24 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||
github.com/go-webauthn/x v0.2.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/flatbuffers v25.2.10+incompatible // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/go-tpm v0.9.5 // indirect
|
||||
github.com/google/flatbuffers v25.12.19+incompatible // indirect
|
||||
github.com/google/go-querystring v1.2.0 // indirect
|
||||
github.com/google/go-tpm v0.9.8 // indirect
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
@ -210,55 +213,55 @@ require (
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
|
||||
github.com/inbucket/html2text v1.0.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jonboulle/clockwork v0.5.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kevinburke/ssh_config v1.4.0 // indirect
|
||||
github.com/kevinburke/ssh_config v1.6.0 // indirect
|
||||
github.com/klauspost/crc32 v1.3.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/libdns/libdns v1.1.1 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.2 // indirect
|
||||
github.com/markbates/going v1.0.3 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.17 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.21 // indirect
|
||||
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||
github.com/mholt/acmez/v3 v3.1.4 // indirect
|
||||
github.com/miekg/dns v1.1.69 // indirect
|
||||
github.com/mholt/acmez/v3 v3.1.6 // indirect
|
||||
github.com/miekg/dns v1.1.72 // indirect
|
||||
github.com/mikelolasagasti/xz v1.0.1 // indirect
|
||||
github.com/minio/crc64nvme v1.1.1 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/minlz v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/minio/minlz v1.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
|
||||
github.com/olekukonko/cat v0.0.0-20250817074551-3280053e4e00 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.1.0 // indirect
|
||||
github.com/olekukonko/tablewriter v1.0.9 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.2.2 // indirect
|
||||
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
|
||||
github.com/olekukonko/errors v1.2.0 // indirect
|
||||
github.com/olekukonko/ll v0.1.8 // indirect
|
||||
github.com/olekukonko/tablewriter v1.1.4 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/philhofer/fwd v1.2.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||
github.com/pjbgf/sha1cd v0.4.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.26 // indirect
|
||||
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.66.1 // indirect
|
||||
github.com/prometheus/procfs v0.17.0 // indirect
|
||||
github.com/rhysd/actionlint v1.7.11 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/prometheus/common v0.67.5 // indirect
|
||||
github.com/prometheus/procfs v0.20.1 // indirect
|
||||
github.com/rhysd/actionlint v1.7.12 // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||
github.com/skeema/knownhosts v1.3.2 // indirect
|
||||
github.com/sorairolake/lzip-go v0.3.8 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||
github.com/tinylib/msgp v1.6.1 // indirect
|
||||
github.com/tinylib/msgp v1.6.3 // indirect
|
||||
github.com/unknwon/com v1.0.1 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
@ -272,14 +275,14 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.1 // indirect
|
||||
go.uber.org/zap/exp v0.3.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||
go4.org v0.0.0-20260112195520-a5071408f32f // indirect
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
|
||||
golang.org/x/mod v0.31.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
golang.org/x/tools v0.40.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect
|
||||
golang.org/x/mod v0.34.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
golang.org/x/tools v0.43.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401020348-3a24fdc17823 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
@ -289,16 +292,22 @@ ignore (
|
||||
./node_modules
|
||||
)
|
||||
|
||||
replace github.com/jaytaylor/html2text => github.com/Necoro/html2text v0.0.0-20250804200300-7bf1ce1c7347
|
||||
// When doing "go get -u ./...", Golang will try to update all dependencies
|
||||
// But not all latest versions of dependencies are compatible with other packages or our codebase, so we need to pin some dependencies to specific versions
|
||||
// Need to regularly maintain this list to try to update them to latest versions, especially the TODO ones
|
||||
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.261.10
|
||||
replace github.com/jaytaylor/html2text => github.com/Necoro/html2text v0.0.0-20250804200300-7bf1ce1c7347 // jaytaylor/html2text is unmaintained
|
||||
|
||||
exclude github.com/gofrs/uuid v3.2.0+incompatible
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.261.10 // gitea maintains its own package
|
||||
|
||||
exclude github.com/gofrs/uuid v4.0.0+incompatible
|
||||
replace github.com/urfave/cli/v3 => github.com/urfave/cli/v3 v3.4.1 // v3.6.2 breaks -c flag parsing in help commands
|
||||
|
||||
exclude github.com/goccy/go-json v0.4.11
|
||||
replace go.yaml.in/yaml/v4 => go.yaml.in/yaml/v4 v4.0.0-rc.3 // rc.4 changes block scalar serialization, wait for stable release
|
||||
|
||||
exclude github.com/satori/go.uuid v1.2.0
|
||||
replace github.com/Azure/azure-sdk-for-go/sdk/azcore => github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0 // v1.21.0+ uses API version unsupported by Azurite in CI
|
||||
|
||||
replace github.com/Azure/azure-sdk-for-go/sdk/storage/azblob => github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2 // v1.6.4+ uses API version unsupported by Azurite in CI
|
||||
|
||||
replace github.com/microsoft/go-mssqldb => github.com/microsoft/go-mssqldb v1.9.7 // downgraded with Azure SDK
|
||||
|
||||
tool code.gitea.io/gitea-vet
|
||||
|
||||
@ -139,7 +139,7 @@ func Test_CalcCommitStatus(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusPending,
|
||||
State: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@ -64,36 +64,6 @@ func LoadProjectIssueColumnMap(ctx context.Context, projectID, defaultColumnID i
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LoadIssuesFromColumn load issues assigned to this column
|
||||
func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column, opts *IssuesOptions) (IssueList, error) {
|
||||
issueList, err := Issues(ctx, opts.Copy(func(o *IssuesOptions) {
|
||||
o.ProjectColumnID = b.ID
|
||||
o.ProjectID = b.ProjectID
|
||||
o.SortType = "project-column-sorting"
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b.Default {
|
||||
issues, err := Issues(ctx, opts.Copy(func(o *IssuesOptions) {
|
||||
o.ProjectColumnID = db.NoConditionID
|
||||
o.ProjectID = b.ProjectID
|
||||
o.SortType = "project-column-sorting"
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
issueList = append(issueList, issues...)
|
||||
}
|
||||
|
||||
if err := issueList.LoadComments(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return issueList, nil
|
||||
}
|
||||
|
||||
// IssueAssignOrRemoveProject changes the project associated with an issue
|
||||
// If newProjectID is 0, the issue is removed from the project
|
||||
func IssueAssignOrRemoveProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID, newColumnID int64) error {
|
||||
|
||||
@ -404,6 +404,7 @@ func prepareMigrationTasks() []*migration {
|
||||
newMigration(327, "Add disabled state to action runners", v1_26.AddDisabledToActionRunner),
|
||||
newMigration(328, "Add TokenPermissions column to ActionRunJob", v1_26.AddTokenPermissionsToActionRunJob),
|
||||
newMigration(329, "Add unique constraint for user badge", v1_26.AddUniqueIndexForUserBadge),
|
||||
newMigration(330, "Add name column to webhook", v1_26.AddNameToWebhook),
|
||||
}
|
||||
return preparedMigrations
|
||||
}
|
||||
|
||||
16
models/migrations/v1_26/v330.go
Normal file
16
models/migrations/v1_26/v330.go
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_26
|
||||
|
||||
import (
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func AddNameToWebhook(x *xorm.Engine) error {
|
||||
type Webhook struct {
|
||||
Name string `xorm:"VARCHAR(255) NOT NULL DEFAULT ''"`
|
||||
}
|
||||
_, err := x.SyncWithOptions(xorm.SyncOptions{IgnoreDropIndices: true}, new(Webhook))
|
||||
return err
|
||||
}
|
||||
@ -257,9 +257,12 @@ func (p *Project) GetColumns(ctx context.Context) (ColumnList, error) {
|
||||
return columns, nil
|
||||
}
|
||||
|
||||
// getDefaultColumn return default column and ensure only one exists
|
||||
func (p *Project) getDefaultColumn(ctx context.Context) (*Column, error) {
|
||||
// getDefaultColumnWithFallback return default column if one exists
|
||||
// otherwise return the first column by sorting and set it as default column
|
||||
func (p *Project) getDefaultColumnWithFallback(ctx context.Context) (*Column, error) {
|
||||
var column Column
|
||||
|
||||
// try to find a column "default=true"
|
||||
has, err := db.GetEngine(ctx).
|
||||
Where("project_id=? AND `default` = ?", p.ID, true).
|
||||
Desc("id").Get(&column)
|
||||
@ -270,23 +273,9 @@ func (p *Project) getDefaultColumn(ctx context.Context) (*Column, error) {
|
||||
if has {
|
||||
return &column, nil
|
||||
}
|
||||
return nil, ErrProjectColumnNotExist{ColumnID: 0}
|
||||
}
|
||||
|
||||
// MustDefaultColumn returns the default column for a project.
|
||||
// If one exists, it is returned
|
||||
// If none exists, the first column will be elevated to the default column of this project
|
||||
func (p *Project) MustDefaultColumn(ctx context.Context) (*Column, error) {
|
||||
c, err := p.getDefaultColumn(ctx)
|
||||
if err != nil && !IsErrProjectColumnNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
if c != nil {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
var column Column
|
||||
has, err := db.GetEngine(ctx).Where("project_id=?", p.ID).OrderBy("sorting, id").Get(&column)
|
||||
// try to find the first column by sorting
|
||||
has, err = db.GetEngine(ctx).Where("project_id=?", p.ID).OrderBy("sorting, id").Get(&column)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -298,8 +287,24 @@ func (p *Project) MustDefaultColumn(ctx context.Context) (*Column, error) {
|
||||
return &column, nil
|
||||
}
|
||||
|
||||
return nil, ErrProjectColumnNotExist{ColumnID: 0}
|
||||
}
|
||||
|
||||
// MustDefaultColumn returns the default column for a project.
|
||||
// If one exists, it is returned
|
||||
// If none exists, the first column will be elevated to the default column of this project
|
||||
// If there is no column, it creates a default column and returns it
|
||||
func (p *Project) MustDefaultColumn(ctx context.Context) (*Column, error) {
|
||||
c, err := p.getDefaultColumnWithFallback(ctx)
|
||||
if err != nil && !IsErrProjectColumnNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
if c != nil {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// create a default column if none is found
|
||||
column = Column{
|
||||
column := Column{
|
||||
ProjectID: p.ID,
|
||||
Default: true,
|
||||
Title: "Uncategorized",
|
||||
|
||||
@ -126,6 +126,7 @@ type Webhook struct {
|
||||
OwnerID int64 `xorm:"INDEX"`
|
||||
IsSystemWebhook bool
|
||||
URL string `xorm:"url TEXT"`
|
||||
Name string `xorm:"VARCHAR(255) NOT NULL DEFAULT ''"`
|
||||
HTTPMethod string `xorm:"http_method"`
|
||||
ContentType HookContentType
|
||||
Secret string `xorm:"TEXT"`
|
||||
|
||||
@ -135,7 +135,7 @@ func rewriteSubExpression(in string, forceFormat bool) (string, error) {
|
||||
exprStart := -1
|
||||
strStart := -1
|
||||
var results []string
|
||||
formatOut := ""
|
||||
var formatOut strings.Builder
|
||||
for pos < len(in) {
|
||||
if strStart > -1 {
|
||||
matches := strPattern.FindStringIndex(in[pos:])
|
||||
@ -158,7 +158,7 @@ func rewriteSubExpression(in string, forceFormat bool) (string, error) {
|
||||
}
|
||||
|
||||
if exprEnd > -1 {
|
||||
formatOut += fmt.Sprintf("{%d}", len(results))
|
||||
fmt.Fprintf(&formatOut, "{%d}", len(results))
|
||||
results = append(results, strings.TrimSpace(in[exprStart:pos+exprEnd]))
|
||||
pos += exprEnd + 2
|
||||
exprStart = -1
|
||||
@ -170,20 +170,20 @@ func rewriteSubExpression(in string, forceFormat bool) (string, error) {
|
||||
} else {
|
||||
exprStart = strings.Index(in[pos:], "${{")
|
||||
if exprStart != -1 {
|
||||
formatOut += escapeFormatString(in[pos : pos+exprStart])
|
||||
formatOut.WriteString(escapeFormatString(in[pos : pos+exprStart]))
|
||||
exprStart = pos + exprStart + 3
|
||||
pos = exprStart
|
||||
} else {
|
||||
formatOut += escapeFormatString(in[pos:])
|
||||
formatOut.WriteString(escapeFormatString(in[pos:]))
|
||||
pos = len(in)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(results) == 1 && formatOut == "{0}" && !forceFormat {
|
||||
if len(results) == 1 && formatOut.String() == "{0}" && !forceFormat {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
out := fmt.Sprintf("format('%s', %s)", strings.ReplaceAll(formatOut, "'", "''"), strings.Join(results, ", "))
|
||||
out := fmt.Sprintf("format('%s', %s)", strings.ReplaceAll(formatOut.String(), "'", "''"), strings.Join(results, ", "))
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@ -9,7 +9,9 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
@ -61,6 +63,8 @@ type LayeredFS struct {
|
||||
layers []*Layer
|
||||
}
|
||||
|
||||
var _ fs.ReadDirFS = (*LayeredFS)(nil)
|
||||
|
||||
// Layered returns a new LayeredFS with the given layers. The first layer is the top layer.
|
||||
func Layered(layers ...*Layer) *LayeredFS {
|
||||
return &LayeredFS{layers: layers}
|
||||
@ -83,6 +87,27 @@ func (l *LayeredFS) ReadFile(elems ...string) ([]byte, error) {
|
||||
return bs, err
|
||||
}
|
||||
|
||||
func (l *LayeredFS) ReadDir(name string) (files []fs.DirEntry, _ error) {
|
||||
filesMap := map[string]fs.DirEntry{}
|
||||
for _, layer := range l.layers {
|
||||
entries, err := readDirOptional(layer, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
entryName := entry.Name()
|
||||
if _, exist := filesMap[entryName]; !exist && shouldInclude(entry) {
|
||||
filesMap[entryName] = entry
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, file := range filesMap {
|
||||
files = append(files, file)
|
||||
}
|
||||
slices.SortFunc(files, func(a, b fs.DirEntry) int { return strings.Compare(a.Name(), b.Name()) })
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// ReadLayeredFile reads the named file, and returns the layer name.
|
||||
func (l *LayeredFS) ReadLayeredFile(elems ...string) ([]byte, string, error) {
|
||||
name := util.PathJoinRel(elems...)
|
||||
|
||||
@ -8,7 +8,7 @@ package pam
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/msteinert/pam"
|
||||
"github.com/msteinert/pam/v2"
|
||||
)
|
||||
|
||||
// Supported is true when built with PAM
|
||||
@ -28,6 +28,7 @@ func Auth(serviceName, userName, passwd string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer t.End()
|
||||
|
||||
if err = t.Authenticate(0); err != nil {
|
||||
return "", err
|
||||
|
||||
@ -61,16 +61,17 @@ type CommitStatusStates []CommitStatusState //nolint:revive // export stutter
|
||||
// According to https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#get-the-combined-status-for-a-specific-reference
|
||||
// > Additionally, a combined state is returned. The state is one of:
|
||||
// > failure if any of the contexts report as error or failure
|
||||
// > failure if any of the contexts report as warning (Gitea specific behavior)
|
||||
// > pending if there are no statuses or a context is pending
|
||||
// > success if the latest status for all contexts is success
|
||||
func (css CommitStatusStates) Combine() CommitStatusState {
|
||||
successCnt := 0
|
||||
for _, state := range css {
|
||||
switch {
|
||||
case state.IsError() || state.IsFailure():
|
||||
case state.IsError() || state.IsFailure() || state.IsWarning():
|
||||
return CommitStatusFailure
|
||||
case state.IsPending():
|
||||
case state.IsSuccess() || state.IsWarning() || state.IsSkipped():
|
||||
case state.IsSuccess() || state.IsSkipped():
|
||||
successCnt++
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ func TestCombine(t *testing.T) {
|
||||
{
|
||||
name: "warning",
|
||||
states: CommitStatusStates{CommitStatusWarning},
|
||||
expected: CommitStatusSuccess,
|
||||
expected: CommitStatusFailure,
|
||||
},
|
||||
// 2 states
|
||||
{
|
||||
@ -62,7 +62,7 @@ func TestCombine(t *testing.T) {
|
||||
{
|
||||
name: "pending and warning",
|
||||
states: CommitStatusStates{CommitStatusPending, CommitStatusWarning},
|
||||
expected: CommitStatusPending,
|
||||
expected: CommitStatusFailure,
|
||||
},
|
||||
{
|
||||
name: "success and error",
|
||||
@ -77,7 +77,7 @@ func TestCombine(t *testing.T) {
|
||||
{
|
||||
name: "success and warning",
|
||||
states: CommitStatusStates{CommitStatusSuccess, CommitStatusWarning},
|
||||
expected: CommitStatusSuccess,
|
||||
expected: CommitStatusFailure,
|
||||
},
|
||||
{
|
||||
name: "error and failure",
|
||||
@ -98,7 +98,7 @@ func TestCombine(t *testing.T) {
|
||||
{
|
||||
name: "pending, success and warning",
|
||||
states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusWarning},
|
||||
expected: CommitStatusPending,
|
||||
expected: CommitStatusFailure,
|
||||
},
|
||||
{
|
||||
name: "pending, success and error",
|
||||
@ -133,7 +133,7 @@ func TestCombine(t *testing.T) {
|
||||
{
|
||||
name: "success, warning and skipped",
|
||||
states: CommitStatusStates{CommitStatusSuccess, CommitStatusWarning, CommitStatusSkipped},
|
||||
expected: CommitStatusSuccess,
|
||||
expected: CommitStatusFailure,
|
||||
},
|
||||
// All success
|
||||
{
|
||||
@ -181,12 +181,12 @@ func TestCombine(t *testing.T) {
|
||||
{
|
||||
name: "mixed states with all success",
|
||||
states: CommitStatusStates{CommitStatusSuccess, CommitStatusSuccess, CommitStatusPending, CommitStatusWarning},
|
||||
expected: CommitStatusPending,
|
||||
expected: CommitStatusFailure,
|
||||
},
|
||||
{
|
||||
name: "all success with warning",
|
||||
states: CommitStatusStates{CommitStatusSuccess, CommitStatusSuccess, CommitStatusSuccess, CommitStatusWarning},
|
||||
expected: CommitStatusSuccess,
|
||||
expected: CommitStatusFailure,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -12,10 +12,17 @@ import (
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/santhosh-tekuri/jsonschema/v5"
|
||||
"github.com/santhosh-tekuri/jsonschema/v6"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// schemaLoader implements jsonschema.URLLoader
|
||||
type schemaLoader struct{}
|
||||
|
||||
func (l *schemaLoader) Load(url string) (any, error) {
|
||||
return openSchema(url)
|
||||
}
|
||||
|
||||
// Load project data from file, with optional validation
|
||||
func Load(filename string, data any, validation bool) error {
|
||||
isJSON := strings.HasSuffix(filename, ".json")
|
||||
@ -43,7 +50,7 @@ func unmarshal(bs []byte, data any, isJSON bool) error {
|
||||
|
||||
func getSchema(filename string) (*jsonschema.Schema, error) {
|
||||
c := jsonschema.NewCompiler()
|
||||
c.LoadURL = openSchema
|
||||
c.UseLoader(&schemaLoader{})
|
||||
return c.Compile(filename)
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/santhosh-tekuri/jsonschema/v5"
|
||||
"github.com/santhosh-tekuri/jsonschema/v6"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"path"
|
||||
"sync"
|
||||
@ -16,6 +15,8 @@ import (
|
||||
_ "embed"
|
||||
|
||||
"code.gitea.io/gitea/modules/assetfs"
|
||||
|
||||
"github.com/santhosh-tekuri/jsonschema/v6"
|
||||
)
|
||||
|
||||
//go:embed bindata.dat
|
||||
@ -25,6 +26,11 @@ var BuiltinAssets = sync.OnceValue(func() fs.FS {
|
||||
return assetfs.NewEmbeddedFS(bindata)
|
||||
})
|
||||
|
||||
func openSchema(filename string) (io.ReadCloser, error) {
|
||||
return BuiltinAssets().Open(path.Base(filename))
|
||||
func openSchema(filename string) (any, error) {
|
||||
f, err := BuiltinAssets().Open(path.Base(filename))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return jsonschema.UnmarshalJSON(f)
|
||||
}
|
||||
|
||||
@ -6,14 +6,15 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/santhosh-tekuri/jsonschema/v6"
|
||||
)
|
||||
|
||||
func openSchema(s string) (io.ReadCloser, error) {
|
||||
func openSchema(s string) (any, error) {
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -34,5 +35,10 @@ func openSchema(s string) (io.ReadCloser, error) {
|
||||
filename = filepath.Join("modules/migration/schemas", basename)
|
||||
}
|
||||
}
|
||||
return os.Open(filename)
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return jsonschema.UnmarshalJSON(f)
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ type nuspecPackage struct {
|
||||
func ParsePackageMetaData(r io.ReaderAt, size int64) (*Package, error) {
|
||||
archive, err := zip.NewReader(r, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, util.NewInvalidArgumentErrorf("unable to parse package meta: %v", err)
|
||||
}
|
||||
|
||||
for _, file := range archive.File {
|
||||
|
||||
@ -42,7 +42,7 @@ func (l PortablePdbList) Close() {
|
||||
func ExtractPortablePdb(r io.ReaderAt, size int64) (PortablePdbList, error) {
|
||||
archive, err := zip.NewReader(r, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, util.NewInvalidArgumentErrorf("unable to extract portable pdb: %v", err)
|
||||
}
|
||||
|
||||
var pdbs PortablePdbList
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/web/routing"
|
||||
@ -22,24 +23,29 @@ const viteDevPortFile = "public/assets/.vite/dev-port"
|
||||
|
||||
var viteDevProxy atomic.Pointer[httputil.ReverseProxy]
|
||||
|
||||
func getViteDevServerBaseURL() string {
|
||||
portFile := filepath.Join(setting.StaticRootPath, viteDevPortFile)
|
||||
portContent, _ := os.ReadFile(portFile)
|
||||
port := strings.TrimSpace(string(portContent))
|
||||
if port == "" {
|
||||
return ""
|
||||
}
|
||||
return "http://localhost:" + port
|
||||
}
|
||||
|
||||
func getViteDevProxy() *httputil.ReverseProxy {
|
||||
if proxy := viteDevProxy.Load(); proxy != nil {
|
||||
return proxy
|
||||
}
|
||||
|
||||
portFile := filepath.Join(setting.StaticRootPath, viteDevPortFile)
|
||||
data, err := os.ReadFile(portFile)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
port := strings.TrimSpace(string(data))
|
||||
if port == "" {
|
||||
viteDevServerBaseURL := getViteDevServerBaseURL()
|
||||
if viteDevServerBaseURL == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
target, err := url.Parse("http://localhost:" + port)
|
||||
target, err := url.Parse(viteDevServerBaseURL)
|
||||
if err != nil {
|
||||
log.Error("Failed to parse Vite dev server URL: %v", err)
|
||||
log.Error("Failed to parse Vite dev server base URL %s, err: %v", viteDevServerBaseURL, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -60,7 +66,7 @@ func getViteDevProxy() *httputil.ReverseProxy {
|
||||
ModifyResponse: func(resp *http.Response) error {
|
||||
// add a header to indicate the Vite dev server port,
|
||||
// make developers know that this request is proxied to Vite dev server and which port it is
|
||||
resp.Header.Add("X-Gitea-Vite-Port", port)
|
||||
resp.Header.Add("X-Gitea-Vite-Dev-Server", viteDevServerBaseURL)
|
||||
return nil
|
||||
},
|
||||
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
@ -92,19 +98,46 @@ func ViteDevMiddleware(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// isViteDevMode returns true if the Vite dev server port file exists.
|
||||
// In production mode, the result is cached after the first check.
|
||||
func isViteDevMode() bool {
|
||||
var viteDevModeCheck atomic.Pointer[struct {
|
||||
isDev bool
|
||||
time time.Time
|
||||
}]
|
||||
|
||||
// IsViteDevMode returns true if the Vite dev server port file exists and the server is alive
|
||||
func IsViteDevMode() bool {
|
||||
if setting.IsProd {
|
||||
return false
|
||||
}
|
||||
portFile := filepath.Join(setting.StaticRootPath, viteDevPortFile)
|
||||
_, err := os.Stat(portFile)
|
||||
return err == nil
|
||||
|
||||
now := time.Now()
|
||||
lastCheck := viteDevModeCheck.Load()
|
||||
if lastCheck != nil && time.Now().Sub(lastCheck.time) < time.Second {
|
||||
return lastCheck.isDev
|
||||
}
|
||||
|
||||
viteDevServerBaseURL := getViteDevServerBaseURL()
|
||||
if viteDevServerBaseURL == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
req := httplib.NewRequest(viteDevServerBaseURL+"/web_src/js/__vite_dev_server_check", "GET")
|
||||
resp, _ := req.Response()
|
||||
if resp != nil {
|
||||
_ = resp.Body.Close()
|
||||
}
|
||||
isDev := resp != nil && resp.StatusCode == http.StatusOK
|
||||
viteDevModeCheck.Store(&struct {
|
||||
isDev bool
|
||||
time time.Time
|
||||
}{
|
||||
isDev: isDev,
|
||||
time: now,
|
||||
})
|
||||
return isDev
|
||||
}
|
||||
|
||||
func viteDevSourceURL(name string) string {
|
||||
if !isViteDevMode() {
|
||||
if !IsViteDevMode() {
|
||||
return ""
|
||||
}
|
||||
if strings.HasPrefix(name, "css/theme-") {
|
||||
|
||||
@ -19,6 +19,8 @@ var ErrInvalidReceiveHook = errors.New("Invalid JSON payload received over webho
|
||||
type Hook struct {
|
||||
// The unique identifier of the webhook
|
||||
ID int64 `json:"id"`
|
||||
// Optional human-readable name for the webhook
|
||||
Name string `json:"name"`
|
||||
// The type of the webhook (e.g., gitea, slack, discord)
|
||||
Type string `json:"type"`
|
||||
// Branch filter pattern to determine which branches trigger the webhook
|
||||
@ -66,6 +68,8 @@ type CreateHookOption struct {
|
||||
// default: false
|
||||
// Whether the webhook should be active upon creation
|
||||
Active bool `json:"active"`
|
||||
// Optional human-readable name for the webhook
|
||||
Name string `json:"name" binding:"MaxSize(255)"`
|
||||
}
|
||||
|
||||
// EditHookOption options when modify one hook
|
||||
@ -80,6 +84,8 @@ type EditHookOption struct {
|
||||
AuthorizationHeader string `json:"authorization_header"`
|
||||
// Whether the webhook is active and will be triggered
|
||||
Active *bool `json:"active"`
|
||||
// Optional human-readable name
|
||||
Name *string `json:"name,omitzero" binding:"MaxSize(255)"`
|
||||
}
|
||||
|
||||
// Payloader payload is some part of one hook
|
||||
|
||||
@ -81,6 +81,8 @@ type Issue struct {
|
||||
Repo *RepositoryMeta `json:"repository"`
|
||||
|
||||
PinOrder int `json:"pin_order"`
|
||||
// The version of the issue content for optimistic locking
|
||||
ContentVersion int `json:"content_version"`
|
||||
}
|
||||
|
||||
// CreateIssueOption options to create one issue
|
||||
@ -114,6 +116,8 @@ type EditIssueOption struct {
|
||||
// swagger:strfmt date-time
|
||||
Deadline *time.Time `json:"due_date"`
|
||||
RemoveDeadline *bool `json:"unset_due_date"`
|
||||
// The current version of the issue content to detect conflicts during editing
|
||||
ContentVersion *int `json:"content_version"`
|
||||
}
|
||||
|
||||
// EditDeadlineOption options for creating a deadline
|
||||
|
||||
@ -91,6 +91,8 @@ type PullRequest struct {
|
||||
|
||||
// The pin order for the pull request
|
||||
PinOrder int `json:"pin_order"`
|
||||
// The version of the pull request content for optimistic locking
|
||||
ContentVersion int `json:"content_version"`
|
||||
}
|
||||
|
||||
// PRBranchInfo information about a branch
|
||||
@ -168,6 +170,8 @@ type EditPullRequestOption struct {
|
||||
RemoveDeadline *bool `json:"unset_due_date"`
|
||||
// Whether to allow maintainer edits
|
||||
AllowMaintainerEdit *bool `json:"allow_maintainer_edit"`
|
||||
// The current version of the pull request content to detect conflicts during editing
|
||||
ContentVersion *int `json:"content_version"`
|
||||
}
|
||||
|
||||
// ChangedFile store information about files affected by the pull request
|
||||
|
||||
@ -53,11 +53,11 @@ func (lc *LogChecker) checkLogEvent(event *log.EventFormatted) {
|
||||
}
|
||||
}
|
||||
|
||||
var checkerIndex int64
|
||||
var checkerIndex atomic.Int64
|
||||
|
||||
func NewLogChecker(namePrefix string) (logChecker *LogChecker, cancel func()) {
|
||||
logger := log.GetManager().GetLogger(namePrefix)
|
||||
newCheckerIndex := atomic.AddInt64(&checkerIndex, 1)
|
||||
newCheckerIndex := checkerIndex.Add(1)
|
||||
writerName := namePrefix + "-" + strconv.FormatInt(newCheckerIndex, 10)
|
||||
|
||||
lc := &LogChecker{}
|
||||
|
||||
@ -12,19 +12,19 @@ import (
|
||||
)
|
||||
|
||||
func TestDebounce(t *testing.T) {
|
||||
var c int64
|
||||
var c atomic.Int64
|
||||
d := Debounce(50 * time.Millisecond)
|
||||
d(func() { atomic.AddInt64(&c, 1) })
|
||||
assert.EqualValues(t, 0, atomic.LoadInt64(&c))
|
||||
d(func() { atomic.AddInt64(&c, 1) })
|
||||
d(func() { atomic.AddInt64(&c, 1) })
|
||||
d(func() { c.Add(1) })
|
||||
assert.EqualValues(t, 0, c.Load())
|
||||
d(func() { c.Add(1) })
|
||||
d(func() { c.Add(1) })
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
assert.EqualValues(t, 1, atomic.LoadInt64(&c))
|
||||
d(func() { atomic.AddInt64(&c, 1) })
|
||||
assert.EqualValues(t, 1, atomic.LoadInt64(&c))
|
||||
d(func() { atomic.AddInt64(&c, 1) })
|
||||
d(func() { atomic.AddInt64(&c, 1) })
|
||||
d(func() { atomic.AddInt64(&c, 1) })
|
||||
assert.EqualValues(t, 1, c.Load())
|
||||
d(func() { c.Add(1) })
|
||||
assert.EqualValues(t, 1, c.Load())
|
||||
d(func() { c.Add(1) })
|
||||
d(func() { c.Add(1) })
|
||||
d(func() { c.Add(1) })
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
assert.EqualValues(t, 2, atomic.LoadInt64(&c))
|
||||
assert.EqualValues(t, 2, c.Load())
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/public"
|
||||
"code.gitea.io/gitea/modules/reqctx"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
@ -36,5 +37,6 @@ func CommonTemplateContextData() reqctx.ContextData {
|
||||
"PageStartTime": time.Now(),
|
||||
|
||||
"RunModeIsProd": setting.IsProd,
|
||||
"ViteModeIsDev": public.IsViteDevMode(),
|
||||
}
|
||||
}
|
||||
|
||||
120
options/fileicon/material-icon-rules.json
generated
120
options/fileicon/material-icon-rules.json
generated
@ -1155,6 +1155,11 @@
|
||||
"_dockerhub": "folder-docker",
|
||||
"-dockerhub": "folder-docker",
|
||||
"__dockerhub__": "folder-docker",
|
||||
"nginx": "folder-nginx",
|
||||
".nginx": "folder-nginx",
|
||||
"_nginx": "folder-nginx",
|
||||
"-nginx": "folder-nginx",
|
||||
"__nginx__": "folder-nginx",
|
||||
"astro": "folder-astro",
|
||||
".astro": "folder-astro",
|
||||
"_astro": "folder-astro",
|
||||
@ -1785,6 +1790,11 @@
|
||||
"_pytest_cache": "folder-python",
|
||||
"-pytest_cache": "folder-python",
|
||||
"__pytest_cache__": "folder-python",
|
||||
"r": "folder-r",
|
||||
".r": "folder-r",
|
||||
"_r": "folder-r",
|
||||
"-r": "folder-r",
|
||||
"__r__": "folder-r",
|
||||
"sandbox": "folder-sandbox",
|
||||
".sandbox": "folder-sandbox",
|
||||
"_sandbox": "folder-sandbox",
|
||||
@ -4517,7 +4527,37 @@
|
||||
".forms": "folder-form",
|
||||
"_forms": "folder-form",
|
||||
"-forms": "folder-form",
|
||||
"__forms__": "folder-form"
|
||||
"__forms__": "folder-form",
|
||||
"deprecated": "folder-deprecated",
|
||||
".deprecated": "folder-deprecated",
|
||||
"_deprecated": "folder-deprecated",
|
||||
"-deprecated": "folder-deprecated",
|
||||
"__deprecated__": "folder-deprecated",
|
||||
"scrap": "folder-scrap",
|
||||
".scrap": "folder-scrap",
|
||||
"_scrap": "folder-scrap",
|
||||
"-scrap": "folder-scrap",
|
||||
"__scrap__": "folder-scrap",
|
||||
"skill": "folder-skills",
|
||||
".skill": "folder-skills",
|
||||
"_skill": "folder-skills",
|
||||
"-skill": "folder-skills",
|
||||
"__skill__": "folder-skills",
|
||||
"skills": "folder-skills",
|
||||
".skills": "folder-skills",
|
||||
"_skills": "folder-skills",
|
||||
"-skills": "folder-skills",
|
||||
"__skills__": "folder-skills",
|
||||
"instruction": "folder-instructions",
|
||||
".instruction": "folder-instructions",
|
||||
"_instruction": "folder-instructions",
|
||||
"-instruction": "folder-instructions",
|
||||
"__instruction__": "folder-instructions",
|
||||
"instructions": "folder-instructions",
|
||||
".instructions": "folder-instructions",
|
||||
"_instructions": "folder-instructions",
|
||||
"-instructions": "folder-instructions",
|
||||
"__instructions__": "folder-instructions"
|
||||
},
|
||||
"folderNamesExpanded": {
|
||||
"rust": "folder-rust-open",
|
||||
@ -5675,6 +5715,11 @@
|
||||
"_dockerhub": "folder-docker-open",
|
||||
"-dockerhub": "folder-docker-open",
|
||||
"__dockerhub__": "folder-docker-open",
|
||||
"nginx": "folder-nginx-open",
|
||||
".nginx": "folder-nginx-open",
|
||||
"_nginx": "folder-nginx-open",
|
||||
"-nginx": "folder-nginx-open",
|
||||
"__nginx__": "folder-nginx-open",
|
||||
"astro": "folder-astro-open",
|
||||
".astro": "folder-astro-open",
|
||||
"_astro": "folder-astro-open",
|
||||
@ -6305,6 +6350,11 @@
|
||||
"_pytest_cache": "folder-python-open",
|
||||
"-pytest_cache": "folder-python-open",
|
||||
"__pytest_cache__": "folder-python-open",
|
||||
"r": "folder-r-open",
|
||||
".r": "folder-r-open",
|
||||
"_r": "folder-r-open",
|
||||
"-r": "folder-r-open",
|
||||
"__r__": "folder-r-open",
|
||||
"sandbox": "folder-sandbox-open",
|
||||
".sandbox": "folder-sandbox-open",
|
||||
"_sandbox": "folder-sandbox-open",
|
||||
@ -9037,7 +9087,37 @@
|
||||
".forms": "folder-form-open",
|
||||
"_forms": "folder-form-open",
|
||||
"-forms": "folder-form-open",
|
||||
"__forms__": "folder-form-open"
|
||||
"__forms__": "folder-form-open",
|
||||
"deprecated": "folder-deprecated-open",
|
||||
".deprecated": "folder-deprecated-open",
|
||||
"_deprecated": "folder-deprecated-open",
|
||||
"-deprecated": "folder-deprecated-open",
|
||||
"__deprecated__": "folder-deprecated-open",
|
||||
"scrap": "folder-scrap-open",
|
||||
".scrap": "folder-scrap-open",
|
||||
"_scrap": "folder-scrap-open",
|
||||
"-scrap": "folder-scrap-open",
|
||||
"__scrap__": "folder-scrap-open",
|
||||
"skill": "folder-skills-open",
|
||||
".skill": "folder-skills-open",
|
||||
"_skill": "folder-skills-open",
|
||||
"-skill": "folder-skills-open",
|
||||
"__skill__": "folder-skills-open",
|
||||
"skills": "folder-skills-open",
|
||||
".skills": "folder-skills-open",
|
||||
"_skills": "folder-skills-open",
|
||||
"-skills": "folder-skills-open",
|
||||
"__skills__": "folder-skills-open",
|
||||
"instruction": "folder-instructions-open",
|
||||
".instruction": "folder-instructions-open",
|
||||
"_instruction": "folder-instructions-open",
|
||||
"-instruction": "folder-instructions-open",
|
||||
"__instruction__": "folder-instructions-open",
|
||||
"instructions": "folder-instructions-open",
|
||||
".instructions": "folder-instructions-open",
|
||||
"_instructions": "folder-instructions-open",
|
||||
"-instructions": "folder-instructions-open",
|
||||
"__instructions__": "folder-instructions-open"
|
||||
},
|
||||
"rootFolderNames": {},
|
||||
"rootFolderNamesExpanded": {},
|
||||
@ -9063,6 +9143,7 @@
|
||||
"json5": "json",
|
||||
"jsonl": "json",
|
||||
"ndjson": "json",
|
||||
"schema.json": "json_schema",
|
||||
"hjson": "hjson",
|
||||
"jinja": "jinja",
|
||||
"jinja2": "jinja",
|
||||
@ -9261,6 +9342,7 @@
|
||||
"vcxitems.filters": "visualstudio",
|
||||
"vcxproj": "visualstudio",
|
||||
"vcxproj.filters": "visualstudio",
|
||||
"wixproj": "visualstudio",
|
||||
"vcl": "varnish",
|
||||
"pdb": "database",
|
||||
"sql": "database",
|
||||
@ -9984,6 +10066,7 @@
|
||||
"ast": "sas",
|
||||
"sast": "sas",
|
||||
"nupkg": "nuget",
|
||||
"nuspec": "nuget",
|
||||
"command": "command",
|
||||
"dsc": "denizenscript",
|
||||
"code-search": "search",
|
||||
@ -10206,6 +10289,10 @@
|
||||
"lean": "lean",
|
||||
"sls": "salt",
|
||||
"m2": "macaulay2",
|
||||
"skill.md": "skill",
|
||||
"skills.md": "skill",
|
||||
"instructions.md": "instructions",
|
||||
"instruction.md": "instructions",
|
||||
"cljx": "clojure",
|
||||
"clojure": "clojure",
|
||||
"edn": "clojure",
|
||||
@ -10363,7 +10450,6 @@
|
||||
"jmx": "xml",
|
||||
"launch": "xml",
|
||||
"menu": "xml",
|
||||
"nuspec": "xml",
|
||||
"opml": "xml",
|
||||
"owl": "xml",
|
||||
"proj": "xml",
|
||||
@ -11094,7 +11180,18 @@
|
||||
"rstest.config.ts": "rstack",
|
||||
"rstest.config.mts": "rstack",
|
||||
"rstest.config.cts": "rstack",
|
||||
"rspress.config.js": "rstack",
|
||||
"rspress.config.mjs": "rstack",
|
||||
"rspress.config.cjs": "rstack",
|
||||
"rspress.config.ts": "rstack",
|
||||
"rspress.config.mts": "rstack",
|
||||
"rspress.config.cts": "rstack",
|
||||
"rslint.config.js": "rstack",
|
||||
"rslint.config.mjs": "rstack",
|
||||
"rslint.config.cjs": "rstack",
|
||||
"rslint.config.ts": "rstack",
|
||||
"rslint.config.mts": "rstack",
|
||||
"rslint.config.cts": "rstack",
|
||||
"rslint.json": "rstack",
|
||||
"rslint.jsonc": "rstack",
|
||||
"lynx.config.js": "lynx",
|
||||
@ -11141,6 +11238,8 @@
|
||||
".env.dist": "tune",
|
||||
".env.prod": "tune",
|
||||
".env.production": "tune",
|
||||
".env.prod.example": "tune",
|
||||
".env.production.example": "tune",
|
||||
".env.stg": "tune",
|
||||
".env.stage": "tune",
|
||||
".env.staging": "tune",
|
||||
@ -11850,6 +11949,12 @@
|
||||
"velite.config.ts": "velite",
|
||||
"velite.config.mts": "velite",
|
||||
"velite.config.cts": "velite",
|
||||
"rolldown.config.js": "rolldown",
|
||||
"rolldown.config.mjs": "rolldown",
|
||||
"rolldown.config.cjs": "rolldown",
|
||||
"rolldown.config.ts": "rolldown",
|
||||
"rolldown.config.mts": "rolldown",
|
||||
"rolldown.config.cts": "rolldown",
|
||||
"lerna.json": "lerna",
|
||||
"windi.config.js": "windicss",
|
||||
"windi.config.cjs": "windicss",
|
||||
@ -12352,6 +12457,7 @@
|
||||
"lefthookrc": "lefthook",
|
||||
".github/labeler.yml": "label",
|
||||
".github/labeler.yaml": "label",
|
||||
"tags": "label",
|
||||
"zeabur.json": "zeabur",
|
||||
"zeabur.jsonc": "zeabur",
|
||||
"zeabur.json5": "zeabur",
|
||||
@ -12427,6 +12533,7 @@
|
||||
".oxfmtrc.json": "oxc",
|
||||
".oxfmtrc.jsonc": "oxc",
|
||||
"oxlint.config.ts": "oxc",
|
||||
"oxfmt.config.ts": "oxc",
|
||||
"claude.md": "claude",
|
||||
"claude.local.md": "claude",
|
||||
".cursorignore": "cursor",
|
||||
@ -12450,6 +12557,9 @@
|
||||
".shellcheckrc": "shellcheck",
|
||||
"shellcheckrc": "shellcheck",
|
||||
"warp.md": "warp",
|
||||
"skill.md": "skill",
|
||||
"instructions.md": "instructions",
|
||||
"instruction.md": "instructions",
|
||||
"language-configuration.json": "jsonc",
|
||||
"icon-theme.json": "jsonc",
|
||||
"color-theme.json": "jsonc",
|
||||
@ -12653,7 +12763,9 @@
|
||||
"helm": "helm",
|
||||
"nginx": "nginx",
|
||||
"cue": "cue",
|
||||
"lean": "lean"
|
||||
"lean": "lean",
|
||||
"skill": "skill",
|
||||
"instructions": "instructions"
|
||||
},
|
||||
"light": {
|
||||
"fileExtensions": {
|
||||
|
||||
16
options/fileicon/material-icon-svgs.json
generated
16
options/fileicon/material-icon-svgs.json
generated
@ -319,6 +319,8 @@
|
||||
"folder-decorators": "<svg viewBox='0 0 32 32'><path fill='#ab47bc' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#e1bee7' d='M23.66 30a7.8 7.8 0 0 1-3.737-.929 7.06 7.06 0 0 1-2.81-2.784 9.2 9.2 0 0 1-1.07-4.655 18.3 18.3 0 0 1 .863-5.874 12.6 12.6 0 0 1 2.349-4.267 10.1 10.1 0 0 1 3.392-2.604A9.3 9.3 0 0 1 26.607 8a5.22 5.22 0 0 1 4.101 1.455A5.64 5.64 0 0 1 32 13.347a5.4 5.4 0 0 1-.069.832q-.07.443-.153.914l-1.611 7.97h-2.308l-.029-1.006h-.11c-.464.258-.96.665-1.488.96a3.96 3.96 0 0 1-1.96.444 3.03 3.03 0 0 1-2.098-.818 2.79 2.79 0 0 1-.904-2.175 4.34 4.34 0 0 1 1.877-3.781 13 13 0 0 1 5.907-1.76 6 6 0 0 0 .167-1.22 3.94 3.94 0 0 0-.611-2.258 2.71 2.71 0 0 0-2.39-.9 4.9 4.9 0 0 0-2.42.692 7.7 7.7 0 0 0-2.266 2.051 10.9 10.9 0 0 0-1.682 3.367 15.3 15.3 0 0 0-.638 4.641 7.05 7.05 0 0 0 .721 3.366 5 5 0 0 0 1.864 2.009 4.67 4.67 0 0 0 2.39.665 4.4 4.4 0 0 0 1.668-.29 6.2 6.2 0 0 0 1.418-.818l1.279 2.272a7.3 7.3 0 0 1-2.21 1.122A9 9 0 0 1 23.66 30m2.018-9.056a2.8 2.8 0 0 0 1.04-.21 4.8 4.8 0 0 0 1.04-.574l.56-2.742a6.8 6.8 0 0 0-2.99.951 1.87 1.87 0 0 0-.772 1.512 1 1 0 0 0 .31.783 1.16 1.16 0 0 0 .812.28'/></svg>",
|
||||
"folder-delta-open": "<svg viewBox='0 0 32 32'><path fill='#ec407a' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#f8bbd0' d='M23 17.699 28.337 26H17.663zM23 14l-9 14h18z'/></svg>",
|
||||
"folder-delta": "<svg viewBox='0 0 32 32'><path fill='#ec407a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#f8bbd0' d='M23 17.699 28.337 26H17.663zM23 14l-9 14h18z'/></svg>",
|
||||
"folder-deprecated-open.clone": "<svg viewBox='0 0 1024 1024'><path fill='#616161' d='M926.912 384H302.144a64 64 0 0 0-60.736 43.776L128 768V320h768a64 64 0 0 0-64-64H483.968a64 64 0 0 1-40.96-14.848l-41.216-34.304A64 64 0 0 0 360.832 192H128a64 64 0 0 0-64 64v512a64 64 0 0 0 64 64h704l153.792-358.784A64 64 0 0 0 926.912 384'/><path fill='#bdbdbd' d='M512 320c-35.456 0-64 28.544-64 64v64c0 35.456 28.544 64 64 64v320c0 35.456 28.544 64 64 64h320c35.456 0 64-28.544 64-64V512c35.456 0 64-28.544 64-64v-64c0-35.456-28.544-64-64-64zm0 64h448v64H512zm128 128h192v64H640z'/></svg>",
|
||||
"folder-deprecated.clone": "<svg viewBox='0 0 1024 1024'><path fill='#616161' d='m443.008 241.152-41.216-34.304A64 64 0 0 0 360.832 192H128a64 64 0 0 0-64 64v512a64 64 0 0 0 64 64h768a64 64 0 0 0 64-64V320a64 64 0 0 0-64-64H483.968a64 64 0 0 1-40.96-14.848'/><path fill='#bdbdbd' d='M512 320c-35.456 0-64 28.544-64 64v64c0 35.456 28.544 64 64 64v320c0 35.456 28.544 64 64 64h320c35.456 0 64-28.544 64-64V512c35.456 0 64-28.544 64-64v-64c0-35.456-28.544-64-64-64zm0 64h448v64H512zm128 128h192v64H640z'/></svg>",
|
||||
"folder-desktop-open": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#b3e5fc' d='M30 12H14a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6v2h-2v2h8v-2h-2v-2h6a2 2 0 0 0 2-2V14a2 2 0 0 0-2-2m0 12H14V14h16Z'/></svg>",
|
||||
"folder-desktop": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b3e5fc' d='M30 12H14a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6v2h-2v2h8v-2h-2v-2h6a2 2 0 0 0 2-2V14a2 2 0 0 0-2-2m0 12H14V14h16Z'/></svg>",
|
||||
"folder-development-open.clone": "<svg viewBox='0 0 32 32'><path fill='#0288d1' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#b3e5fc' d='M18.473 30a1 1 0 0 1-.238-.028 1.137 1.137 0 0 1-.828-1.323L20.5 12.905a1.13 1.13 0 0 1 .507-.744 1.06 1.06 0 0 1 .8-.134 1.14 1.14 0 0 1 .828 1.324l-3.101 15.744a1.12 1.12 0 0 1-.504.743 1.06 1.06 0 0 1-.557.162m6.2-2h-.077a1.08 1.08 0 0 1-.762-.412 1.164 1.164 0 0 1 .113-1.548l5.319-4.967-5.296-4.623a1.165 1.165 0 0 1-.162-1.544 1.08 1.08 0 0 1 .754-.437 1.06 1.06 0 0 1 .81.258l6.244 5.455a1.156 1.156 0 0 1 .003 1.723l-6.218 5.808a1.07 1.07 0 0 1-.729.289Zm-9.31 0a1.07 1.07 0 0 1-.728-.292l-6.226-5.811a1.16 1.16 0 0 1-.01-1.692l.02-.018 6.246-5.454a1.03 1.03 0 0 1 .8-.26 1.08 1.08 0 0 1 .76.436 1.165 1.165 0 0 1-.16 1.547l-5.294 4.62 5.32 4.964a1.156 1.156 0 0 1 .112 1.548 1.07 1.07 0 0 1-.762.412Z'/></svg>",
|
||||
@ -427,6 +429,8 @@
|
||||
"folder-include": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b3e5fc' d='M25 14a7 7 0 1 0 7 7 7 7 0 0 0-7-7m1 8v4h-2v-4h-4v-2h4v-4h2v4h4v2Z'/></svg>",
|
||||
"folder-input-open": "<svg viewBox='0 0 32 32'><path fill='#00acc1' d='M28.965 12H9.441a2 2 0 0 0-1.898 1.368L4 24V10h23.998a2 2 0 0 0-2-2H15.122a2 2 0 0 1-1.28-.464l-1.287-1.072A2 2 0 0 0 11.275 6H3.999a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h21.998l4.805-11.212A2 2 0 0 0 28.964 12'/><path fill='#b2ebf2' d='M13.98 10c-1.098 0-1.98.994-1.98 2.229V16h2v-4h16v14H14v-4h-2v3.772c0 1.234.882 2.228 1.98 2.228h16.039c1.098 0 1.98-.994 1.98-2.228V12.229C32 10.994 31.118 10 30.02 10zM22 14v4H12v2h10v4l5.12-5z'/></svg>",
|
||||
"folder-input": "<svg viewBox='0 0 32 32'><path fill='#00acc1' d='m13.844 7.537-1.287-1.073A2 2 0 0 0 11.277 6H4.001A2 2 0 0 0 2 8v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.125a2 2 0 0 1-1.282-.463'/><path fill='#b2ebf2' d='M13.98 10c-1.098 0-1.98.994-1.98 2.229V16h2v-4h16v14H14v-4h-2v3.772c0 1.234.882 2.228 1.98 2.228h16.039c1.098 0 1.98-.994 1.98-2.228V12.229C32 10.994 31.118 10 30.02 10zM22 14v4H12v2h10v4l5.12-5z'/></svg>",
|
||||
"folder-instructions-open.clone": "<svg viewBox='0 0 32 32'><path fill='#00b8d4' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#b2ebf2' d='M16 16h-2v13a1 1 0 0 0 1 1h13v-2H16Z'/><path fill='#b2ebf2' d='M31 12H19a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V13a1 1 0 0 0-1-1m-5 12h-6v-2h6Zm4-4H20v-2h10Zm0-4H20v-2h10Z'/></svg>",
|
||||
"folder-instructions.clone": "<svg viewBox='0 0 32 32'><path fill='#00b8d4' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b2ebf2' d='M16 16h-2v13a1 1 0 0 0 1 1h13v-2H16Z'/><path fill='#b2ebf2' d='M31 12H19a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V13a1 1 0 0 0-1-1m-5 12h-6v-2h6Zm4-4H20v-2h10Zm0-4H20v-2h10Z'/></svg>",
|
||||
"folder-intellij-open": "<svg viewBox='0 0 32 32'><defs data-mit-no-recolor='true'><linearGradient id='a' x1='.445' x2='104.977' y1='3272.835' y2='3209.742' gradientTransform='translate(18.126 -331.024)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#fdd835'/><stop offset='1' stop-color='#f57c00'/></linearGradient><linearGradient id='b' x1='22.55' x2='117.962' y1='3121.343' y2='3204.873' gradientTransform='translate(18.126 -331.024)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#ef5350'/><stop offset='.57' stop-color='#ff6e40'/><stop offset='1' stop-color='#f57c00'/></linearGradient><linearGradient id='c' x1='28.608' x2='-27.937' y1='3197.064' y2='3161.75' gradientTransform='translate(18.126 -331.024)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#8e24aa'/><stop offset='.385' stop-color='#ab47bc'/><stop offset='.765' stop-color='#ec407a'/><stop offset='.957' stop-color='#ec407a'/></linearGradient><linearGradient id='d' x1='27.588' x2='-27.616' y1='3117.085' y2='3162.678' gradientTransform='translate(18.126 -331.024)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#ef5350'/><stop offset='.364' stop-color='#ec407a'/><stop offset='1' stop-color='#ec407a'/></linearGradient></defs><path fill='#546e7a' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='url(#a)' d='M30.93 22.519a.68.68 0 0 0 .22-.47.69.69 0 0 0-.647-.72.72.72 0 0 0-.485.161l-12.314 6.745a1.44 1.44 0 0 0-.69.602 1.48 1.48 0 0 0 .506 2.03l.022.013a1.51 1.51 0 0 0 1.573-.03c.03-.029.073-.043.103-.073l11.461-8.053a2 2 0 0 0 .25-.205Z'/><path fill='url(#b)' d='m30.959 21.534-9.376-9.199a1.133 1.133 0 1 0-1.66 1.543 2 2 0 0 0 .176.147l9.904 8.48a.76.76 0 0 0 .441.19.69.69 0 0 0 .72-.646.73.73 0 0 0-.205-.515'/><path fill='url(#c)' d='M21.892 20.711c-.015 0-5.79-4.555-5.907-4.628l-.265-.133a1.644 1.644 0 0 0-1.44 2.94 1.3 1.3 0 0 0 .294.131c.059.03 6.671 2.763 6.671 2.763a.63.63 0 0 0 .647-1.073'/><path fill='url(#d)' d='M20.746 11.968a1.2 1.2 0 0 0-.676.22l-5.849 3.939c-.014.014-.03.014-.03.029h-.014a1.638 1.638 0 0 0 .397 2.865 1.61 1.61 0 0 0 1.528-.205 1.4 1.4 0 0 0 .265-.235l5.084-4.585a1.132 1.132 0 0 0-.705-2.028'/></svg>",
|
||||
"folder-intellij-open_light": "<svg viewBox='0 0 32 32'><defs data-mit-no-recolor='true'><linearGradient id='a' x1='.445' x2='104.977' y1='3611.926' y2='3548.833' gradientTransform='translate(18.126 -368.395)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#fdd835'/><stop offset='1' stop-color='#f57c00'/></linearGradient><linearGradient id='b' x1='22.55' x2='117.962' y1='3460.434' y2='3543.963' gradientTransform='translate(18.126 -368.395)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#ef5350'/><stop offset='.57' stop-color='#ff6e40'/><stop offset='1' stop-color='#f57c00'/></linearGradient><linearGradient id='c' x1='28.608' x2='-27.937' y1='3536.154' y2='3500.841' gradientTransform='translate(18.126 -368.395)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#8e24aa'/><stop offset='.385' stop-color='#ab47bc'/><stop offset='.765' stop-color='#ec407a'/><stop offset='.957' stop-color='#ec407a'/></linearGradient><linearGradient id='d' x1='27.588' x2='-27.616' y1='3456.176' y2='3501.769' gradientTransform='translate(18.126 -368.395)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#ef5350'/><stop offset='.364' stop-color='#ec407a'/><stop offset='1' stop-color='#ec407a'/></linearGradient></defs><path fill='#b0bec5' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='url(#a)' d='M30.93 22.519a.68.68 0 0 0 .22-.47.69.69 0 0 0-.647-.72.72.72 0 0 0-.485.161l-12.314 6.745a1.44 1.44 0 0 0-.69.602 1.48 1.48 0 0 0 .506 2.03l.022.013a1.51 1.51 0 0 0 1.573-.03c.03-.029.073-.043.103-.073l11.461-8.053a2 2 0 0 0 .25-.205Z'/><path fill='url(#b)' d='m30.959 21.534-9.376-9.199a1.133 1.133 0 1 0-1.66 1.543 2 2 0 0 0 .176.147l9.904 8.48a.76.76 0 0 0 .441.19.69.69 0 0 0 .72-.646.73.73 0 0 0-.205-.515'/><path fill='url(#c)' d='M21.892 20.711c-.015 0-5.79-4.555-5.907-4.628l-.265-.133a1.644 1.644 0 0 0-1.44 2.94 1.3 1.3 0 0 0 .294.131c.059.03 6.671 2.763 6.671 2.763a.63.63 0 0 0 .647-1.073'/><path fill='url(#d)' d='M20.746 11.968a1.2 1.2 0 0 0-.676.22l-5.849 3.939c-.014.014-.03.014-.03.029h-.014a1.638 1.638 0 0 0 .397 2.865 1.61 1.61 0 0 0 1.528-.205 1.4 1.4 0 0 0 .265-.235l5.084-4.585a1.132 1.132 0 0 0-.705-2.028'/></svg>",
|
||||
"folder-intellij": "<svg viewBox='0 0 32 32'><defs data-mit-no-recolor='true'><linearGradient id='a' x1='-338.646' x2='-234.114' y1='3272.835' y2='3209.742' gradientTransform='translate(55.497 -331.024)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#fdd835'/><stop offset='1' stop-color='#f57c00'/></linearGradient><linearGradient id='b' x1='-316.541' x2='-221.129' y1='3121.343' y2='3204.873' gradientTransform='translate(55.497 -331.024)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#ef5350'/><stop offset='.57' stop-color='#ff6e40'/><stop offset='1' stop-color='#f57c00'/></linearGradient><linearGradient id='c' x1='-310.483' x2='-367.028' y1='3197.064' y2='3161.75' gradientTransform='translate(55.497 -331.024)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#8e24aa'/><stop offset='.385' stop-color='#ab47bc'/><stop offset='.765' stop-color='#ec407a'/><stop offset='.957' stop-color='#ec407a'/></linearGradient><linearGradient id='d' x1='-311.503' x2='-366.707' y1='3117.085' y2='3162.678' gradientTransform='translate(55.497 -331.024)scale(.11021)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#ef5350'/><stop offset='.364' stop-color='#ec407a'/><stop offset='1' stop-color='#ec407a'/></linearGradient></defs><path fill='#546e7a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='url(#a)' d='M30.93 22.519a.68.68 0 0 0 .22-.47.69.69 0 0 0-.647-.72.72.72 0 0 0-.485.161l-12.314 6.745a1.44 1.44 0 0 0-.69.602 1.48 1.48 0 0 0 .506 2.03l.022.013a1.51 1.51 0 0 0 1.573-.03c.03-.029.073-.043.103-.073l11.461-8.053a2 2 0 0 0 .25-.205Z'/><path fill='url(#b)' d='m30.959 21.534-9.376-9.199a1.133 1.133 0 1 0-1.66 1.543 2 2 0 0 0 .176.147l9.904 8.48a.76.76 0 0 0 .441.19.69.69 0 0 0 .72-.646.73.73 0 0 0-.205-.515'/><path fill='url(#c)' d='M21.892 20.711c-.015 0-5.79-4.555-5.907-4.628l-.265-.133a1.644 1.644 0 0 0-1.44 2.94 1.3 1.3 0 0 0 .294.131c.059.03 6.671 2.763 6.671 2.763a.63.63 0 0 0 .647-1.073'/><path fill='url(#d)' d='M20.746 11.968a1.2 1.2 0 0 0-.676.22l-5.849 3.939c-.014.014-.03.014-.03.029h-.014a1.638 1.638 0 0 0 .397 2.865 1.61 1.61 0 0 0 1.528-.205 1.4 1.4 0 0 0 .265-.235l5.084-4.585a1.132 1.132 0 0 0-.705-2.028'/></svg>",
|
||||
@ -517,6 +521,8 @@
|
||||
"folder-netlify": "<svg viewBox='0 0 32 32'><path fill='#26a69a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#a7ffeb' d='M22 16h-4v6h2v-4h1.5a.5.5 0 0 1 .5.5V22h2v-4a2 2 0 0 0-2-2'/><rect width='6' height='2' x='26' y='18' fill='#a7ffeb' rx='.5'/><rect width='2' height='6' x='20' y='8' fill='#a7ffeb' rx='.5'/><rect width='6' height='2' x='10' y='18' fill='#a7ffeb' rx='.5'/><rect width='2' height='6' x='20' y='24' fill='#a7ffeb' rx='.5'/><path fill='#a7ffeb' d='m13 12.172 1.414-1.414 2.828 2.828L15.828 15zM15.828 23l1.414 1.414-2.828 2.828L13 25.828z'/></svg>",
|
||||
"folder-next-open": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#cfd8dc' d='M24 12a8 8 0 1 0 3.969 14.94L22 19v4.5a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .5-.5h1.232a.5.5 0 0 1 .416.223l6.736 10.103A7.993 7.993 0 0 0 24 12m4 8h-2v-3.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5Z'/></svg>",
|
||||
"folder-next": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#cfd8dc' d='M24 12a8 8 0 1 0 3.969 14.94L22 19v4.5a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .5-.5h1.232a.5.5 0 0 1 .416.223l6.736 10.103A7.993 7.993 0 0 0 24 12m4 8h-2v-3.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5Z'/></svg>",
|
||||
"folder-nginx-open": "<svg viewBox='0 0 32 32'><path fill='#388e3c' d='M28.966 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.806-11.212A2 2 0 0 0 28.966 12'/><path fill='#a5d6a7' d='m24 10.857-8 4.571v9.143l8 4.572 8-4.572v-9.143zM28 23.5v.5h-1.76a.5.5 0 0 1-.39-.187L22 19v5h-2v-8h1.76a.5.5 0 0 1 .39.188L26 21v-5h2z'/></svg>",
|
||||
"folder-nginx": "<svg viewBox='0 0 32 32'><path fill='#388e3c' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#a5d6a7' d='m24 10.857-8 4.571v9.143l8 4.572 8-4.572v-9.143zM28 24h-1.76a.5.5 0 0 1-.39-.187L22 19v5h-2v-8h1.76a.5.5 0 0 1 .39.188L26 21v-5h2z'/></svg>",
|
||||
"folder-ngrx-actions-open.clone": "<svg viewBox='0 0 32 32'><path fill='#ab47bc' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#e1bee7' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
|
||||
"folder-ngrx-actions.clone": "<svg viewBox='0 0 32 32'><path fill='#ab47bc' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#e1bee7' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
|
||||
"folder-ngrx-effects-open.clone": "<svg viewBox='0 0 32 32'><path fill='#00bcd4' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#b2ebf2' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
|
||||
@ -582,6 +588,8 @@
|
||||
"folder-quasar": "<svg viewBox='0 0 32 32'><path fill='#1976d2' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#bbdefb' d='M24.026 20A2.028 2.028 0 1 1 22 18.048 1.99 1.99 0 0 1 24.026 20m6.967-5.002a10 10 0 0 0-1.59-2.002L27.06 14.3a7.9 7.9 0 0 0-2.445-1.365 9.3 9.3 0 0 0-1.893 2.6 11.74 11.74 0 0 1 7.8 2.618l1.473-.819A9.8 9.8 0 0 0 30.993 15Zm0 10.002A9.8 9.8 0 0 0 32 22.67l-2.342-1.303a7.2 7.2 0 0 0 .005-2.72 10 10 0 0 0-3.285-.278 10.7 10.7 0 0 1 1.545 7.812l1.473.82A10 10 0 0 0 30.993 25m-8.992 5a10.8 10.8 0 0 0 2.597-.326v-2.603a7.9 7.9 0 0 0 2.451-1.357 9.1 9.1 0 0 0-1.392-2.88 11.36 11.36 0 0 1-6.255 5.196v1.64a10.8 10.8 0 0 0 2.599.33m-8.994-5a10 10 0 0 0 1.592 2.004L16.94 25.7a7.8 7.8 0 0 0 2.447 1.365 9.3 9.3 0 0 0 1.891-2.6 11.75 11.75 0 0 1-7.8-2.618l-1.471.819a9.8 9.8 0 0 0 1 2.333Zm0-10A9.8 9.8 0 0 0 12 17.33l2.343 1.303a7.2 7.2 0 0 0-.005 2.72 10 10 0 0 0 3.286.278 10.7 10.7 0 0 1-1.545-7.814l-1.475-.82a10 10 0 0 0-1.597 2.005Zm8.992-5a10.8 10.8 0 0 0-2.597.326v2.603a7.9 7.9 0 0 0-2.45 1.357 9.1 9.1 0 0 0 1.393 2.88A11.35 11.35 0 0 1 24.6 11.97v-1.64A10.8 10.8 0 0 0 22 10Z'/></svg>",
|
||||
"folder-queue-open": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#b3e5fc' d='M24 16v-2h-3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h3v-2h-2v-8Zm8-2v-2h-5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h5v-2h-4V14Zm-16 2h2v8h-2z'/></svg>",
|
||||
"folder-queue": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b3e5fc' d='M24 16v-2h-3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h3v-2h-2v-8Zm8-2v-2h-5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h5v-2h-4V14Zm-16 2h2v8h-2z'/></svg>",
|
||||
"folder-r-open": "<svg viewBox='0 0 32 32'><path fill='#1976d2' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#90caf9' fill-rule='evenodd' d='M16 22.405v2.786c-4.8-1.097-8.263-4.17-8.263-7.804 0-4.553 5.432-8.245 12.132-8.245S32 12.834 32 17.387a6.46 6.46 0 0 1-1.915 4.433l-.49-.855a4.65 4.65 0 0 0 .981-2.962c0-3.91-3.758-5.637-8.85-5.637-5.093 0-9.221 2.523-9.221 5.637 0 1.787 1.372 3.37 3.495 4.402m15.332 5.596V28h-.001Zm0-.001h-4.656l-2.177-4.208a5.4 5.4 0 0 0-.72-1.017c-.23-.19-.327-.258-.553-.258H22V28h-4V14h8.274S30 14.07 30 17.76a3.866 3.866 0 0 1-3.559 3.964 9 9 0 0 1 1.156.448 2.2 2.2 0 0 1 .586.431 1.6 1.6 0 0 1 .268.396ZM26 17.5a1.5 1.5 0 0 0-1.5-1.5H22v4h2.5a1.5 1.5 0 0 0 1.5-1.5Z'/></svg>",
|
||||
"folder-r": "<svg viewBox='0 0 32 32'><path fill='#1976d2' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#90caf9' fill-rule='evenodd' d='M16 22.405v2.786c-4.8-1.097-8.263-4.17-8.263-7.804 0-4.553 5.432-8.245 12.132-8.245S32 12.834 32 17.387a6.46 6.46 0 0 1-1.915 4.433l-.49-.855a4.65 4.65 0 0 0 .981-2.962c0-3.91-3.758-5.637-8.85-5.637-5.093 0-9.221 2.523-9.221 5.637 0 1.787 1.372 3.37 3.495 4.402m15.332 5.596V28h-.001Zm0-.001h-4.656l-2.177-4.208a5.4 5.4 0 0 0-.72-1.017c-.23-.19-.327-.258-.553-.258H22V28h-4V14h8.274S30 14.07 30 17.76a3.866 3.866 0 0 1-3.559 3.964 9 9 0 0 1 1.156.448 2.2 2.2 0 0 1 .586.431 1.6 1.6 0 0 1 .268.396ZM26 17.5a1.5 1.5 0 0 0-1.5-1.5H22v4h2.5a1.5 1.5 0 0 0 1.5-1.5Z'/></svg>",
|
||||
"folder-react-components-open": "<svg viewBox='0 0 16 16'><path fill='#00bcd4' d='M14.484 6H4.72a1 1 0 0 0-.949.684L2 12V5h13a1 1 0 0 0-1-1H7.562a1 1 0 0 1-.64-.232l-.644-.536A1 1 0 0 0 5.638 3H2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h11l2.403-5.606A1 1 0 0 0 14.483 6'/><g fill='#b2ebf2'><path d='M10.5 8.399c2.924 0 4.714 1.037 4.714 1.6s-1.79 1.602-4.714 1.602S5.785 10.564 5.785 10s1.79-1.601 4.715-1.601m0-.8c-3.038 0-5.5 1.075-5.5 2.4s2.462 2.402 5.5 2.402S16 11.326 16 10s-2.463-2.401-5.5-2.401'/><path d='M10.5 9.2a.786.8 0 1 0 .785.8.786.8 0 0 0-.785-.8'/><path d='M8.322 5.8c.793 0 2.333 1.272 3.538 3.4 1.463 2.58 1.476 4.677.997 4.959a.354.36 0 0 1-.18.04c-.792 0-2.333-1.271-3.538-3.399-1.463-2.58-1.476-4.677-.997-4.96a.354.36 0 0 1 .18-.04m0-.8a1.128 1.149 0 0 0-.572.147c-1.128.663-.81 3.374.708 6.054C9.748 13.478 11.491 15 12.678 15a1.128 1.149 0 0 0 .572-.148c1.127-.663.81-3.373-.71-6.053C11.25 6.522 9.509 5 8.323 5Z'/><path d='M12.677 5.8a.354.36 0 0 1 .18.04c.48.283.466 2.38-.997 4.96-1.206 2.128-2.746 3.4-3.538 3.4a.354.36 0 0 1-.18-.04c-.48-.284-.466-2.38.997-4.96 1.206-2.128 2.746-3.4 3.538-3.4m0-.8c-1.186 0-2.929 1.522-4.22 3.8-1.517 2.68-1.835 5.39-.707 6.052a1.128 1.149 0 0 0 .572.148c1.186 0 2.929-1.523 4.22-3.8 1.517-2.68 1.835-5.39.708-6.052A1.128 1.149 0 0 0 12.677 5'/></g></svg>",
|
||||
"folder-react-components": "<svg viewBox='0 0 16 16'><path fill='#00bcd4' d='m6.922 3.768-.644-.536A1 1 0 0 0 5.638 3H2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H7.562a1 1 0 0 1-.64-.232'/><g fill='#b2ebf2'><path d='M10.5 8.399c2.924 0 4.714 1.037 4.714 1.6s-1.79 1.602-4.714 1.602S5.785 10.564 5.785 10s1.79-1.601 4.715-1.601m0-.8c-3.038 0-5.5 1.075-5.5 2.4s2.462 2.402 5.5 2.402S16 11.326 16 10s-2.463-2.401-5.5-2.401'/><path d='M10.5 9.2a.786.8 0 1 0 .785.8.786.8 0 0 0-.785-.8'/><path d='M8.322 5.8c.793 0 2.333 1.272 3.538 3.4 1.463 2.58 1.476 4.677.997 4.959a.354.36 0 0 1-.18.04c-.792 0-2.333-1.271-3.538-3.399-1.463-2.58-1.476-4.677-.997-4.96a.354.36 0 0 1 .18-.04m0-.8a1.128 1.149 0 0 0-.572.147c-1.128.663-.81 3.374.708 6.054C9.748 13.478 11.491 15 12.678 15a1.128 1.149 0 0 0 .572-.148c1.127-.663.81-3.373-.71-6.053C11.25 6.522 9.509 5 8.323 5Z'/><path d='M12.677 5.8a.354.36 0 0 1 .18.04c.48.283.466 2.38-.997 4.96-1.206 2.128-2.746 3.4-3.538 3.4a.354.36 0 0 1-.18-.04c-.48-.284-.466-2.38.997-4.96 1.206-2.128 2.746-3.4 3.538-3.4m0-.8c-1.186 0-2.929 1.522-4.22 3.8-1.517 2.68-1.835 5.39-.707 6.052a1.128 1.149 0 0 0 .572.148c1.186 0 2.929-1.523 4.22-3.8 1.517-2.68 1.835-5.39.708-6.052A1.128 1.149 0 0 0 12.677 5'/></g></svg>",
|
||||
"folder-redux-actions-open.clone": "<svg viewBox='0 0 32 32'><path fill='#ab47bc' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#f3e5f5' stroke='#f3e5f5' stroke-linejoin='round' stroke-width='.293' d='M25.948 24.114a1.65 1.65 0 0 0 .97-.6 1.8 1.8 0 0 0 .381-1.274 1.72 1.72 0 0 0-1.69-1.596h-.06a1.724 1.724 0 0 0-1.61 1.814 1.85 1.85 0 0 0 .34.985 8.85 8.85 0 0 1-3.863 3.799 6.15 6.15 0 0 1-3.876.771 3.13 3.13 0 0 1-2.32-1.411 3.67 3.67 0 0 1-.18-3.738 5.8 5.8 0 0 1 1.605-1.986.3.3 0 0 0 .098-.313 14 14 0 0 1-.315-1.298.29.29 0 0 0-.172-.213.28.28 0 0 0-.272.036c-3.731 2.836-3.326 6.763-2.188 8.579a5.36 5.36 0 0 0 4.294 2.229q.125 0 .24-.005h.04a6 6 0 0 0 1.5-.188 9.88 9.88 0 0 0 7.078-5.591Z'/><path fill='#f3e5f5' stroke='#f3e5f5' stroke-linejoin='round' stroke-width='.293' d='M30.327 20.428a10.12 10.12 0 0 0-7.774-3.69q-.133 0-.265.003h-.234a1.61 1.61 0 0 0-1.377-.78h-.053a1.62 1.62 0 0 0-1.175.535 1.806 1.806 0 0 0 .039 2.466 1.67 1.67 0 0 0 1.19.494h.064a1.68 1.68 0 0 0 1.375-.886h.27a8.83 8.83 0 0 1 5.126 1.646 6.6 6.6 0 0 1 2.522 3.202 3.48 3.48 0 0 1-.046 2.831 3.39 3.39 0 0 1-3.137 1.97 5.8 5.8 0 0 1-2.32-.522.27.27 0 0 0-.304.054 14 14 0 0 1-1.088.912.294.294 0 0 0 .039.495 7.7 7.7 0 0 0 3.313.84l.192.002a5.66 5.66 0 0 0 4.886-2.948 6.39 6.39 0 0 0-1.243-6.624Z'/><path fill='#f3e5f5' stroke='#f3e5f5' stroke-linejoin='round' stroke-width='.293' d='m17.249 24.295.123-.01-.123.02a1.705 1.705 0 0 0 1.67 1.682h.053a1.715 1.715 0 0 0 1.64-1.778 1.78 1.78 0 0 0-.507-1.224 1.6 1.6 0 0 0-1.187-.493h-.076a9.6 9.6 0 0 1-1.154-5.448 6.83 6.83 0 0 1 1.39-3.853 3.97 3.97 0 0 1 2.842-1.363h.055c2.438 0 3.415 3.34 3.477 4.491a.29.29 0 0 0 .216.265c.299.073.822.246 1.213.384a.27.27 0 0 0 .266-.048.3.3 0 0 0 .105-.247C26.928 12.088 24.204 10 21.804 10a5.96 5.96 0 0 0-5.36 4.39 11.38 11.38 0 0 0 .936 9.155 1.5 1.5 0 0 0-.131.75Z'/></svg>",
|
||||
@ -622,6 +630,8 @@
|
||||
"folder-scala": "<svg viewBox='0 0 32 32'><path fill='#f44336' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#ffcdd2' d='M18 26v4c2.281-.781 8.713-1.025 10-2v-4c-1.287.975-7.719 1.219-10 2m0-6v4c2.281-.781 8.713-1.025 10-2v-4c-1.287.975-7.719 1.219-10 2m0-6v4c2.281-.781 8.713-1.025 10-2v-4c-1.287.975-7.719 1.219-10 2'/></svg>",
|
||||
"folder-scons-open": "<svg viewBox='0 0 32 32'><path fill='#ef5350' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#ffcdd2' d='M12 24h8v4h-8Zm12 0h8v4h-8Zm-12-6h4v4h-4Zm16 0h4v4h-4Zm-10-8h8v4h-8Zm4 14-4-4h2v-4h4v4h2Z'/></svg>",
|
||||
"folder-scons": "<svg viewBox='0 0 32 32'><path fill='#ef5350' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124c-.468 0-.921-.164-1.28-.464'/><path fill='#ffcdd2' d='M12 24h8v4h-8Zm12 0h8v4h-8Zm-12-6h4v4h-4Zm16 0h4v4h-4Zm-10-8h8v4h-8Zm4 14-4-4h2v-4h4v4h2Z'/></svg>",
|
||||
"folder-scrap-open.clone": "<svg fill-rule='evenodd' clip-rule='evenodd' image-rendering='optimizeQuality' shape-rendering='geometricPrecision' text-rendering='geometricPrecision' viewBox='0 0 512 512'><path fill='#616161' d='M463.47 192H151.06c-13.77 0-26 8.82-30.35 21.89L64 384V160h384c0-17.67-14.33-32-32-32H241.98a32 32 0 0 1-20.48-7.42l-20.6-17.15c-5.75-4.8-13-7.43-20.48-7.43H64c-17.67 0-32 14.33-32 32v256c0 17.67 14.33 32 32 32h352l76.88-179.39c1.7-3.98 2.59-8.28 2.59-12.61 0-17.67-14.33-32-32-32'/><path fill='#bdbdbd' d='M320 160v32h-96v32h32v192c0 17.63 14.38 32 32 32h160c17.63 0 32-14.37 32-32V224h32v-32h-96v-32zm0 96v128h32V256zm64 0v128h32V256z'/></svg>",
|
||||
"folder-scrap.clone": "<svg fill-rule='evenodd' clip-rule='evenodd' image-rendering='optimizeQuality' shape-rendering='geometricPrecision' text-rendering='geometricPrecision' viewBox='0 0 512 512'><path fill='#616161' d='m221.5 120.58-20.6-17.16A32 32 0 0 0 180.42 96H64c-17.67 0-32 14.33-32 32v256c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32V160c0-17.67-14.33-32-32-32H241.98a32 32 0 0 1-20.48-7.42'/><path fill='#bdbdbd' d='M320 160v32h-96v32h32v192c0 17.63 14.38 32 32 32h160c17.63 0 32-14.37 32-32V224h32v-32h-96v-32zm0 96v128h32V256zm64 0v128h32V256z'/></svg>",
|
||||
"folder-scripts-open": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#cfd8dc' d='M28 12h-6a4 4 0 0 0-4 4v8h2v-8h8v9.893a2.074 2.074 0 0 1-1.664 2.08A2 2 0 0 1 24 26h-8a4 4 0 0 0 4 4h6a4 4 0 0 0 4-4V16h2a4 4 0 0 0-4-4'/></svg>",
|
||||
"folder-scripts": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#cfd8dc' d='M28 12h-6a4 4 0 0 0-4 4v8h2v-8h8v9.893a2.074 2.074 0 0 1-1.664 2.08A2 2 0 0 1 24 26h-8a4 4 0 0 0 4 4h6a4 4 0 0 0 4-4V16h2a4 4 0 0 0-4-4'/></svg>",
|
||||
"folder-secure-open": "<svg viewBox='0 0 32 32'><path fill='#f9a825' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#fff9c4' d='M28 16v-3.828a4.116 4.116 0 0 0-3.607-4.153A4 4 0 0 0 20 12v4h-2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8a2 2 0 0 0-2-2Zm-4 8a2 2 0 1 1 2-2 2 2 0 0 1-2 2m2-8h-4v-4a2 2 0 0 1 4 0Z'/></svg>",
|
||||
@ -638,6 +648,8 @@
|
||||
"folder-shared": "<svg viewBox='0 0 32 32'><path fill='#ab47bc' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#e1bee7' d='M28 26a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2H18a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h-4v2h18v-2Zm-5-6v-2l4 2.798L23 24v-2a4.12 4.12 0 0 0-4 2c.448-2.003.888-3.595 4-4'/></svg>",
|
||||
"folder-simulations-open": "<svg viewBox='0 0 32 32'><path fill='#ab47bc' d='M28.965 12H9.441a2 2 0 0 0-1.898 1.368L4 24V10h23.998a2 2 0 0 0-2-2H15.122a2 2 0 0 1-1.28-.464l-1.287-1.072A2 2 0 0 0 11.275 6H3.999a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h21.998l4.805-11.212A2 2 0 0 0 28.964 12'/><path fill='#e1bee7' d='m24.029 28.172-1.474-3.447c1.417-.523 2.733-1.225 3.97-2.044zm-6.749-8.723-3.448-1.466 5.501-2.493a18.6 18.6 0 0 0-2.053 3.96m14.383-9.1s-4.458-1.907-9.55 3.187c-1.974 1.97-3.154 4.14-3.914 6.04a1.79 1.79 0 0 0 .409 1.916l1.916 1.908c.5.504 1.237.666 1.906.414a17.2 17.2 0 0 0 6.046-3.914c5.093-5.095 3.187-9.55 3.187-9.55m-6.374 6.363a1.82 1.82 0 0 1 0-2.547 1.81 1.81 0 0 1 2.552 0 1.81 1.81 0 0 1 0 2.547 1.81 1.81 0 0 1-2.552 0m-5.093 6.364-1.26-1.27zm-2.371 4.923 3.278-3.276a2.8 2.8 0 0 1-.873-.406l-3.675 3.682zm-3.811 0h1.259l4.299-4.284-1.282-1.27-4.276 4.285zm0-2.548 3.675-3.671a2.6 2.6 0 0 1-.408-.874l-3.267 3.277z'/></svg>",
|
||||
"folder-simulations": "<svg viewBox='0 0 32 32'><path fill='#ab47bc' d='m13.843 7.537-1.287-1.073A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h23.998A2 2 0 0 0 30 24V10a2 2 0 0 0-2-2.001H15.122a2 2 0 0 1-1.28-.463'/><path fill='#e1bee7' d='m24.029 28.172-1.474-3.447c1.417-.523 2.733-1.225 3.97-2.044zm-6.749-8.723-3.448-1.466 5.501-2.493a18.6 18.6 0 0 0-2.053 3.96m14.383-9.1s-4.458-1.907-9.55 3.187c-1.974 1.97-3.154 4.14-3.914 6.04a1.79 1.79 0 0 0 .409 1.916l1.916 1.908c.5.504 1.237.666 1.906.414a17.2 17.2 0 0 0 6.046-3.914c5.093-5.095 3.187-9.55 3.187-9.55m-6.374 6.363a1.82 1.82 0 0 1 0-2.547 1.81 1.81 0 0 1 2.552 0 1.81 1.81 0 0 1 0 2.547 1.81 1.81 0 0 1-2.552 0m-5.093 6.364-1.26-1.27zm-2.371 4.923 3.278-3.276a2.8 2.8 0 0 1-.873-.406l-3.675 3.682zm-3.811 0h1.259l4.299-4.284-1.282-1.27-4.276 4.285zm0-2.548 3.675-3.671a2.6 2.6 0 0 1-.408-.874l-3.267 3.277z'/></svg>",
|
||||
"folder-skills-open": "<svg viewBox='0 0 32 32'><path fill='#ff8f00' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#ffecb3' d='M24 26v2h4v-2zm0-16-4 4v4l2 2v2l2 2h4l2-2v-2l2-2v-4l-4-4-2 2v2l-2 2h-2v-2l2-2h2l2-2z'/></svg>",
|
||||
"folder-skills": "<svg viewBox='0 0 32 32'><path fill='#ff8f00' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#ffecb3' d='M24 26v2h4v-2zm0-16-4 4v4l2 2v2l2 2h4l2-2v-2l2-2v-4l-4-4-2 2v2l-2 2h-2v-2l2-2h2l2-2z'/></svg>",
|
||||
"folder-snapcraft-open": "<svg viewBox='0 0 16 16'><path fill='#66bb6a' d='M14.033 6H4.597a.97.97 0 0 0-.918.684L2 12V5h11.566c0-.552-.433-1-.967-1H7.343a.95.95 0 0 1-.619-.232l-.622-.536A.95.95 0 0 0 5.483 3H1.967C1.433 3 1 3.448 1 4v8c0 .552.433 1 .967 1h10.632l2.323-5.606c.273-.66-.195-1.394-.889-1.394'/><path fill='#dcedc8' d='m12.538 7.077 2.077 1.038-2.077 2.077zM8.385 14l3.807-3.462-1.73-1.73zM7 5l5.192 5.192V7.077zm8.654 2.077-3.116-.346L16 8.46z'/></svg>",
|
||||
"folder-snapcraft": "<svg viewBox='0 0 16 16'><path fill='#66bb6a' d='m6.922 3.768-.644-.536A1 1 0 0 0 5.638 3H2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H7.562a1 1 0 0 1-.64-.232'/><path fill='#dcedc8' d='m12.538 7.077 2.077 1.038-2.077 2.077zM8.385 14l3.807-3.462-1.73-1.73zM7 5l5.192 5.192V7.077zm8.654 2.077-3.116-.346L16 8.46z'/></svg>",
|
||||
"folder-snippet-open": "<svg viewBox='0 0 32 32'><path fill='#ff9800' d='M29 12H9.4a2 2 0 0 0-1.9 1.4L4 24V10h24a2 2 0 0 0-2-2H15.1a2 2 0 0 1-1.3-.5l-1.2-1a2 2 0 0 0-1.3-.5H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.8-11.2A2 2 0 0 0 29 12'/><path fill='#ffe0b2' d='M20 10s-2 1.86-2 4 6 8 6 8l-.89.88a3 3 0 0 0-5.1 2A3.01 3.01 0 0 0 20.87 28a3.02 3.02 0 0 0 3.11-3.24L26 23.5l.25.31A3.02 3.02 0 0 0 28.88 28 3.01 3.01 0 0 0 32 25.12a3.01 3.01 0 0 0-4.38-2.78zm10 0-4 8 2 2s4-3.94 4-6-2-4-2-4m-9.06 14h.1c.51.02.9.4.95.89v.2a.98.98 0 0 1-1.03.91.99.99 0 0 1-.96-1.04.98.98 0 0 1 .94-.96m8 0h.1c.56.02.98.48.96 1.04a.98.98 0 0 1-1.04.96.98.98 0 0 1-.96-1.04.98.98 0 0 1 .94-.96' style='-inkscape-stroke:none'/></svg>",
|
||||
@ -808,6 +820,7 @@
|
||||
"image": "<svg viewBox='0 0 16 16'><path fill='#26a69a' d='M8.5 6h4l-4-4zM3.875 1H9.5l4 4v8.6c0 .773-.616 1.4-1.375 1.4h-8.25c-.76 0-1.375-.627-1.375-1.4V2.4c0-.777.612-1.4 1.375-1.4M4 13.6h8V8l-2.625 2.8L8 9.4zm1.25-7.7c-.76 0-1.375.627-1.375 1.4s.616 1.4 1.375 1.4c.76 0 1.375-.627 1.375-1.4S6.009 5.9 5.25 5.9'/></svg>",
|
||||
"imba": "<svg stroke-linejoin='round' stroke-miterlimit='1.414' clip-rule='evenodd' viewBox='0 0 201 201'><path fill='#ffc400' d='M161.96 61.952c-3.043 13.905-32.633 79.576-36.431 94.457-2.698 10.575 11.229 23.851 13.555 15.159 6.84-25.548 37.32-86.251 39.023-98.893 1.468-10.897-14.66-17.516-16.147-10.723m-37.128 48.192a4.97 4.97 0 0 1 5.726 6.91c.023.012.021.015.021.016a19.04 19.04 0 0 1-13.667 10.676c-3.4.645-7.236 1.182-11.504 1.588-15.316 1.453-31.743-17.007-20.624-16.49 16.552.77 29.747-.447 40.047-2.7zm16.256-17.347a13.36 13.36 0 0 1-9.677 8.152c-20.232 4.242-49.32 2.59-63.662-.888-13.94-3.38-23.102-23.665-14.05-20.64 21.019 7.024 60.118 9.347 82.248 6.838a4.808 4.808 0 0 1 5.133 6.523c.011.004.011.004.008.015m8.398-23.8a11.39 11.39 0 0 1-9.973 8.037c-40.633 2.924-92.83-6.466-107.91-22.019C20.273 43.326 21 20.85 27.442 27.992c24.417 27.072 84.437 34.865 117.12 34.521a5.022 5.022 0 0 1 4.92 6.481q.003.002.001.003z'/></svg>",
|
||||
"installation": "<svg viewBox='0 0 16 16'><path fill='#ff5722' d='M12 7h-2V2H6v5H4l4 4zm-9 5.5V14h10v-1.5z'/></svg>",
|
||||
"instructions.clone": "<svg fill='none' viewBox='0 0 24 24'><path d='M0 0h24v24H0z'/><path fill='#00b8d4' d='M4 6H2v14c0 1.1.9 2 2 2h14v-2H4zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2m0 14H8V4h12zM10 9h8v2h-8zm0 3h4v2h-4zm0-6h8v2h-8z'/></svg>",
|
||||
"ionic": "<svg viewBox='0 0 512 512'><g fill='#448aff'><path d='M423.59 132.8a31.86 31.86 0 0 0 5.408-17.804c0-17.675-14.33-32-32-32a31.85 31.85 0 0 0-17.805 5.409c-34.486-25.394-77.085-40.409-123.2-40.409-114.88 0-208 93.125-208 208 0 114.88 93.125 208 208 208 114.87 0 208-93.123 208-208 0-46.111-15.016-88.71-40.408-123.2zm-31.762 259.03c-17.646 17.646-38.191 31.499-61.064 41.174-23.672 10.012-48.826 15.089-74.766 15.089s-51.095-5.077-74.767-15.089c-22.873-9.675-43.417-23.527-61.064-41.174s-31.5-38.191-41.174-61.064c-10.013-23.672-15.09-48.828-15.09-74.768s5.077-51.095 15.089-74.767c9.674-22.873 23.527-43.417 41.174-61.064s38.191-31.5 61.064-41.174c23.673-10.013 48.828-15.09 74.768-15.09s51.094 5.077 74.766 15.089a191.2 191.2 0 0 1 37.802 21.327 31.85 31.85 0 0 0-3.568 14.679c0 17.675 14.327 32 32 32 5.293 0 10.28-1.293 14.678-3.568a191 191 0 0 1 21.327 37.801c10.013 23.672 15.09 48.827 15.09 74.767s-5.077 51.096-15.09 74.768c-9.675 22.873-23.527 43.418-41.175 61.064'/><circle cx='256' cy='256' r='96'/></g></svg>",
|
||||
"istanbul": "<svg viewBox='0 0 32 32'><path fill='#fdd835' d='M30 13v-3h-2v3h-1v.5a.5.5 0 0 0 .5.5h.5v10h-1v-2h-1v-8h-1v6h-2v-3h-1v1h-1v-1h1a6.35 6.35 0 0 0-6-4 6.35 6.35 0 0 0-6 4h1v1h-1v-1H9v3H7v-6H6v8H5v2H4V14h.5a.5.5 0 0 0 .5-.5V13H4v-3H2v3H1v.5a.5.5 0 0 0 .5.5H2v12h8v-6h2v6h8v-6h2v6h8V14h.5a.5.5 0 0 0 .5-.5V13ZM14 24h-1v-2h1Zm3 0h-2v-2a1 1 0 0 1 2 0Zm2 0h-1v-2h1Zm-1-7v1h-1v-1Zm-3 0v1h-1v-1Zm-3 0h1v1h-1Zm7 1v-1h1v1ZM3 6 2 9h2zm26 0-1 3h2z'/><path fill='#fdd835' d='m16 10-1 2h2zm9.5 1-.5 2h1zm-19 0L6 13h1z'/></svg>",
|
||||
"jar": "<svg viewBox='0 0 32 32'><path fill='#f44336' d='M22 10h2v4h-2z'/><path fill='#f44336' d='M28 2H4a2 2 0 0 0-2 2v24a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2m-2 12a2 2 0 0 1-2 2h-2v4a4 4 0 0 1-4 4h-8a4 4 0 0 1-4-4V8h18a2 2 0 0 1 2 2Z'/></svg>",
|
||||
@ -821,6 +834,7 @@
|
||||
"jinja_light": "<svg viewBox='0 0 32 32'><path fill='#616161' d='M30 8V4a94.4 94.4 0 0 1-14 1A94.4 94.4 0 0 1 2 4v4s1.482.247 3.95.495L5.4 14H2v2h3.2L4 28h6V16h12v12h6l-1.2-12H30v-2h-3.4l-.55-5.505C28.517 8.247 30 8 30 8m-20 6V8.817c1.235.074 2.576.13 4 .16V14Zm12 0h-4V8.977a104 104 0 0 0 4-.16Z'/></svg>",
|
||||
"jsconfig": "<svg viewBox='0 0 32 32'><path fill='#757575' d='M15 2H6a2.006 2.006 0 0 0-2 2v22a2.006 2.006 0 0 0 2 2h6v-4H6v-2h6v-2H6v-2h6v-2H6v-2h6v-2h2V4l8 8h2v-1Z' data-mit-no-recolor='true'/><path fill='#ffca28' d='M12 12v18h18V12zm8 12a2.006 2.006 0 0 1-2 2h-2a2.006 2.006 0 0 1-2-2v-2h2v2h2v-8h2zm8-6h-4v2h2a2.006 2.006 0 0 1 2 2v2a2.006 2.006 0 0 1-2 2h-4v-2h4v-2h-2a2.006 2.006 0 0 1-2-2v-2a2.006 2.006 0 0 1 2-2h4z'/></svg>",
|
||||
"json": "<svg viewBox='0 -960 960 960'><path fill='#f9a825' d='M560-160v-80h120q17 0 28.5-11.5T720-280v-80q0-38 22-69t58-44v-14q-36-13-58-44t-22-69v-80q0-17-11.5-28.5T680-720H560v-80h120q50 0 85 35t35 85v80q0 17 11.5 28.5T840-560h40v160h-40q-17 0-28.5 11.5T800-360v80q0 50-35 85t-85 35zm-280 0q-50 0-85-35t-35-85v-80q0-17-11.5-28.5T120-400H80v-160h40q17 0 28.5-11.5T160-600v-80q0-50 35-85t85-35h120v80H280q-17 0-28.5 11.5T240-680v80q0 38-22 69t-58 44v14q36 13 58 44t22 69v80q0 17 11.5 28.5T280-240h120v80z'/></svg>",
|
||||
"json_schema": "<svg viewBox='0 -960 960 960'><path fill='#f9a825' d='M560-160v-80h120q17 0 28.5-11.5T720-280v-80q0-38 22-69t58-44v-14q-36-13-58-44t-22-69v-80q0-17-11.5-28.5T680-720H560v-80h120q50 0 85 35t35 85v80q0 17 11.5 28.5T840-560h40v160h-40q-17 0-28.5 11.5T800-360v80q0 50-35 85t-85 35zm-280 0q-50 0-85-35t-35-85v-80q0-17-11.5-28.5T120-400H80v-160h40q17 0 28.5-11.5T160-600v-80q0-50 35-85t85-35h120v80H280q-17 0-28.5 11.5T240-680v80q0 38-22 69t-58 44v14q36 13 58 44t22 69v80q0 17 11.5 28.5T280-240h120v80z'/><path fill='#f9a825' stroke='#f9a825' stroke-width='36.192' d='M581.79-570.48 446.07-434.76l-67.859-67.859-22.62 22.62 90.479 90.479 158.34-158.34z'/></svg>",
|
||||
"jsr": "<svg viewBox='0 0 16 16'><path fill='#fdd835' d='M2 7h1v2h1V5h1v5H2m4-5h4v1H7v1.5h3V11H6v-1h3V8.5H6M11 6h3v2.5h-1V7h-1v4h-1'/></svg>",
|
||||
"jsr_light": "<svg viewBox='0 0 16 16'><path fill='#37474f' d='M1 6h2V4h8v1h4v5h-2v2H5v-1H1'/><path fill='#fdd835' d='M2 7h1v2h1V5h1v5H2m4-5h4v1H7v1.5h3V11H6v-1h3V8.5H6M11 6h3v2.5h-1V7h-1v4h-1'/></svg>",
|
||||
"julia": "<svg viewBox='0 0 50 50'><g transform='translate(.21 -247.01)'><circle cx='13.497' cy='281.63' r='9.555' fill='#c62828'/><circle cx='36.081' cy='281.63' r='9.555' fill='#7e57c2'/><circle cx='24.722' cy='262.39' r='9.555' fill='#388e3c'/></g></svg>",
|
||||
@ -1024,6 +1038,7 @@
|
||||
"robots": "<svg viewBox='0 0 32 32'><path fill='#ff5252' d='M28.586 18H28a8 8 0 0 0-8-8h-2V8.445a4 4 0 1 0-4 0V10h-2a8 8 0 0 0-8 8h-.586A1.414 1.414 0 0 0 2 19.414v3.172A1.414 1.414 0 0 0 3.414 24H4v1a3 3 0 0 0 3 3h18a3 3 0 0 0 3-3v-1h.586A1.414 1.414 0 0 0 30 22.586v-3.172A1.414 1.414 0 0 0 28.586 18M11 22a3 3 0 1 1 3-3 3 3 0 0 1-3 3m10 0a3 3 0 1 1 3-3 3 3 0 0 1-3 3'/></svg>",
|
||||
"rocket": "<svg viewBox='0 0 32 32'><path fill='#ef5350' d='M12 26c-1.71 1.905-7.64 2.149-7.93 1.937l-.004.003-.002-.005-.005-.002.004-.003C3.85 27.64 4.1 21.715 6 20ZM29.64 7.908c-.655 2.69-1.681 5.64-5.64 10.092l-.789 4.749a4 4 0 0 1-1.116 2.171l-4.863 4.868A.72.72 0 0 1 16 29.277v-6.23L9 16H2.723a.721.721 0 0 1-.511-1.232L7.08 9.905A4 4 0 0 1 9.25 8.79L14 8c4.453-3.959 7.402-4.985 10.092-5.64a11.1 11.1 0 0 1 3.642-.329 3.1 3.1 0 0 1 1.72.515 3.1 3.1 0 0 1 .515 1.72 11.1 11.1 0 0 1-.33 3.642ZM26 10a4 4 0 1 0-4 4 4 4 0 0 0 4-4'/></svg>",
|
||||
"rojo": "<svg fill='none' viewBox='0 0 24 24'><path fill='#e53935' d='M9.586 2h.077l-.077.135v.29c.598-.116.908-.27.908-.425l.425.058A36 36 0 0 1 12.869 2h.077c.927 0 2.009.502 3.284 1.526.27.444.424.83.502 1.197v.695c-.155.966-.425 1.7-.773 2.183q-.319.26-1.39 1.738h-.078v-.135l.194-.29h-.116a17.6 17.6 0 0 1-5.601 3.226 6.2 6.2 0 0 1-1.545.212c.656.772 1.873 1.796 3.63 3.07.174.097 1.295.812 3.361 2.183 1.719 1.062 3.766 2.221 6.161 3.496v.077h-.29c-.463-.174-.695-.309-.695-.367l-.135.077h-.135c-.058 0-.078-.019-.078-.077-.173.039-.309.213-.424.502.29.078.424.174.424.27-.115.097-.193.155-.27.155l-.348-.077v.077c0 .078.058.135.194.135v.213h-.058c-.097 0-1.16-.618-3.148-1.835-1.41-.715-3.149-1.815-5.176-3.283-.676-.31-1.912-1.217-3.728-2.723h-.193c-.27.405-.618 1.41-1.062 3.013-.097.367-.56.907-1.39 1.602h-.155l-.135-.212v-.077c0-.097.077-.31.212-.618v-.077h-.077c0 .135-.29.347-.83.637H3v-.135c1.642-4.867 2.781-8.035 3.438-9.522q1.68-3.852 1.68-4.403c-.251 0-.811.309-1.68.965h-.135l.058-.135v-.135c-.252 0-.831.406-1.739 1.255h-.077v-.077l.908-1.043.154-.212v-.077h-.154l-.83.695c-.097 0-.136-.039-.136-.116A11.1 11.1 0 0 1 7.693 3.12c1.178-.309 1.758-.656 1.758-1.062zm6.373 1.95v.078c0 .077.058.135.135.135v-.077c0-.077-.038-.135-.135-.135M7.77 10.673h.058c.85-.174 1.275-.31 1.275-.425-.058-.097-.077-.155-.077-.213C10.803 9.436 12 8.837 12.599 8.22c.058 0 .425-.386 1.12-1.198h.077V7.1c-.096.154-.154.27-.154.347h.077c.599-.463.908-.965.908-1.525v-.425c-.136 0-.213-.058-.213-.155q.348-.057.348-.347 0-.348-1.39-.696c-.754-.193-1.565-.27-2.453-.27-.445 0-.889.811-1.333 2.453-.193.193-.792 1.583-1.816 4.19m.83-5.949V4.8c.078 0 .136-.077.213-.212v-.077c-.058 0-.135.077-.212.212m.078 1.333h.077c.136-.058.213-.193.213-.425-.077 0-.174.135-.29.425m6.586.27v.155c.058 0 .135-.078.193-.213v-.077H15.4c-.096.02-.135.058-.135.135m-7.57 4.693v.078h.134a.5.5 0 0 1 .213-.078v.078c1.14-.213 1.815-.445 2.047-.696h-.077c-1.024.232-1.796.444-2.318.618m-.271.696h.058l1.274-.27-.077-.136c-.83.097-1.255.251-1.255.406m2.78 4.345v.135c.735.56 1.179.85 1.334.85-.174-.135-.27-.251-.27-.348zm2.048 1.545c.039.174.174.27.406.27h.077v-.077c-.116 0-.251-.058-.425-.193zm4.539 2.51q.55.495 1.68.986l.077-.135c-.58-.348-1.12-.638-1.603-.85zm3.862 1.121h.213c.077.02.135.058.135.135-.097 0-.135.078-.135.213h-.155l.078-.136v-.077h-.136z'/></svg>",
|
||||
"rolldown": "<svg fill='none' viewBox='0 0 16 16'><path fill='#f4511e' d='M13.628 1c.3 0 .465.35.272.582l-3.277 3.933c-.385.462-.229 1.485.374 1.485h3.644c.301 0 .465.35.273.582l-6.645 7.29a.355.355 0 0 1-.545 0l-6.64-7.29A.355.355 0 0 1 1.355 7h3.64c.602 0 .759-1.023.373-1.485L2.092 1.582A.355.355 0 0 1 2.364 1z'/></svg>",
|
||||
"rollup": "<svg viewBox='100 100 800 800'><path fill='#f44336' d='M733.79 394.71c0 77.407-42.308 144.79-104.67 180.51-3.76 3.134-5.954 8.148-3.76 12.849l106.87 211.22c2.82 6.581-1.568 14.103-8.776 14.103h-408.35l2.194-1.254c15.356-8.774 121.91-219.06 225.95-318.72 104.05-99.658 117.21-66.439 59.857-174.87 0 0 44.188 86.182 6.581 92.763-29.459 5.328-97.15-60.17-72.08-119.09 25.071-57.664 123.79-46.695 169.23.314 17.236 30.085 26.952 64.872 26.952 102.17m-385.47 140.71c-41.367 76.154-67.692 131.62-82.108 170.48v-509.57c0-5.328 4.388-9.715 9.715-9.715h252.91c73.333 1.253 137.58 40.114 173.62 98.718-26.325-32.906-67.692-51.71-108.43-51.71-77.407 0-96.837 28.206-245.7 301.79z'/></svg>",
|
||||
"rome": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='M9.875 5.409A14.02 14.02 0 0 0 2.01 17.48a.51.51 0 0 0 .508.519H5.52a.495.495 0 0 0 .491-.481 10.01 10.01 0 0 1 5.273-8.337.494.494 0 0 0 .243-.592l-.958-2.882a.505.505 0 0 0-.694-.3Zm11.556.299-.958 2.882a.494.494 0 0 0 .243.592 10.01 10.01 0 0 1 5.273 8.337.495.495 0 0 0 .49.481h3.004a.51.51 0 0 0 .508-.519A14.02 14.02 0 0 0 22.125 5.41a.505.505 0 0 0-.694.299ZM26 20.5v9a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-9a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5m-24 0v9a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-9a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5'/><path fill='#ffc400' d='M16.13 10h-.26A7.87 7.87 0 0 0 8 17.87V29.5a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5V17.87A3.88 3.88 0 0 1 15.87 14h.26A3.88 3.88 0 0 1 20 17.87V29.5a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5V17.87A7.87 7.87 0 0 0 16.13 10m1.51-2h-3.28a.5.5 0 0 1-.474-.342l-1.667-5A.5.5 0 0 1 12.694 2h6.612a.5.5 0 0 1 .475.658l-1.667 5A.5.5 0 0 1 17.64 8'/></svg>",
|
||||
"routing": "<svg viewBox='0 0 32 32'><path fill='#43a047' d='M18 14v-2h8l2-3-2-3h-8V4l-2-2-2 2v6H6l-2 3 2 3h8v10a4 4 0 0 0-4 4h12a4 4 0 0 0-4-4v-6h8l2-3-2-3Z'/></svg>",
|
||||
@ -1060,6 +1075,7 @@
|
||||
"simulink": "<svg viewBox='0 0 4.233 4.233'><path fill='#9e9e9e' d='M.53 1.323v.264h2.38v.794h.265V1.323z'/><path fill='#ff6e40' d='M2.381 2.381h1.323v1.323H2.381z'/><path fill='#64b5f6' d='m2.381 1.455-1.587.926V.53z'/></svg>",
|
||||
"siyuan": "<svg viewBox='0 0 32 32'><path fill='#e53935' d='M2 11.976 10 4v16l-8 8Z'/><path fill='#455a64' d='M30 11.976 22 4v15.99L30 28ZM10 4l6 6v16l-6-6Z'/><path fill='#e53935' d='m22 4-6 6v16l6-6.01Z'/></svg>",
|
||||
"sketch": "<svg viewBox='0 0 24 24'><path fill='#ffc107' d='M15.705 9.221h2.779l-4.632 6.484m-3.705-6.484h3.705L12 16.631m-6.484-7.41h2.779l1.852 6.484M14.78 4.59h1.852l1.853 2.779h-2.78m-4.63-2.779h1.852l.926 2.779h-3.705M7.368 4.59h1.853l-.926 2.78h-2.78m.927-4.631L2.737 8.294 12 21.263l9.262-12.968-3.705-5.557z'/></svg>",
|
||||
"skill": "<svg viewBox='0 0 16 16'><path fill='#ff8f00' d='M6 12v1h4v-1zm1 2v1h2v-1zM7 1 5 2 4 4v2l1 2 1 1v1l1 1h2l1-1V9l1-1 1-2V4l-1-2-2-1v2L7 5H6V4l2-2h1v1-2z'/></svg>",
|
||||
"slim": "<svg viewBox='0 0 32 32'><path fill='#f57f17' d='M23 2H9a7 7 0 0 0-7 7v14a7 7 0 0 0 7 7h14a7 7 0 0 0 7-7V9a7 7 0 0 0-7-7m-5 14-4-6v6H6a10 10 0 0 1 20 0Z'/></svg>",
|
||||
"slint": "<svg viewBox='0 0 16 16'><path fill='#2979ff' d='M12 1 3 7l5 2-2-2Z'/><path fill='#2979ff' d='m4 15 9-6-5-2 2 2Z'/></svg>",
|
||||
"slug": "<svg viewBox='0 0 24 24'><path fill='#f9a825' d='m9.164 21.221-.983-.056c-3.402-.19-5.654-.714-6.125-1.427-.136-.205-.146-.515-.022-.681.115-.154.377-.28.744-.355l.313-.064.373.122c1.568.517 2.903.589 4.875.263.82-.135 1.26-.29 1.736-.613.183-.124.26-.152.413-.152.62-.002 1.581-.168 2.066-.357 1.392-.544 2.655-2.023 2.979-3.49.159-.717.072-1.83-.211-2.693l-.13-.397.028-.747c.023-.606.047-.818.126-1.123.29-1.108.991-1.878 1.957-2.145.374-.103 1.17-.093 1.589.02a3.34 3.34 0 0 1 1.595.941c.505.548.707 1.025.735 1.738.021.55-.034.809-.283 1.316-.211.43-.542.833-.909 1.107-.15.113-.302.23-.336.26-.052.046-.067.192-.087.837-.014.43-.053.986-.086 1.235-.458 3.354-2.234 5.421-5.307 6.174-1.023.25-1.37.283-3.183.292-.908.005-1.748.002-1.867-.005m-3.967-2.877-.45-.07-.3-.322c-1.514-1.613-2.085-4.002-1.43-5.98.646-1.953 2.32-3.39 4.496-3.86.557-.121 1.912-.133 2.437-.023a6.7 6.7 0 0 1 1.631.56c1.828.904 2.982 2.495 3.205 4.421.111.955-.13 1.793-.763 2.651-.712.966-1.618 1.525-2.681 1.654l-.233.028.267-.277c.475-.495.596-.93.596-2.15 0-.683-.011-.831-.087-1.134-.182-.721-.476-1.239-.967-1.705-.643-.611-1.44-.923-2.349-.92-1.295.005-2.196.828-2.196 2.006 0 .398.069.695.24 1.033.135.269.446.62.68.769.368.233.984.35 1.195.225a.387.387 0 0 0 .096-.61c-.09-.101-.15-.126-.364-.154-.337-.043-.437-.086-.642-.275-.26-.239-.395-.57-.397-.964-.002-.269.014-.348.11-.543.133-.27.396-.497.703-.603.327-.114.98-.096 1.386.038.854.281 1.456.918 1.699 1.797.054.196.07.401.07.903 0 .57-.011.683-.092.941-.103.327-.31.758-.488 1.019-.295.429-.853.927-1.283 1.144-.691.348-2.98.573-4.09.4zM19.199 6.578l-.244-.078.14-.4c.537-1.544 1.334-2.521 2.057-2.521.567 0 1.043.588.862 1.067-.045.12-.244.345-.37.419-.044.025-.31.054-.597.065-.497.019-.524.024-.688.139-.221.154-.503.575-.69 1.03-.081.2-.166.361-.188.36a3 3 0 0 1-.282-.081m-2.185-.06c-.068-.115-.127-.837-.126-1.545.001-.639.015-.863.07-1.08.194-.765.529-1.121 1.055-1.121.588 0 .932.42.782.957-.072.258-.183.365-.591.568-.312.155-.394.216-.496.369-.176.262-.228.59-.2 1.253l.023.538-.165.027c-.09.014-.202.035-.249.047s-.092.006-.103-.012z'/></svg>",
|
||||
|
||||
@ -213,6 +213,9 @@
|
||||
"editor.buttons.switch_to_legacy.tooltip": "Use the legacy editor instead",
|
||||
"editor.buttons.enable_monospace_font": "Enable monospace font",
|
||||
"editor.buttons.disable_monospace_font": "Disable monospace font",
|
||||
"editor.code_editor.command_palette": "Command Palette",
|
||||
"editor.code_editor.find": "Find",
|
||||
"editor.code_editor.placeholder": "Enter file content here",
|
||||
"filter.string.asc": "A–Z",
|
||||
"filter.string.desc": "Z–A",
|
||||
"error.occurred": "An error occurred",
|
||||
@ -2250,13 +2253,14 @@
|
||||
"repo.settings.webhook.delivery.success": "An event has been added to the delivery queue. It may take few seconds before it shows up in the delivery history.",
|
||||
"repo.settings.githooks_desc": "Git Hooks are powered by Git itself. You can edit hook files below to set up custom operations.",
|
||||
"repo.settings.githook_edit_desc": "If the hook is inactive, sample content will be presented. Leaving content to an empty value will disable this hook.",
|
||||
"repo.settings.githook_name": "Hook Name",
|
||||
"repo.settings.githook_content": "Hook Content",
|
||||
"repo.settings.update_githook": "Update Hook",
|
||||
"repo.settings.add_webhook_desc": "Gitea will send <code>POST</code> requests with a specified content type to the target URL. Read more in the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"%s\">webhooks guide</a>.",
|
||||
"repo.settings.payload_url": "Target URL",
|
||||
"repo.settings.http_method": "HTTP Method",
|
||||
"repo.settings.content_type": "POST Content Type",
|
||||
"repo.settings.webhook.name": "Webhook name",
|
||||
"repo.settings.webhook.name_helper": "Optionally give this webhook a friendly name",
|
||||
"repo.settings.webhook.name_empty": "Unnamed Webhook",
|
||||
"repo.settings.secret": "Secret",
|
||||
"repo.settings.webhook_secret_desc": "If the webhook server supports using secret, you can follow the webhook's manual and fill in a secret here.",
|
||||
"repo.settings.slack_username": "Username",
|
||||
@ -2778,9 +2782,9 @@
|
||||
"org.settings.labels_desc": "Add labels which can be used on issues for <strong>all repositories</strong> under this organization.",
|
||||
"org.members.membership_visibility": "Membership Visibility:",
|
||||
"org.members.public": "Visible",
|
||||
"org.members.public_helper": "make hidden",
|
||||
"org.members.public_helper": "Make hidden",
|
||||
"org.members.private": "Hidden",
|
||||
"org.members.private_helper": "make visible",
|
||||
"org.members.private_helper": "Make visible",
|
||||
"org.members.member_role": "Member Role:",
|
||||
"org.members.owner": "Owner",
|
||||
"org.members.member": "Member",
|
||||
@ -2808,7 +2812,10 @@
|
||||
"org.teams.no_desc": "This team has no description",
|
||||
"org.teams.settings": "Settings",
|
||||
"org.teams.owners_permission_desc": "Owners have full access to <strong>all repositories</strong> and have <strong>administrator access</strong> to the organization.",
|
||||
"org.teams.owners_permission_suggestion": "You can create new teams for members to get fine-grained access control.",
|
||||
"org.teams.members": "Team Members",
|
||||
"org.teams.manage_team_member": "Manage teams and members",
|
||||
"org.teams.manage_team_member_prompt": "Members are managed through teams. Add users to a team to invite them to this organization.",
|
||||
"org.teams.update_settings": "Update Settings",
|
||||
"org.teams.delete_team": "Delete Team",
|
||||
"org.teams.add_team_member": "Add Team Member",
|
||||
@ -3715,6 +3722,8 @@
|
||||
"actions.runs.workflow_run_count_1": "%d workflow run",
|
||||
"actions.runs.workflow_run_count_n": "%d workflow runs",
|
||||
"actions.runs.commit": "Commit",
|
||||
"actions.runs.run_details": "Run Details",
|
||||
"actions.runs.workflow_file": "Workflow file",
|
||||
"actions.runs.scheduled": "Scheduled",
|
||||
"actions.runs.pushed_by": "pushed by",
|
||||
"actions.runs.invalid_workflow_helper": "Workflow config file is invalid. Please check your config file: %s",
|
||||
|
||||
44
package.json
44
package.json
@ -2,7 +2,7 @@
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@10.33.0",
|
||||
"engines": {
|
||||
"node": ">= 22.6.0",
|
||||
"node": ">= 22.18.0",
|
||||
"pnpm": ">= 10.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -10,12 +10,28 @@
|
||||
"@citation-js/plugin-bibtex": "0.7.21",
|
||||
"@citation-js/plugin-csl": "0.7.22",
|
||||
"@citation-js/plugin-software-formats": "0.6.2",
|
||||
"@codemirror/autocomplete": "6.20.1",
|
||||
"@codemirror/commands": "6.10.3",
|
||||
"@codemirror/lang-json": "6.0.2",
|
||||
"@codemirror/lang-markdown": "6.5.0",
|
||||
"@codemirror/language": "6.12.3",
|
||||
"@codemirror/language-data": "6.5.2",
|
||||
"@codemirror/legacy-modes": "6.5.2",
|
||||
"@codemirror/lint": "6.9.5",
|
||||
"@codemirror/search": "6.6.0",
|
||||
"@codemirror/state": "6.6.0",
|
||||
"@codemirror/view": "6.41.0",
|
||||
"@github/markdown-toolbar-element": "2.2.3",
|
||||
"@github/paste-markdown": "1.5.3",
|
||||
"@github/text-expander-element": "2.9.4",
|
||||
"@lezer/highlight": "1.2.3",
|
||||
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
|
||||
"@mermaid-js/layout-elk": "0.2.1",
|
||||
"@primer/octicons": "19.23.1",
|
||||
"@replit/codemirror-indentation-markers": "6.5.3",
|
||||
"@replit/codemirror-lang-nix": "6.0.1",
|
||||
"@replit/codemirror-lang-svelte": "6.0.0",
|
||||
"@replit/codemirror-vscode-keymap": "6.0.2",
|
||||
"@resvg/resvg-wasm": "2.6.2",
|
||||
"@silverwind/vue3-calendar-heatmap": "2.1.1",
|
||||
"@vitejs/plugin-vue": "6.0.5",
|
||||
@ -25,6 +41,7 @@
|
||||
"chartjs-adapter-dayjs-4": "1.0.4",
|
||||
"chartjs-plugin-zoom": "2.2.0",
|
||||
"clippie": "4.1.10",
|
||||
"codemirror-lang-elixir": "4.0.1",
|
||||
"colord": "2.9.3",
|
||||
"compare-versions": "6.1.1",
|
||||
"cropperjs": "1.6.2",
|
||||
@ -36,9 +53,8 @@
|
||||
"idiomorph": "0.7.4",
|
||||
"jquery": "4.0.0",
|
||||
"js-yaml": "4.1.1",
|
||||
"katex": "0.16.43",
|
||||
"mermaid": "11.13.0",
|
||||
"monaco-editor": "0.55.1",
|
||||
"katex": "0.16.44",
|
||||
"mermaid": "11.14.0",
|
||||
"online-3d-viewer": "0.18.0",
|
||||
"pdfobject": "2.3.1",
|
||||
"perfect-debounce": "2.1.0",
|
||||
@ -63,9 +79,9 @@
|
||||
"devDependencies": {
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "4.7.1",
|
||||
"@eslint/json": "1.2.0",
|
||||
"@playwright/test": "1.58.2",
|
||||
"@playwright/test": "1.59.0",
|
||||
"@stylistic/eslint-plugin": "5.10.0",
|
||||
"@stylistic/stylelint-plugin": "5.0.1",
|
||||
"@stylistic/stylelint-plugin": "5.1.0",
|
||||
"@types/codemirror": "5.60.17",
|
||||
"@types/dropzone": "5.7.9",
|
||||
"@types/jquery": "4.0.0",
|
||||
@ -77,9 +93,9 @@
|
||||
"@types/swagger-ui-dist": "3.30.6",
|
||||
"@types/throttle-debounce": "5.0.2",
|
||||
"@types/toastify-js": "1.12.4",
|
||||
"@typescript-eslint/parser": "8.57.2",
|
||||
"@typescript-eslint/parser": "8.58.0",
|
||||
"@vitejs/plugin-vue": "6.0.5",
|
||||
"@vitest/eslint-plugin": "1.6.13",
|
||||
"@vitest/eslint-plugin": "1.6.14",
|
||||
"eslint": "10.1.0",
|
||||
"eslint-import-resolver-typescript": "4.4.4",
|
||||
"eslint-plugin-array-func": "5.1.1",
|
||||
@ -89,15 +105,15 @@
|
||||
"eslint-plugin-playwright": "2.10.1",
|
||||
"eslint-plugin-regexp": "3.1.0",
|
||||
"eslint-plugin-sonarjs": "4.0.2",
|
||||
"eslint-plugin-unicorn": "63.0.0",
|
||||
"eslint-plugin-unicorn": "64.0.0",
|
||||
"eslint-plugin-vue": "10.8.0",
|
||||
"eslint-plugin-vue-scoped-css": "3.0.0",
|
||||
"eslint-plugin-wc": "3.1.0",
|
||||
"globals": "17.4.0",
|
||||
"happy-dom": "20.8.8",
|
||||
"happy-dom": "20.8.9",
|
||||
"jiti": "2.6.1",
|
||||
"markdownlint-cli": "0.48.0",
|
||||
"material-icon-theme": "5.32.0",
|
||||
"material-icon-theme": "5.33.1",
|
||||
"nolyfill": "1.0.44",
|
||||
"postcss-html": "1.8.1",
|
||||
"spectral-cli-bundle": "1.0.7",
|
||||
@ -107,9 +123,9 @@
|
||||
"stylelint-declaration-strict-value": "1.11.1",
|
||||
"stylelint-value-no-unknown-custom-properties": "6.1.1",
|
||||
"svgo": "4.0.1",
|
||||
"typescript": "5.9.3",
|
||||
"typescript-eslint": "8.57.2",
|
||||
"updates": "17.12.0",
|
||||
"typescript": "6.0.2",
|
||||
"typescript-eslint": "8.58.0",
|
||||
"updates": "17.13.1",
|
||||
"vitest": "4.1.2",
|
||||
"vue-tsc": "3.2.6"
|
||||
},
|
||||
|
||||
@ -1,21 +1,24 @@
|
||||
import {env} from 'node:process';
|
||||
import {defineConfig, devices} from '@playwright/test';
|
||||
|
||||
const timeoutFactor = Number(env.GITEA_TEST_E2E_TIMEOUT_FACTOR) || 1;
|
||||
const timeout = 5000 * timeoutFactor;
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './tests/e2e/',
|
||||
outputDir: './tests/e2e-output/',
|
||||
testMatch: /.*\.test\.ts/,
|
||||
forbidOnly: Boolean(env.CI),
|
||||
reporter: 'list',
|
||||
timeout: env.CI ? 12000 : 6000,
|
||||
timeout: 2 * timeout,
|
||||
expect: {
|
||||
timeout: env.CI ? 6000 : 3000,
|
||||
timeout,
|
||||
},
|
||||
use: {
|
||||
baseURL: env.GITEA_TEST_E2E_URL?.replace?.(/\/$/g, ''),
|
||||
baseURL: env.GITEA_TEST_E2E_URL?.replace?.(/\/$/, ''),
|
||||
locale: 'en-US',
|
||||
actionTimeout: env.CI ? 6000 : 3000,
|
||||
navigationTimeout: env.CI ? 12000 : 6000,
|
||||
actionTimeout: timeout,
|
||||
navigationTimeout: 2 * timeout,
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
|
||||
1674
pnpm-lock.yaml
generated
1674
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -726,6 +726,9 @@ func EditIssue(ctx *context.APIContext) {
|
||||
// swagger:operation PATCH /repos/{owner}/{repo}/issues/{index} issue issueEditIssue
|
||||
// ---
|
||||
// summary: Edit an issue. If using deadline only the date will be taken into account, and time of day ignored.
|
||||
// description: |
|
||||
// Pass `content_version` to enable optimistic locking on body edits.
|
||||
// If the version doesn't match the current value, the request fails with 409 Conflict.
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
@ -785,6 +788,15 @@ func EditIssue(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
// Fail fast: if content_version is provided and already stale, reject
|
||||
// before any mutations. The DB-level check in ChangeContent still
|
||||
// handles concurrent requests.
|
||||
// TODO: wrap all mutations in a transaction to fully prevent partial writes.
|
||||
if form.ContentVersion != nil && *form.ContentVersion != issue.ContentVersion {
|
||||
ctx.APIError(http.StatusConflict, issues_model.ErrIssueAlreadyChanged)
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.Title) > 0 {
|
||||
err = issue_service.ChangeTitle(ctx, issue, ctx.Doer, form.Title)
|
||||
if err != nil {
|
||||
@ -793,10 +805,14 @@ func EditIssue(ctx *context.APIContext) {
|
||||
}
|
||||
}
|
||||
if form.Body != nil {
|
||||
err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body, issue.ContentVersion)
|
||||
contentVersion := issue.ContentVersion
|
||||
if form.ContentVersion != nil {
|
||||
contentVersion = *form.ContentVersion
|
||||
}
|
||||
err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body, contentVersion)
|
||||
if err != nil {
|
||||
if errors.Is(err, issues_model.ErrIssueAlreadyChanged) {
|
||||
ctx.APIError(http.StatusBadRequest, err)
|
||||
ctx.APIError(http.StatusConflict, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -657,6 +657,15 @@ func EditPullRequest(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
// Fail fast: if content_version is provided and already stale, reject
|
||||
// before any mutations. The DB-level check in ChangeContent still
|
||||
// handles concurrent requests.
|
||||
// TODO: wrap all mutations in a transaction to fully prevent partial writes.
|
||||
if form.ContentVersion != nil && *form.ContentVersion != issue.ContentVersion {
|
||||
ctx.APIError(http.StatusConflict, issues_model.ErrIssueAlreadyChanged)
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.Title) > 0 {
|
||||
err = issue_service.ChangeTitle(ctx, issue, ctx.Doer, form.Title)
|
||||
if err != nil {
|
||||
@ -665,10 +674,14 @@ func EditPullRequest(ctx *context.APIContext) {
|
||||
}
|
||||
}
|
||||
if form.Body != nil {
|
||||
err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body, issue.ContentVersion)
|
||||
contentVersion := issue.ContentVersion
|
||||
if form.ContentVersion != nil {
|
||||
contentVersion = *form.ContentVersion
|
||||
}
|
||||
err = issue_service.ChangeContent(ctx, issue, ctx.Doer, *form.Body, contentVersion)
|
||||
if err != nil {
|
||||
if errors.Is(err, issues_model.ErrIssueAlreadyChanged) {
|
||||
ctx.APIError(http.StatusBadRequest, err)
|
||||
ctx.APIError(http.StatusConflict, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -215,6 +215,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI
|
||||
w := &webhook.Webhook{
|
||||
OwnerID: ownerID,
|
||||
RepoID: repoID,
|
||||
Name: strings.TrimSpace(form.Name),
|
||||
URL: form.Config["url"],
|
||||
ContentType: webhook.ToHookContentType(form.Config["content_type"]),
|
||||
Secret: form.Config["secret"],
|
||||
@ -392,6 +393,10 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *webhook.Webh
|
||||
w.IsActive = *form.Active
|
||||
}
|
||||
|
||||
if form.Name != nil {
|
||||
w.Name = strings.TrimSpace(*form.Name)
|
||||
}
|
||||
|
||||
if err := webhook.UpdateWebhook(ctx, w); err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return false
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/gtprof"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/public"
|
||||
"code.gitea.io/gitea/modules/reqctx"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/web/routing"
|
||||
@ -40,6 +41,10 @@ func ProtocolMiddlewares() (handlers []any) {
|
||||
handlers = append(handlers, context.AccessLogger())
|
||||
}
|
||||
|
||||
if !setting.IsProd {
|
||||
handlers = append(handlers, public.ViteDevMiddleware)
|
||||
}
|
||||
|
||||
return handlers
|
||||
}
|
||||
|
||||
|
||||
@ -218,18 +218,50 @@ func performAutoLogin(ctx *context.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func prepareSignInPageData(ctx *context.Context) {
|
||||
func performAutoLoginOAuth2(ctx *context.Context, data *preparedSignInData) bool {
|
||||
// If only 1 OAuth provider is present and other login methods are disabled, redirect to the OAuth provider.
|
||||
onlySingleOAuth2 := len(data.oauth2Providers) == 1 &&
|
||||
!setting.Service.EnablePasswordSignInForm &&
|
||||
!setting.Service.EnableOpenIDSignIn &&
|
||||
!setting.Service.EnablePasskeyAuth &&
|
||||
!data.enableSSPI
|
||||
|
||||
if !onlySingleOAuth2 {
|
||||
return false
|
||||
}
|
||||
|
||||
skipToOAuthURL := setting.AppSubURL + "/user/oauth2/" + url.QueryEscape(data.oauth2Providers[0].DisplayName())
|
||||
if redirectTo := ctx.FormString("redirect_to"); redirectTo != "" {
|
||||
skipToOAuthURL += "?redirect_to=" + url.QueryEscape(redirectTo)
|
||||
}
|
||||
ctx.Redirect(skipToOAuthURL)
|
||||
return true
|
||||
}
|
||||
|
||||
type preparedSignInData struct {
|
||||
oauth2Providers []oauth2.Provider
|
||||
enableSSPI bool
|
||||
}
|
||||
|
||||
func prepareSignInPageData(ctx *context.Context) (ret preparedSignInData) {
|
||||
var err error
|
||||
ret.enableSSPI = auth.IsSSPIEnabled(ctx)
|
||||
ret.oauth2Providers, err = oauth2.GetOAuth2Providers(ctx, optional.Some(true))
|
||||
if err != nil {
|
||||
log.Error("Failed to get OAuth2 providers: %v", err)
|
||||
}
|
||||
ctx.Data["Title"] = ctx.Tr("sign_in")
|
||||
ctx.Data["OAuth2Providers"], _ = oauth2.GetOAuth2Providers(ctx, optional.Some(true))
|
||||
ctx.Data["OAuth2Providers"] = ret.oauth2Providers
|
||||
ctx.Data["Title"] = ctx.Tr("sign_in")
|
||||
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
|
||||
ctx.Data["PageIsSignIn"] = true
|
||||
ctx.Data["PageIsLogin"] = true
|
||||
ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx)
|
||||
ctx.Data["EnableSSPI"] = ret.enableSSPI
|
||||
|
||||
prepareCommonAuthPageData(ctx, CommonAuthOptions{
|
||||
EnableCaptcha: setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin,
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
// SignIn render sign in page
|
||||
@ -241,7 +273,10 @@ func SignIn(ctx *context.Context) {
|
||||
redirectAfterAuth(ctx)
|
||||
return
|
||||
}
|
||||
prepareSignInPageData(ctx)
|
||||
data := prepareSignInPageData(ctx)
|
||||
if performAutoLoginOAuth2(ctx, &data) {
|
||||
return
|
||||
}
|
||||
ctx.HTML(http.StatusOK, tplSignIn)
|
||||
}
|
||||
|
||||
@ -468,6 +503,7 @@ func prepareSignUpPageData(ctx *context.Context) bool {
|
||||
ctx.Data["Title"] = ctx.Tr("sign_up")
|
||||
ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
|
||||
ctx.Data["PageIsSignUp"] = true
|
||||
ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx)
|
||||
|
||||
hasUsers, err := user_model.HasUsers(ctx)
|
||||
if err != nil {
|
||||
|
||||
@ -96,6 +96,37 @@ func TestWebAuthOAuth2(t *testing.T) {
|
||||
assert.Contains(t, ctx.Flash.ErrorMsg, "auth.oauth.signin.error.general")
|
||||
})
|
||||
|
||||
t.Run("RedirectSingleProvider", func(t *testing.T) {
|
||||
enablePassword := &setting.Service.EnablePasswordSignInForm
|
||||
enableOpenID := &setting.Service.EnableOpenIDSignIn
|
||||
enablePasskey := &setting.Service.EnablePasskeyAuth
|
||||
defer test.MockVariableValue(enablePassword, false)()
|
||||
defer test.MockVariableValue(enableOpenID, false)()
|
||||
defer test.MockVariableValue(enablePasskey, false)()
|
||||
|
||||
testSignIn := func(t *testing.T, link string, expectedCode int, expectedRedirect string) {
|
||||
ctx, resp := contexttest.MockContext(t, link)
|
||||
SignIn(ctx)
|
||||
assert.Equal(t, expectedCode, resp.Code)
|
||||
if expectedCode == http.StatusSeeOther {
|
||||
assert.Equal(t, expectedRedirect, test.RedirectURL(resp))
|
||||
}
|
||||
}
|
||||
testSignIn(t, "/user/login", http.StatusSeeOther, "/user/oauth2/dummy-auth-source")
|
||||
testSignIn(t, "/user/login?redirect_to=/", http.StatusSeeOther, "/user/oauth2/dummy-auth-source?redirect_to=%2F")
|
||||
|
||||
*enablePassword, *enableOpenID, *enablePasskey = true, false, false
|
||||
testSignIn(t, "/user/login", http.StatusOK, "")
|
||||
*enablePassword, *enableOpenID, *enablePasskey = false, true, false
|
||||
testSignIn(t, "/user/login", http.StatusOK, "")
|
||||
*enablePassword, *enableOpenID, *enablePasskey = false, false, true
|
||||
testSignIn(t, "/user/login", http.StatusOK, "")
|
||||
|
||||
*enablePassword, *enableOpenID, *enablePasskey = false, false, false
|
||||
addOAuth2Source(t, "dummy-auth-source-2", oauth2.Source{})
|
||||
testSignIn(t, "/user/login", http.StatusOK, "")
|
||||
})
|
||||
|
||||
t.Run("OIDCLogout", func(t *testing.T) {
|
||||
var mockServer *httptest.Server
|
||||
mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
@ -12,6 +13,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
org_service "code.gitea.io/gitea/services/org"
|
||||
@ -76,11 +78,11 @@ func Members(ctx *context.Context) {
|
||||
// MembersAction response for operation to a member of organization
|
||||
func MembersAction(ctx *context.Context) {
|
||||
member, err := user_model.GetUserByID(ctx, ctx.FormInt64("uid"))
|
||||
if err != nil {
|
||||
log.Error("GetUserByID: %v", err)
|
||||
}
|
||||
if member == nil {
|
||||
ctx.Redirect(ctx.Org.OrgLink + "/members")
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
ctx.HTTPError(http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
ctx.ServerError("GetUserByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -105,40 +107,25 @@ func MembersAction(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
err = org_service.RemoveOrgUser(ctx, org, member)
|
||||
if organization.IsErrLastOrgOwner(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
|
||||
ctx.JSONRedirect(ctx.Org.OrgLink + "/members")
|
||||
return
|
||||
}
|
||||
case "leave":
|
||||
err = org_service.RemoveOrgUser(ctx, org, ctx.Doer)
|
||||
if err == nil {
|
||||
ctx.Flash.Success(ctx.Tr("form.organization_leave_success", org.DisplayName()))
|
||||
ctx.JSON(http.StatusOK, map[string]any{
|
||||
"redirect": "", // keep the user stay on current page, in case they want to do other operations.
|
||||
})
|
||||
} else if organization.IsErrLastOrgOwner(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
|
||||
ctx.JSONRedirect(ctx.Org.OrgLink + "/members")
|
||||
} else {
|
||||
log.Error("RemoveOrgUser(%d,%d): %v", org.ID, ctx.Doer.ID, err)
|
||||
ctx.JSONRedirect(setting.AppSubURL + "/")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
ctx.JSONOK()
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error("Action(%s): %v", ctx.PathParam("action"), err)
|
||||
ctx.JSON(http.StatusOK, map[string]any{
|
||||
"ok": false,
|
||||
"err": err.Error(),
|
||||
})
|
||||
if organization.IsErrLastOrgOwner(err) {
|
||||
ctx.JSONError(ctx.Tr("form.last_org_owner"))
|
||||
return
|
||||
}
|
||||
|
||||
redirect := ctx.Org.OrgLink + "/members"
|
||||
if ctx.PathParam("action") == "leave" {
|
||||
redirect = setting.AppSubURL + "/"
|
||||
}
|
||||
|
||||
ctx.JSONRedirect(redirect)
|
||||
log.Error("Action(%s): %v", ctx.PathParam("action"), err)
|
||||
ctx.JSONError(err.Error()) // FIXME: legacy logic, errors are handled together, it's not right, need to distinguish between different errors
|
||||
}
|
||||
|
||||
@ -319,7 +319,12 @@ func EditFile(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["CodeEditorConfig"] = getCodeEditorConfig(ctx, ctx.Repo.TreePath)
|
||||
editorConfig := getCodeEditorConfigByEditorconfig(ctx, ctx.Repo.TreePath)
|
||||
editorConfig.Autofocus = !isNewFile
|
||||
if isNewFile {
|
||||
editorConfig.Filename = ""
|
||||
}
|
||||
ctx.Data["CodeEditorConfig"] = editorConfig
|
||||
ctx.HTML(http.StatusOK, tplEditFile)
|
||||
}
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ func NewDiffPatch(ctx *context.Context) {
|
||||
}
|
||||
|
||||
ctx.Data["PageIsPatch"] = true
|
||||
ctx.Data["CodeEditorConfig"] = CodeEditorConfig{} // not really editing a file, so no need to fill in the config
|
||||
ctx.Data["CodeEditorConfig"] = CodeEditorConfig{Filename: "diff.patch"}
|
||||
ctx.HTML(http.StatusOK, tplPatchFile)
|
||||
}
|
||||
|
||||
|
||||
@ -65,27 +65,33 @@ func getClosestParentWithFiles(gitRepo *git.Repository, branchName, originTreePa
|
||||
return f(originTreePath, commit)
|
||||
}
|
||||
|
||||
// CodeEditorConfig is also used by frontend, defined in "codeeditor.ts"
|
||||
// CodeEditorConfig is also used by frontend, defined in "codeeditor" module
|
||||
type CodeEditorConfig struct {
|
||||
PreviewableExtensions []string `json:"previewable_extensions"`
|
||||
LineWrapExtensions []string `json:"line_wrap_extensions"`
|
||||
LineWrapOn bool `json:"line_wrap_on"`
|
||||
Filename string `json:"filename"` // the base name, not full path
|
||||
Autofocus bool `json:"autofocus"`
|
||||
PreviewableExtensions []string `json:"previewableExtensions,omitempty"`
|
||||
LineWrapExtensions []string `json:"lineWrapExtensions,omitempty"`
|
||||
LineWrap bool `json:"lineWrap"`
|
||||
Previewable bool `json:"previewable,omitempty"`
|
||||
|
||||
IndentStyle string `json:"indent_style"`
|
||||
IndentSize int `json:"indent_size"`
|
||||
TabWidth int `json:"tab_width"`
|
||||
TrimTrailingWhitespace *bool `json:"trim_trailing_whitespace,omitempty"`
|
||||
// the following can be read from .editorconfig if exists, or use default value
|
||||
IndentStyle string `json:"indentStyle"` // in most cases, keep it empty by default, detected by the source code
|
||||
IndentSize int `json:"indentSize"`
|
||||
TabWidth int `json:"tabWidth"`
|
||||
TrimTrailingWhitespace *bool `json:"trimTrailingWhitespace,omitempty"`
|
||||
}
|
||||
|
||||
func getCodeEditorConfig(ctx *context_service.Context, treePath string) (ret CodeEditorConfig) {
|
||||
func getCodeEditorConfigByEditorconfig(ctx *context_service.Context, treePath string) CodeEditorConfig {
|
||||
ret := CodeEditorConfig{Filename: path.Base(treePath)}
|
||||
ret.PreviewableExtensions = markup.PreviewableExtensions()
|
||||
ret.LineWrapExtensions = setting.Repository.Editor.LineWrapExtensions
|
||||
ret.LineWrapOn = util.SliceContainsString(ret.LineWrapExtensions, path.Ext(treePath), true)
|
||||
ret.LineWrap = util.SliceContainsString(ret.LineWrapExtensions, path.Ext(treePath), true)
|
||||
ret.Previewable = util.SliceContainsString(ret.PreviewableExtensions, path.Ext(treePath), true)
|
||||
ec, _, err := ctx.Repo.GetEditorconfig()
|
||||
if err == nil {
|
||||
def, err := ec.GetDefinitionForFilename(treePath)
|
||||
if err == nil {
|
||||
ret.IndentStyle = def.IndentStyle
|
||||
ret.IndentStyle = util.IfZero(def.IndentStyle, ret.IndentStyle)
|
||||
ret.IndentSize, _ = strconv.Atoi(def.IndentSize)
|
||||
ret.TabWidth = def.TabWidth
|
||||
ret.TrimTrailingWhitespace = def.TrimTrailingWhitespace
|
||||
|
||||
@ -121,11 +121,9 @@ func NewIssue(ctx *context.Context) {
|
||||
}
|
||||
|
||||
pageMetaData.MilestonesData.SelectedMilestoneID = ctx.FormInt64("milestone")
|
||||
pageMetaData.ProjectsData.SelectedProjectID = ctx.FormInt64("project")
|
||||
if pageMetaData.ProjectsData.SelectedProjectID > 0 {
|
||||
if len(ctx.Req.URL.Query().Get("project")) > 0 {
|
||||
ctx.Data["redirect_after_creation"] = "project"
|
||||
}
|
||||
pageMetaData.ProjectsData.SelectedProjectIDs, _ = base.StringsToInt64s(strings.Split(ctx.FormString("project"), ","))
|
||||
if len(pageMetaData.ProjectsData.SelectedProjectIDs) == 1 {
|
||||
ctx.Data["redirect_after_creation"] = "project"
|
||||
}
|
||||
|
||||
tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID)
|
||||
@ -273,7 +271,7 @@ func ValidateRepoMetasForNewIssue(ctx *context.Context, form forms.CreateIssueFo
|
||||
ctx.NotFound(nil)
|
||||
return ret
|
||||
}
|
||||
pageMetaData.ProjectsData.SelectedProjectID = form.ProjectID
|
||||
pageMetaData.ProjectsData.SelectedProjectIDs = util.Iif(form.ProjectID > 0, []int64{form.ProjectID}, nil)
|
||||
|
||||
// prepare assignees
|
||||
candidateAssignees := toSet(pageMetaData.AssigneesData.CandidateAssignees, func(user *user_model.User) int64 { return user.ID })
|
||||
|
||||
@ -34,9 +34,14 @@ type issueSidebarAssigneesData struct {
|
||||
}
|
||||
|
||||
type issueSidebarProjectsData struct {
|
||||
SelectedProjectID int64
|
||||
OpenProjects []*project_model.Project
|
||||
ClosedProjects []*project_model.Project
|
||||
SelectedProjectIDs []int64 // TODO: support multiple projects in the future
|
||||
|
||||
// the "selected" fields are only valid when len(SelectedProjectIDs)==1
|
||||
SelectedProjectColumns []*project_model.Column
|
||||
SelectedProjectColumn *project_model.Column
|
||||
|
||||
OpenProjects []*project_model.Project
|
||||
ClosedProjects []*project_model.Project
|
||||
}
|
||||
|
||||
type IssuePageMetaData struct {
|
||||
@ -92,6 +97,11 @@ func retrieveRepoIssueMetaData(ctx *context.Context, repo *repo_model.Repository
|
||||
return data
|
||||
}
|
||||
|
||||
data.retrieveProjectData(ctx)
|
||||
if ctx.Written() {
|
||||
return data
|
||||
}
|
||||
|
||||
// TODO: the issue/pull permissions are quite complex and unclear
|
||||
// A reader could create an issue/PR with setting some meta (eg: assignees from issue template, reviewers, target branch)
|
||||
// A reader(creator) could update some meta (eg: target branch), but can't change assignees anymore.
|
||||
@ -158,9 +168,33 @@ func (d *IssuePageMetaData) retrieveAssigneesData(ctx *context.Context) {
|
||||
ctx.Data["Assignees"] = d.AssigneesData.CandidateAssignees
|
||||
}
|
||||
|
||||
func (d *IssuePageMetaData) retrieveProjectData(ctx *context.Context) {
|
||||
if d.Issue == nil || d.Issue.Project == nil {
|
||||
return
|
||||
}
|
||||
d.ProjectsData.SelectedProjectIDs = []int64{d.Issue.Project.ID}
|
||||
columns, err := d.Issue.Project.GetColumns(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetProjectColumns", err)
|
||||
return
|
||||
}
|
||||
d.ProjectsData.SelectedProjectColumns = columns
|
||||
columnID, err := d.Issue.ProjectColumnID(ctx)
|
||||
if err != nil {
|
||||
ctx.ServerError("ProjectColumnID", err)
|
||||
return
|
||||
}
|
||||
for _, col := range columns {
|
||||
if col.ID == columnID {
|
||||
d.ProjectsData.SelectedProjectColumn = col
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *IssuePageMetaData) retrieveProjectsDataForIssueWriter(ctx *context.Context) {
|
||||
if d.Issue != nil && d.Issue.Project != nil {
|
||||
d.ProjectsData.SelectedProjectID = d.Issue.Project.ID
|
||||
d.ProjectsData.SelectedProjectIDs = []int64{d.Issue.Project.ID}
|
||||
}
|
||||
d.ProjectsData.OpenProjects, d.ProjectsData.ClosedProjects = retrieveProjectsInternal(ctx, ctx.Repo.Repository)
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ func GitHooksEdit(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
ctx.Data["Hook"] = hook
|
||||
ctx.Data["CodeEditorConfig"] = repo.CodeEditorConfig{} // not really editing a repo file, so no editor config
|
||||
ctx.Data["CodeEditorConfig"] = repo.CodeEditorConfig{Filename: name + ".sh", IndentStyle: "tab", TabWidth: 4}
|
||||
ctx.HTML(http.StatusOK, tplGithookEdit)
|
||||
}
|
||||
|
||||
|
||||
@ -234,6 +234,7 @@ func createWebhook(ctx *context.Context, params webhookParams) {
|
||||
w := &webhook.Webhook{
|
||||
RepoID: orCtx.RepoID,
|
||||
URL: params.URL,
|
||||
Name: strings.TrimSpace(params.WebhookForm.Name),
|
||||
HTTPMethod: params.HTTPMethod,
|
||||
ContentType: params.ContentType,
|
||||
Secret: params.WebhookForm.Secret,
|
||||
@ -288,6 +289,7 @@ func editWebhook(ctx *context.Context, params webhookParams) {
|
||||
}
|
||||
|
||||
w.URL = params.URL
|
||||
w.Name = strings.TrimSpace(params.WebhookForm.Name)
|
||||
w.ContentType = params.ContentType
|
||||
w.Secret = params.WebhookForm.Secret
|
||||
w.HookEvent = ParseHookEvent(params.WebhookForm)
|
||||
|
||||
@ -259,10 +259,6 @@ func Routes() *web.Router {
|
||||
// GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route
|
||||
routes.BeforeRouting(chi_middleware.GetHead)
|
||||
|
||||
if !setting.IsProd {
|
||||
routes.BeforeRouting(public.ViteDevMiddleware)
|
||||
}
|
||||
|
||||
routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler
|
||||
routes.Methods("GET, HEAD, OPTIONS", "/assets/*", routing.MarkLogLevelTrace, optionsCorsHandler(), public.FileHandlerFunc())
|
||||
routes.Methods("GET, HEAD", "/avatars/*", avatarStorageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
|
||||
|
||||
@ -62,7 +62,7 @@ func (p *AuthSourceProvider) DisplayName() string {
|
||||
|
||||
func (p *AuthSourceProvider) IconHTML(size int) template.HTML {
|
||||
if p.iconURL != "" {
|
||||
img := fmt.Sprintf(`<img class="tw-object-contain tw-mr-2" width="%d" height="%d" src="%s" alt="%s">`,
|
||||
img := fmt.Sprintf(`<img class="tw-object-contain" width="%d" height="%d" src="%s" alt="%s">`,
|
||||
size,
|
||||
size,
|
||||
html.EscapeString(p.iconURL), html.EscapeString(p.DisplayName()),
|
||||
|
||||
@ -42,10 +42,10 @@ func (b *BaseProvider) IconHTML(size int) template.HTML {
|
||||
case "github":
|
||||
svgName = "octicon-mark-github"
|
||||
}
|
||||
svgHTML := svg.RenderHTML(svgName, size, "tw-mr-2")
|
||||
svgHTML := svg.RenderHTML(svgName, size)
|
||||
if svgHTML == "" {
|
||||
log.Error("No SVG icon for oauth2 provider %q", b.name)
|
||||
svgHTML = svg.RenderHTML("gitea-openid", size, "tw-mr-2")
|
||||
svgHTML = svg.RenderHTML("gitea-openid", size)
|
||||
}
|
||||
return svgHTML
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ func (o *OpenIDProvider) DisplayName() string {
|
||||
|
||||
// IconHTML returns icon HTML for this provider
|
||||
func (o *OpenIDProvider) IconHTML(size int) template.HTML {
|
||||
return svg.RenderHTML("gitea-openid", size, "tw-mr-2")
|
||||
return svg.RenderHTML("gitea-openid", size)
|
||||
}
|
||||
|
||||
// CreateGothProvider creates a GothProvider from this Provider
|
||||
|
||||
@ -62,7 +62,8 @@ func toIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Iss
|
||||
Updated: issue.UpdatedUnix.AsTime(),
|
||||
PinOrder: util.Iif(issue.PinOrder == -1, 0, issue.PinOrder), // -1 means loaded with no pin order
|
||||
|
||||
TimeEstimate: issue.TimeEstimate,
|
||||
TimeEstimate: issue.TimeEstimate,
|
||||
ContentVersion: issue.ContentVersion,
|
||||
}
|
||||
|
||||
if issue.Repo != nil {
|
||||
|
||||
@ -97,6 +97,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
|
||||
Created: pr.Issue.CreatedUnix.AsTimePtr(),
|
||||
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
|
||||
PinOrder: util.Iif(apiIssue.PinOrder == -1, 0, apiIssue.PinOrder),
|
||||
ContentVersion: apiIssue.ContentVersion,
|
||||
|
||||
// output "[]" rather than null to align to github outputs
|
||||
RequestedReviewers: []*api.User{},
|
||||
@ -372,6 +373,7 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
|
||||
Created: pr.Issue.CreatedUnix.AsTimePtr(),
|
||||
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
|
||||
PinOrder: util.Iif(apiIssue.PinOrder == -1, 0, apiIssue.PinOrder),
|
||||
ContentVersion: apiIssue.ContentVersion,
|
||||
|
||||
AllowMaintainerEdit: pr.AllowMaintainerEdit,
|
||||
|
||||
|
||||
@ -10,13 +10,22 @@ import (
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/go-co-op/gocron"
|
||||
"github.com/go-co-op/gocron/v2"
|
||||
)
|
||||
|
||||
var scheduler = gocron.NewScheduler(time.Local)
|
||||
var scheduler gocron.Scheduler
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
scheduler, err = gocron.NewScheduler(gocron.WithLocation(time.Local))
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create cron scheduler: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Init begins cron tasks
|
||||
// Each cron task is run within the shutdown context as a running server
|
||||
@ -35,11 +44,13 @@ func Init(original context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
scheduler.StartAsync()
|
||||
scheduler.Start()
|
||||
started = true
|
||||
lock.Unlock()
|
||||
graceful.GetManager().RunAtShutdown(context.Background(), func() {
|
||||
scheduler.Stop()
|
||||
if err := scheduler.Shutdown(); err != nil {
|
||||
log.Error("Unable to shutdown cron scheduler: %v", err)
|
||||
}
|
||||
lock.Lock()
|
||||
started = false
|
||||
lock.Unlock()
|
||||
@ -74,14 +85,14 @@ type TaskTable []*TaskTableRow
|
||||
// ListTasks returns all running cron tasks.
|
||||
func ListTasks() TaskTable {
|
||||
jobs := scheduler.Jobs()
|
||||
jobMap := map[string]*gocron.Job{}
|
||||
jobMap := map[string]gocron.Job{}
|
||||
for _, job := range jobs {
|
||||
// the first tag is the task name
|
||||
tags := job.Tags()
|
||||
if len(tags) == 0 { // should never happen
|
||||
continue
|
||||
}
|
||||
jobMap[job.Tags()[0]] = job
|
||||
jobMap[tags[0]] = job
|
||||
}
|
||||
|
||||
lock.Lock()
|
||||
@ -99,8 +110,8 @@ func ListTasks() TaskTable {
|
||||
if len(tags) > 1 {
|
||||
spec = tags[1] // the second tag is the task spec
|
||||
}
|
||||
next = e.NextRun()
|
||||
prev = e.PreviousRun()
|
||||
next, _ = e.NextRun()
|
||||
prev, _ = e.LastRun()
|
||||
}
|
||||
|
||||
task.lock.Lock()
|
||||
|
||||
@ -20,6 +20,8 @@ import (
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/go-co-op/gocron/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -224,12 +226,13 @@ func RegisterTaskFatal(name string, config Config, fun func(context.Context, *us
|
||||
|
||||
func addTaskToScheduler(task *Task) error {
|
||||
tags := []string{task.Name, task.config.GetSchedule()} // name and schedule can't be get from job, so we add them as tag
|
||||
if scheduleHasSeconds(task.config.GetSchedule()) {
|
||||
scheduler = scheduler.CronWithSeconds(task.config.GetSchedule())
|
||||
} else {
|
||||
scheduler = scheduler.Cron(task.config.GetSchedule())
|
||||
}
|
||||
if _, err := scheduler.Tag(tags...).Do(task.Run); err != nil {
|
||||
withSeconds := scheduleHasSeconds(task.config.GetSchedule())
|
||||
_, err := scheduler.NewJob(
|
||||
gocron.CronJob(task.config.GetSchedule(), withSeconds),
|
||||
gocron.NewTask(task.Run),
|
||||
gocron.WithTags(tags...),
|
||||
)
|
||||
if err != nil {
|
||||
log.Error("Unable to register cron task with name: %s Error: %v", task.Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -13,7 +13,11 @@ import (
|
||||
|
||||
func TestAddTaskToScheduler(t *testing.T) {
|
||||
assert.Empty(t, scheduler.Jobs())
|
||||
defer scheduler.Clear()
|
||||
defer func() {
|
||||
for _, j := range scheduler.Jobs() {
|
||||
_ = scheduler.RemoveJob(j.ID())
|
||||
}
|
||||
}()
|
||||
|
||||
// no seconds
|
||||
err := addTaskToScheduler(&Task{
|
||||
|
||||
@ -206,6 +206,7 @@ type ProtectBranchPriorityForm struct {
|
||||
|
||||
// WebhookForm form for changing web hook
|
||||
type WebhookForm struct {
|
||||
Name string `binding:"MaxSize(255)"`
|
||||
Events string
|
||||
Create bool
|
||||
Delete bool
|
||||
|
||||
@ -21,7 +21,7 @@ import (
|
||||
"github.com/dimiro1/reply"
|
||||
"github.com/emersion/go-imap"
|
||||
"github.com/emersion/go-imap/client"
|
||||
"github.com/jhillyerd/enmime"
|
||||
"github.com/jhillyerd/enmime/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/jhillyerd/enmime"
|
||||
"github.com/jhillyerd/enmime/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@ -41,19 +41,17 @@ func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
|
||||
}
|
||||
|
||||
type ntlmAuth struct {
|
||||
username, password, domain string
|
||||
domainNeeded bool
|
||||
username, password string
|
||||
}
|
||||
|
||||
// NtlmAuth SMTP AUTH NTLM Auth Handler
|
||||
func NtlmAuth(username, password string) smtp.Auth {
|
||||
user, domain, domainNeeded := ntlmssp.GetDomain(username)
|
||||
return &ntlmAuth{user, password, domain, domainNeeded}
|
||||
return &ntlmAuth{username, password}
|
||||
}
|
||||
|
||||
// Start starts SMTP NTLM Auth
|
||||
func (a *ntlmAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
|
||||
negotiateMessage, err := ntlmssp.NewNegotiateMessage(a.domain, "")
|
||||
negotiateMessage, err := ntlmssp.NewNegotiateMessage("", "")
|
||||
return "NTLM", negotiateMessage, err
|
||||
}
|
||||
|
||||
@ -63,7 +61,7 @@ func (a *ntlmAuth) Next(fromServer []byte, more bool) ([]byte, error) {
|
||||
if len(fromServer) == 0 {
|
||||
return nil, errors.New("ntlm ChallengeMessage is empty")
|
||||
}
|
||||
authenticateMessage, err := ntlmssp.ProcessChallenge(fromServer, a.username, a.password, a.domainNeeded)
|
||||
authenticateMessage, err := ntlmssp.NewAuthenticateMessage(fromServer, a.username, a.password, nil)
|
||||
return authenticateMessage, err
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
@ -7,7 +7,7 @@ package migrations
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/google/go-github/v74/github"
|
||||
"github.com/google/go-github/v84/github"
|
||||
)
|
||||
|
||||
// ErrRepoNotCreated returns the error that repository not created
|
||||
|
||||
@ -20,7 +20,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/proxy"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/google/go-github/v74/github"
|
||||
"github.com/google/go-github/v84/github"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
@ -861,28 +861,22 @@ func (g *GithubDownloaderV3) GetReviews(ctx context.Context, reviewable base.Rev
|
||||
opt.Page = resp.NextPage
|
||||
}
|
||||
// Get requested reviews
|
||||
for {
|
||||
g.waitAndPickClient(ctx)
|
||||
reviewers, resp, err := g.getClient().PullRequests.ListReviewers(ctx, g.repoOwner, g.repoName, int(reviewable.GetForeignIndex()), opt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while listing repos: %w", err)
|
||||
}
|
||||
g.setRate(&resp.Rate)
|
||||
for _, user := range reviewers.Users {
|
||||
r := &base.Review{
|
||||
ReviewerID: user.GetID(),
|
||||
ReviewerName: user.GetLogin(),
|
||||
State: base.ReviewStateRequestReview,
|
||||
IssueIndex: reviewable.GetLocalIndex(),
|
||||
}
|
||||
allReviews = append(allReviews, r)
|
||||
}
|
||||
// TODO: Handle Team requests
|
||||
if resp.NextPage == 0 {
|
||||
break
|
||||
}
|
||||
opt.Page = resp.NextPage
|
||||
g.waitAndPickClient(ctx)
|
||||
reviewers, resp, err := g.getClient().PullRequests.ListReviewers(ctx, g.repoOwner, g.repoName, int(reviewable.GetForeignIndex()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while listing repos: %w", err)
|
||||
}
|
||||
g.setRate(&resp.Rate)
|
||||
for _, user := range reviewers.Users {
|
||||
r := &base.Review{
|
||||
ReviewerID: user.GetID(),
|
||||
ReviewerName: user.GetLogin(),
|
||||
State: base.ReviewStateRequestReview,
|
||||
IssueIndex: reviewable.GetLocalIndex(),
|
||||
}
|
||||
allReviews = append(allReviews, r)
|
||||
}
|
||||
// TODO: Handle Team requests
|
||||
return allReviews, nil
|
||||
}
|
||||
|
||||
|
||||
@ -63,16 +63,16 @@ type gitlabIIDResolver struct {
|
||||
frozen bool
|
||||
}
|
||||
|
||||
func (r *gitlabIIDResolver) recordIssueIID(issueIID int) {
|
||||
func (r *gitlabIIDResolver) recordIssueIID(issueIID int64) {
|
||||
if r.frozen {
|
||||
panic("cannot record issue IID after pull request IID generation has started")
|
||||
}
|
||||
r.maxIssueIID = max(r.maxIssueIID, int64(issueIID))
|
||||
r.maxIssueIID = max(r.maxIssueIID, issueIID)
|
||||
}
|
||||
|
||||
func (r *gitlabIIDResolver) generatePullRequestNumber(mrIID int) int64 {
|
||||
func (r *gitlabIIDResolver) generatePullRequestNumber(mrIID int64) int64 {
|
||||
r.frozen = true
|
||||
return r.maxIssueIID + int64(mrIID)
|
||||
return r.maxIssueIID + mrIID
|
||||
}
|
||||
|
||||
// GitlabDownloader implements a Downloader interface to get repository information
|
||||
@ -83,7 +83,7 @@ type GitlabDownloader struct {
|
||||
base.NullDownloader
|
||||
client *gitlab.Client
|
||||
baseURL string
|
||||
repoID int
|
||||
repoID int64
|
||||
repoName string
|
||||
iidResolver gitlabIIDResolver
|
||||
maxPerPage int
|
||||
@ -212,8 +212,8 @@ func (g *GitlabDownloader) GetMilestones(ctx context.Context) ([]*base.Milestone
|
||||
ms, _, err := g.client.Milestones.ListMilestones(g.repoID, &gitlab.ListMilestonesOptions{
|
||||
State: &state,
|
||||
ListOptions: gitlab.ListOptions{
|
||||
Page: i,
|
||||
PerPage: perPage,
|
||||
Page: int64(i),
|
||||
PerPage: int64(perPage),
|
||||
},
|
||||
}, nil, gitlab.WithContext(ctx))
|
||||
if err != nil {
|
||||
@ -281,8 +281,8 @@ func (g *GitlabDownloader) GetLabels(ctx context.Context) ([]*base.Label, error)
|
||||
labels := make([]*base.Label, 0, perPage)
|
||||
for i := 1; ; i++ {
|
||||
ls, _, err := g.client.Labels.ListLabels(g.repoID, &gitlab.ListLabelsOptions{ListOptions: gitlab.ListOptions{
|
||||
Page: i,
|
||||
PerPage: perPage,
|
||||
Page: int64(i),
|
||||
PerPage: int64(perPage),
|
||||
}}, nil, gitlab.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -310,7 +310,7 @@ func (g *GitlabDownloader) convertGitlabRelease(ctx context.Context, rel *gitlab
|
||||
Name: rel.Name,
|
||||
Body: rel.Description,
|
||||
Created: *rel.CreatedAt,
|
||||
PublisherID: int64(rel.Author.ID),
|
||||
PublisherID: rel.Author.ID,
|
||||
PublisherName: rel.Author.Username,
|
||||
}
|
||||
|
||||
@ -319,7 +319,7 @@ func (g *GitlabDownloader) convertGitlabRelease(ctx context.Context, rel *gitlab
|
||||
for _, asset := range rel.Assets.Links {
|
||||
assetID := asset.ID // Don't optimize this, for closure we need a local variable
|
||||
r.Assets = append(r.Assets, &base.ReleaseAsset{
|
||||
ID: int64(asset.ID),
|
||||
ID: asset.ID,
|
||||
Name: asset.Name,
|
||||
Size: &zero,
|
||||
DownloadCount: &zero,
|
||||
@ -359,8 +359,8 @@ func (g *GitlabDownloader) GetReleases(ctx context.Context) ([]*base.Release, er
|
||||
for i := 1; ; i++ {
|
||||
ls, _, err := g.client.Releases.ListReleases(g.repoID, &gitlab.ListReleasesOptions{
|
||||
ListOptions: gitlab.ListOptions{
|
||||
Page: i,
|
||||
PerPage: perPage,
|
||||
Page: int64(i),
|
||||
PerPage: int64(perPage),
|
||||
},
|
||||
}, nil, gitlab.WithContext(ctx))
|
||||
if err != nil {
|
||||
@ -396,8 +396,8 @@ func (g *GitlabDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
|
||||
State: &state,
|
||||
Sort: &sort,
|
||||
ListOptions: gitlab.ListOptions{
|
||||
PerPage: perPage,
|
||||
Page: page,
|
||||
PerPage: int64(perPage),
|
||||
Page: int64(page),
|
||||
},
|
||||
}
|
||||
|
||||
@ -423,7 +423,7 @@ func (g *GitlabDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
|
||||
var reactions []*gitlab.AwardEmoji
|
||||
awardPage := 1
|
||||
for {
|
||||
awards, _, err := g.client.AwardEmoji.ListIssueAwardEmoji(g.repoID, issue.IID, &gitlab.ListAwardEmojiOptions{Page: awardPage, PerPage: perPage}, gitlab.WithContext(ctx))
|
||||
awards, _, err := g.client.AwardEmoji.ListIssueAwardEmoji(g.repoID, issue.IID, &gitlab.ListAwardEmojiOptions{ListOptions: gitlab.ListOptions{Page: int64(awardPage), PerPage: int64(perPage)}}, gitlab.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error while listing issue awards: %w", err)
|
||||
}
|
||||
@ -439,8 +439,8 @@ func (g *GitlabDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
|
||||
|
||||
allIssues = append(allIssues, &base.Issue{
|
||||
Title: issue.Title,
|
||||
Number: int64(issue.IID),
|
||||
PosterID: int64(issue.Author.ID),
|
||||
Number: issue.IID,
|
||||
PosterID: issue.Author.ID,
|
||||
PosterName: issue.Author.Username,
|
||||
Content: issue.Description,
|
||||
Milestone: milestone,
|
||||
@ -451,7 +451,7 @@ func (g *GitlabDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
|
||||
Closed: issue.ClosedAt,
|
||||
IsLocked: issue.DiscussionLocked,
|
||||
Updated: *issue.UpdatedAt,
|
||||
ForeignIndex: int64(issue.IID),
|
||||
ForeignIndex: issue.IID,
|
||||
Context: gitlabIssueContext{IsMergeRequest: false},
|
||||
})
|
||||
|
||||
@ -472,21 +472,25 @@ func (g *GitlabDownloader) GetComments(ctx context.Context, commentable base.Com
|
||||
|
||||
allComments := make([]*base.Comment, 0, g.maxPerPage)
|
||||
|
||||
page := 1
|
||||
var page int64 = 1
|
||||
|
||||
for {
|
||||
var comments []*gitlab.Discussion
|
||||
var resp *gitlab.Response
|
||||
var err error
|
||||
if !context.IsMergeRequest {
|
||||
comments, resp, err = g.client.Discussions.ListIssueDiscussions(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListIssueDiscussionsOptions{
|
||||
Page: page,
|
||||
PerPage: g.maxPerPage,
|
||||
comments, resp, err = g.client.Discussions.ListIssueDiscussions(g.repoID, commentable.GetForeignIndex(), &gitlab.ListIssueDiscussionsOptions{
|
||||
ListOptions: gitlab.ListOptions{
|
||||
Page: page,
|
||||
PerPage: int64(g.maxPerPage),
|
||||
},
|
||||
}, nil, gitlab.WithContext(ctx))
|
||||
} else {
|
||||
comments, resp, err = g.client.Discussions.ListMergeRequestDiscussions(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListMergeRequestDiscussionsOptions{
|
||||
Page: page,
|
||||
PerPage: g.maxPerPage,
|
||||
comments, resp, err = g.client.Discussions.ListMergeRequestDiscussions(g.repoID, commentable.GetForeignIndex(), &gitlab.ListMergeRequestDiscussionsOptions{
|
||||
ListOptions: gitlab.ListOptions{
|
||||
Page: page,
|
||||
PerPage: int64(g.maxPerPage),
|
||||
},
|
||||
}, nil, gitlab.WithContext(ctx))
|
||||
}
|
||||
|
||||
@ -510,17 +514,17 @@ func (g *GitlabDownloader) GetComments(ctx context.Context, commentable base.Com
|
||||
var resp *gitlab.Response
|
||||
var err error
|
||||
if context.IsMergeRequest {
|
||||
stateEvents, resp, err = g.client.ResourceStateEvents.ListMergeStateEvents(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListStateEventsOptions{
|
||||
stateEvents, resp, err = g.client.ResourceStateEvents.ListMergeStateEvents(g.repoID, commentable.GetForeignIndex(), &gitlab.ListStateEventsOptions{
|
||||
ListOptions: gitlab.ListOptions{
|
||||
Page: page,
|
||||
PerPage: g.maxPerPage,
|
||||
PerPage: int64(g.maxPerPage),
|
||||
},
|
||||
}, nil, gitlab.WithContext(ctx))
|
||||
} else {
|
||||
stateEvents, resp, err = g.client.ResourceStateEvents.ListIssueStateEvents(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListStateEventsOptions{
|
||||
stateEvents, resp, err = g.client.ResourceStateEvents.ListIssueStateEvents(g.repoID, commentable.GetForeignIndex(), &gitlab.ListStateEventsOptions{
|
||||
ListOptions: gitlab.ListOptions{
|
||||
Page: page,
|
||||
PerPage: g.maxPerPage,
|
||||
PerPage: int64(g.maxPerPage),
|
||||
},
|
||||
}, nil, gitlab.WithContext(ctx))
|
||||
}
|
||||
@ -531,11 +535,11 @@ func (g *GitlabDownloader) GetComments(ctx context.Context, commentable base.Com
|
||||
for _, stateEvent := range stateEvents {
|
||||
posterUserID, posterUsername := user.GhostUserID, user.GhostUserName
|
||||
if stateEvent.User != nil {
|
||||
posterUserID, posterUsername = int64(stateEvent.User.ID), stateEvent.User.Username
|
||||
posterUserID, posterUsername = stateEvent.User.ID, stateEvent.User.Username
|
||||
}
|
||||
comment := &base.Comment{
|
||||
IssueIndex: commentable.GetLocalIndex(),
|
||||
Index: int64(stateEvent.ID),
|
||||
Index: stateEvent.ID,
|
||||
PosterID: posterUserID,
|
||||
PosterName: posterUsername,
|
||||
Content: "",
|
||||
@ -569,8 +573,8 @@ var targetBranchChangeRegexp = regexp.MustCompile("^changed target branch from `
|
||||
func (g *GitlabDownloader) convertNoteToComment(localIndex int64, note *gitlab.Note) *base.Comment {
|
||||
comment := &base.Comment{
|
||||
IssueIndex: localIndex,
|
||||
Index: int64(note.ID),
|
||||
PosterID: int64(note.Author.ID),
|
||||
Index: note.ID,
|
||||
PosterID: note.Author.ID,
|
||||
PosterName: note.Author.Username,
|
||||
PosterEmail: note.Author.Email,
|
||||
Content: note.Body,
|
||||
@ -603,8 +607,8 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
|
||||
view := "simple"
|
||||
opt := &gitlab.ListProjectMergeRequestsOptions{
|
||||
ListOptions: gitlab.ListOptions{
|
||||
PerPage: perPage,
|
||||
Page: page,
|
||||
PerPage: int64(perPage),
|
||||
Page: int64(page),
|
||||
},
|
||||
View: &view,
|
||||
}
|
||||
@ -664,7 +668,7 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
|
||||
var reactions []*gitlab.AwardEmoji
|
||||
awardPage := 1
|
||||
for {
|
||||
awards, _, err := g.client.AwardEmoji.ListMergeRequestAwardEmoji(g.repoID, pr.IID, &gitlab.ListAwardEmojiOptions{Page: awardPage, PerPage: perPage}, gitlab.WithContext(ctx))
|
||||
awards, _, err := g.client.AwardEmoji.ListMergeRequestAwardEmoji(g.repoID, pr.IID, &gitlab.ListAwardEmojiOptions{ListOptions: gitlab.ListOptions{Page: int64(awardPage), PerPage: int64(perPage)}}, gitlab.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error while listing merge requests awards: %w", err)
|
||||
}
|
||||
@ -685,7 +689,7 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
|
||||
Title: pr.Title,
|
||||
Number: newPRNumber,
|
||||
PosterName: pr.Author.Username,
|
||||
PosterID: int64(pr.Author.ID),
|
||||
PosterID: pr.Author.ID,
|
||||
Content: pr.Description,
|
||||
Milestone: milestone,
|
||||
State: pr.State,
|
||||
@ -711,7 +715,7 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
|
||||
OwnerName: pr.Author.Username,
|
||||
},
|
||||
PatchURL: pr.WebURL + ".patch",
|
||||
ForeignIndex: int64(pr.IID),
|
||||
ForeignIndex: pr.IID,
|
||||
Context: gitlabIssueContext{IsMergeRequest: true},
|
||||
IsDraft: pr.Draft,
|
||||
})
|
||||
@ -725,7 +729,7 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
|
||||
|
||||
// GetReviews returns pull requests review
|
||||
func (g *GitlabDownloader) GetReviews(ctx context.Context, reviewable base.Reviewable) ([]*base.Review, error) {
|
||||
approvals, resp, err := g.client.MergeRequestApprovals.GetConfiguration(g.repoID, int(reviewable.GetForeignIndex()), gitlab.WithContext(ctx))
|
||||
approvals, resp, err := g.client.MergeRequestApprovals.GetConfiguration(g.repoID, reviewable.GetForeignIndex(), gitlab.WithContext(ctx))
|
||||
if err != nil {
|
||||
if resp != nil && resp.StatusCode == http.StatusNotFound {
|
||||
log.Error(fmt.Sprintf("GitlabDownloader: while migrating a error occurred: '%s'", err.Error()))
|
||||
@ -747,7 +751,7 @@ func (g *GitlabDownloader) GetReviews(ctx context.Context, reviewable base.Revie
|
||||
for _, user := range approvals.ApprovedBy {
|
||||
reviews = append(reviews, &base.Review{
|
||||
IssueIndex: reviewable.GetLocalIndex(),
|
||||
ReviewerID: int64(user.User.ID),
|
||||
ReviewerID: user.User.ID,
|
||||
ReviewerName: user.User.Username,
|
||||
CreatedAt: createdAt,
|
||||
// All we get are approvals
|
||||
@ -765,7 +769,7 @@ func (g *GitlabDownloader) awardsToReactions(awards []*gitlab.AwardEmoji) []*bas
|
||||
uid := fmt.Sprintf("%s%d", award.Name, award.User.ID)
|
||||
if uniqCheck.Add(uid) {
|
||||
result = append(result, &base.Reaction{
|
||||
UserID: int64(award.User.ID),
|
||||
UserID: award.User.ID,
|
||||
UserName: award.User.Username,
|
||||
Content: award.Name,
|
||||
})
|
||||
|
||||
@ -358,7 +358,7 @@ func gitlabClientMockTeardown(server *httptest.Server) {
|
||||
}
|
||||
|
||||
type reviewTestCase struct {
|
||||
repoID, prID, reviewerID int
|
||||
repoID, prID, reviewerID int64
|
||||
reviewerName string
|
||||
createdAt, updatedAt *time.Time
|
||||
expectedCreatedAt time.Time
|
||||
@ -383,8 +383,8 @@ func convertTestCase(t reviewTestCase) (func(w http.ResponseWriter, r *http.Requ
|
||||
fmt.Fprint(w, `
|
||||
{
|
||||
"id": 5,
|
||||
"iid": `+strconv.Itoa(t.prID)+`,
|
||||
"project_id": `+strconv.Itoa(t.repoID)+`,
|
||||
"iid": `+strconv.FormatInt(t.prID, 10)+`,
|
||||
"project_id": `+strconv.FormatInt(t.repoID, 10)+`,
|
||||
"title": "Approvals API",
|
||||
"description": "Test",
|
||||
"state": "opened",
|
||||
@ -398,7 +398,7 @@ func convertTestCase(t reviewTestCase) (func(w http.ResponseWriter, r *http.Requ
|
||||
"user": {
|
||||
"name": "Administrator",
|
||||
"username": "`+t.reviewerName+`",
|
||||
"id": `+strconv.Itoa(t.reviewerID)+`,
|
||||
"id": `+strconv.FormatInt(t.reviewerID, 10)+`,
|
||||
"state": "active",
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
|
||||
"web_url": "http://localhost:3000/root"
|
||||
@ -408,8 +408,8 @@ func convertTestCase(t reviewTestCase) (func(w http.ResponseWriter, r *http.Requ
|
||||
}`)
|
||||
}
|
||||
review := base.Review{
|
||||
IssueIndex: int64(t.prID),
|
||||
ReviewerID: int64(t.reviewerID),
|
||||
IssueIndex: t.prID,
|
||||
ReviewerID: t.reviewerID,
|
||||
ReviewerName: t.reviewerName,
|
||||
CreatedAt: t.expectedCreatedAt,
|
||||
State: "APPROVED",
|
||||
@ -422,7 +422,7 @@ func TestGitlabGetReviews(t *testing.T) {
|
||||
mux, server, client := gitlabClientMockSetup(t)
|
||||
defer gitlabClientMockTeardown(server)
|
||||
|
||||
repoID := 1324
|
||||
var repoID int64 = 1324
|
||||
ctx := t.Context()
|
||||
downloader := &GitlabDownloader{
|
||||
client: client,
|
||||
@ -463,8 +463,7 @@ func TestGitlabGetReviews(t *testing.T) {
|
||||
mock, review := convertTestCase(testCase)
|
||||
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/%d/merge_requests/%d/approvals", testCase.repoID, testCase.prID), mock)
|
||||
|
||||
id := int64(testCase.prID)
|
||||
rvs, err := downloader.GetReviews(ctx, &base.Issue{Number: id, ForeignIndex: id})
|
||||
rvs, err := downloader.GetReviews(ctx, &base.Issue{Number: testCase.prID, ForeignIndex: testCase.prID})
|
||||
assert.NoError(t, err)
|
||||
assertReviewsEqual(t, []*base.Review{&review}, rvs)
|
||||
}
|
||||
@ -520,18 +519,10 @@ func TestNoteToComment(t *testing.T) {
|
||||
downloader := &GitlabDownloader{}
|
||||
|
||||
now := time.Now()
|
||||
makeTestNote := func(id int, body string, system bool) gitlab.Note {
|
||||
makeTestNote := func(id int64, body string, system bool) gitlab.Note {
|
||||
return gitlab.Note{
|
||||
ID: id,
|
||||
Author: struct {
|
||||
ID int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
State string `json:"state"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
WebURL string `json:"web_url"`
|
||||
}{
|
||||
Author: gitlab.NoteAuthor{
|
||||
ID: 72,
|
||||
Email: "test@example.com",
|
||||
Username: "test",
|
||||
|
||||
@ -5,6 +5,7 @@ package org
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@ -306,19 +307,19 @@ func removeTeamMember(ctx context.Context, team *organization.Team, user *user_m
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete access to team repositories.
|
||||
// Delete access to team repositories. If any user or repo is missing, we can continue.
|
||||
for _, repo := range repos {
|
||||
if err := access_model.RecalculateUserAccess(ctx, repo, user.ID); err != nil {
|
||||
if err := access_model.RecalculateUserAccess(ctx, repo, user.ID); err != nil && !errors.Is(err, util.ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove watches from now inaccessible
|
||||
if err := repo_service.ReconsiderWatches(ctx, repo, user); err != nil {
|
||||
if err := repo_service.ReconsiderWatches(ctx, repo, user); err != nil && !errors.Is(err, util.ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove issue assignments from now inaccessible
|
||||
if err := repo_service.ReconsiderRepoIssuesAssignee(ctx, repo, user); err != nil {
|
||||
if err := repo_service.ReconsiderRepoIssuesAssignee(ctx, repo, user); err != nil && !errors.Is(err, util.ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ func MoveIssuesOnProjectColumn(ctx context.Context, doer *user_model.User, colum
|
||||
}
|
||||
|
||||
// LoadIssuesFromProject load issues assigned to each project column inside the given project
|
||||
func LoadIssuesFromProject(ctx context.Context, project *project_model.Project, opts *issues_model.IssuesOptions) (map[int64]issues_model.IssueList, error) {
|
||||
func LoadIssuesFromProject(ctx context.Context, project *project_model.Project, opts *issues_model.IssuesOptions) (results map[int64]issues_model.IssueList, _ error) {
|
||||
issueList, err := issues_model.Issues(ctx, opts.Copy(func(o *issues_model.IssuesOptions) {
|
||||
o.ProjectID = project.ID
|
||||
o.SortType = "project-column-sorting"
|
||||
@ -95,7 +95,10 @@ func LoadIssuesFromProject(ctx context.Context, project *project_model.Project,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(issueList) == 0 {
|
||||
// if no issue, return directly, then no need to create a default column for an empty project
|
||||
return results, nil
|
||||
}
|
||||
if err := issueList.LoadComments(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -110,7 +113,7 @@ func LoadIssuesFromProject(ctx context.Context, project *project_model.Project,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results := make(map[int64]issues_model.IssueList)
|
||||
results = make(map[int64]issues_model.IssueList)
|
||||
for _, issue := range issueList {
|
||||
projectColumnID, ok := issueColumnMap[issue.ID]
|
||||
if !ok {
|
||||
|
||||
@ -411,6 +411,7 @@ func ToHook(repoLink string, w *webhook_model.Webhook) (*api.Hook, error) {
|
||||
|
||||
return &api.Hook{
|
||||
ID: w.ID,
|
||||
Name: w.Name,
|
||||
Type: w.Type,
|
||||
URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID),
|
||||
Active: w.IsActive,
|
||||
|
||||
@ -4,10 +4,14 @@
|
||||
package webtheme
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
@ -16,15 +20,15 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
type themeCollection struct {
|
||||
type themeCollectionStruct struct {
|
||||
lastCheckTime time.Time
|
||||
usingViteDevMode bool
|
||||
|
||||
themeList []*ThemeMetaInfo
|
||||
themeMap map[string]*ThemeMetaInfo
|
||||
}
|
||||
|
||||
var (
|
||||
themeMu sync.RWMutex
|
||||
availableThemes *themeCollection
|
||||
)
|
||||
var themeCollection atomic.Pointer[themeCollectionStruct]
|
||||
|
||||
const (
|
||||
fileNamePrefix = "theme-"
|
||||
@ -140,23 +144,42 @@ func parseThemeMetaInfo(fileName, cssContent string) *ThemeMetaInfo {
|
||||
return themeInfo
|
||||
}
|
||||
|
||||
func loadThemesFromAssets() (themeList []*ThemeMetaInfo, themeMap map[string]*ThemeMetaInfo) {
|
||||
cssFiles, err := public.AssetFS().ListFiles("assets/css")
|
||||
func collectThemeFiles(dirFS fs.ReadDirFS, fsPath string) (themes []*ThemeMetaInfo, _ error) {
|
||||
files, err := dirFS.ReadDir(fsPath)
|
||||
if err != nil {
|
||||
log.Error("Failed to list themes: %v", err)
|
||||
return nil, nil
|
||||
return nil, err
|
||||
}
|
||||
for _, file := range files {
|
||||
fileName := file.Name()
|
||||
if !strings.HasPrefix(fileName, fileNamePrefix) || !strings.HasSuffix(fileName, fileNameSuffix) {
|
||||
continue
|
||||
}
|
||||
content, err := fs.ReadFile(dirFS, path.Join(fsPath, file.Name()))
|
||||
if err != nil {
|
||||
log.Error("Failed to read theme file %q: %v", fileName, err)
|
||||
continue
|
||||
}
|
||||
themes = append(themes, parseThemeMetaInfo(fileName, util.UnsafeBytesToString(content)))
|
||||
}
|
||||
return themes, nil
|
||||
}
|
||||
|
||||
func loadThemesFromAssets(isViteDevMode bool) (themeList []*ThemeMetaInfo, themeMap map[string]*ThemeMetaInfo) {
|
||||
var themeDir fs.ReadDirFS
|
||||
var themePath string
|
||||
|
||||
if isViteDevMode {
|
||||
// In vite dev mode, Vite serves themes directly from source files.
|
||||
themeDir, themePath = os.DirFS(setting.StaticRootPath).(fs.ReadDirFS), "web_src/css/themes"
|
||||
} else {
|
||||
// Without vite dev server, use built assets from AssetFS.
|
||||
themeDir, themePath = public.AssetFS(), "assets/css"
|
||||
}
|
||||
|
||||
var foundThemes []*ThemeMetaInfo
|
||||
for _, fileName := range cssFiles {
|
||||
if strings.HasPrefix(fileName, fileNamePrefix) && strings.HasSuffix(fileName, fileNameSuffix) {
|
||||
content, err := public.AssetFS().ReadFile("/assets/css/" + fileName)
|
||||
if err != nil {
|
||||
log.Error("Failed to read theme file %q: %v", fileName, err)
|
||||
continue
|
||||
}
|
||||
foundThemes = append(foundThemes, parseThemeMetaInfo(fileName, util.UnsafeBytesToString(content)))
|
||||
}
|
||||
foundThemes, err := collectThemeFiles(themeDir, themePath)
|
||||
if err != nil {
|
||||
log.Error("Failed to load theme files: %v", err)
|
||||
return themeList, themeMap
|
||||
}
|
||||
|
||||
themeList = foundThemes
|
||||
@ -187,20 +210,21 @@ func loadThemesFromAssets() (themeList []*ThemeMetaInfo, themeMap map[string]*Th
|
||||
return themeList, themeMap
|
||||
}
|
||||
|
||||
func getAvailableThemes() (themeList []*ThemeMetaInfo, themeMap map[string]*ThemeMetaInfo) {
|
||||
themeMu.RLock()
|
||||
if availableThemes != nil {
|
||||
themeList, themeMap = availableThemes.themeList, availableThemes.themeMap
|
||||
}
|
||||
themeMu.RUnlock()
|
||||
if len(themeList) != 0 {
|
||||
return themeList, themeMap
|
||||
func getAvailableThemes() *themeCollectionStruct {
|
||||
themes := themeCollection.Load()
|
||||
|
||||
now := time.Now()
|
||||
if themes != nil && now.Sub(themes.lastCheckTime) < time.Second {
|
||||
return themes
|
||||
}
|
||||
|
||||
themeMu.Lock()
|
||||
defer themeMu.Unlock()
|
||||
// no need to double-check "availableThemes.themeList" since the loading isn't really slow, to keep code simple
|
||||
themeList, themeMap = loadThemesFromAssets()
|
||||
isViteDevMode := public.IsViteDevMode()
|
||||
useLoadedThemes := themes != nil && (setting.IsProd || themes.usingViteDevMode == isViteDevMode)
|
||||
if useLoadedThemes && len(themes.themeList) > 0 {
|
||||
return themes
|
||||
}
|
||||
|
||||
themeList, themeMap := loadThemesFromAssets(isViteDevMode)
|
||||
hasAvailableThemes := len(themeList) > 0
|
||||
if !hasAvailableThemes {
|
||||
defaultTheme := defaultThemeMetaInfoByInternalName(setting.UI.DefaultTheme)
|
||||
@ -215,27 +239,19 @@ func getAvailableThemes() (themeList []*ThemeMetaInfo, themeMap map[string]*Them
|
||||
if themeMap[setting.UI.DefaultTheme] == nil {
|
||||
setting.LogStartupProblem(1, log.ERROR, "Default theme %q is not available, please correct the '[ui].DEFAULT_THEME' setting in the config file", setting.UI.DefaultTheme)
|
||||
}
|
||||
availableThemes = &themeCollection{themeList, themeMap}
|
||||
return themeList, themeMap
|
||||
}
|
||||
|
||||
// In dev mode, only store the loaded themes if the list is not empty, in case the frontend is still being built.
|
||||
// TBH, there still could be a data-race that the themes are only partially built then the list is incomplete for first time loading.
|
||||
// Such edge case can be handled by checking whether the loaded themes are the same in a period or there is a flag file, but it is an over-kill, so, no.
|
||||
if hasAvailableThemes {
|
||||
availableThemes = &themeCollection{themeList, themeMap}
|
||||
}
|
||||
return themeList, themeMap
|
||||
}
|
||||
|
||||
func GetAvailableThemes() []*ThemeMetaInfo {
|
||||
themes, _ := getAvailableThemes()
|
||||
themes = &themeCollectionStruct{now, isViteDevMode, themeList, themeMap}
|
||||
themeCollection.Store(themes)
|
||||
return themes
|
||||
}
|
||||
|
||||
func GetAvailableThemes() []*ThemeMetaInfo {
|
||||
return getAvailableThemes().themeList
|
||||
}
|
||||
|
||||
func GetThemeMetaInfo(internalName string) *ThemeMetaInfo {
|
||||
_, themeMap := getAvailableThemes()
|
||||
return themeMap[internalName]
|
||||
return getAvailableThemes().themeMap[internalName]
|
||||
}
|
||||
|
||||
// GuaranteeGetThemeMetaInfo guarantees to return a non-nil ThemeMetaInfo,
|
||||
|
||||
@ -44,7 +44,7 @@ parts:
|
||||
source: .
|
||||
stage-packages: [ git, sqlite3, openssh-client ]
|
||||
build-packages: [ git, libpam0g-dev, libsqlite3-dev, build-essential]
|
||||
build-snaps: [ go/1.25/stable, node/22/stable ]
|
||||
build-snaps: [ go/1.26/stable, node/24/stable ]
|
||||
build-environment:
|
||||
- LDFLAGS: ""
|
||||
override-pull: |
|
||||
|
||||
@ -4,17 +4,22 @@
|
||||
<a target="_blank" href="https://about.gitea.com">{{ctx.Locale.Tr "powered_by" "Gitea"}}</a>
|
||||
{{end}}
|
||||
{{if (or .ShowFooterVersion .PageIsAdmin)}}
|
||||
<span>
|
||||
{{ctx.Locale.Tr "version"}}:
|
||||
{{if .IsAdmin}}
|
||||
<a href="{{AppSubUrl}}/-/admin/config">{{AppVer}}</a>
|
||||
{{else}}
|
||||
{{AppVer}}
|
||||
{{end}}
|
||||
</span>
|
||||
{{end}}
|
||||
{{if and .TemplateLoadTimes ShowFooterTemplateLoadTime}}
|
||||
{{ctx.Locale.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong>
|
||||
{{ctx.Locale.Tr "template"}}{{if .TemplateName}} {{.TemplateName}}{{end}}: <strong>{{call .TemplateLoadTimes}}</strong>
|
||||
<span>
|
||||
{{ctx.Locale.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong>
|
||||
{{ctx.Locale.Tr "template"}}{{if .TemplateName}} {{.TemplateName}}{{end}}: <strong>{{call .TemplateLoadTimes}}</strong>
|
||||
</span>
|
||||
{{end}}
|
||||
{{if $.ViteModeIsDev}}<span class="ui basic label primary">ViteDevMode</span>{{end}}
|
||||
</div>
|
||||
<div class="right-links" role="group" aria-label="{{ctx.Locale.Tr "aria.footer.links"}}">
|
||||
<div class="ui dropdown custom" id="footer-theme-selector">
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
<span class="text">
|
||||
{{ctx.AvatarUtils.Avatar .SignedUser 24 "tw-mr-1"}}
|
||||
<span class="only-mobile">{{.SignedUser.Name}}</span>
|
||||
<span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
|
||||
<span class="not-mobile flex-text-block">{{svg "octicon-triangle-down"}}</span>
|
||||
</span>
|
||||
<div class="menu user-menu">
|
||||
<div class="header">
|
||||
@ -64,9 +64,9 @@
|
||||
{{else if .IsSigned}}
|
||||
{{template "base/head_navbar_icons" dict "ItemExtraClass" "not-mobile" "PageGlobalData" .PageGlobalData}}
|
||||
<div class="ui dropdown jump item" data-tooltip-content="{{ctx.Locale.Tr "create_new"}}">
|
||||
<span class="text">
|
||||
<span class="flex-text-block">
|
||||
{{svg "octicon-plus"}}
|
||||
<span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
|
||||
<span class="not-mobile flex-text-block">{{svg "octicon-triangle-down"}}</span>
|
||||
<span class="only-mobile">{{ctx.Locale.Tr "create_new"}}</span>
|
||||
</span>
|
||||
<div class="menu">
|
||||
@ -93,7 +93,7 @@
|
||||
{{if .IsAdmin}}{{svg "octicon-shield-check" 16 "navbar-admin-badge"}}{{end}}
|
||||
</span>
|
||||
<span class="only-mobile">{{.SignedUser.Name}}</span>
|
||||
<span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
|
||||
<span class="not-mobile flex-text-block">{{svg "octicon-triangle-down"}}</span>
|
||||
</span>
|
||||
<div class="menu user-menu">
|
||||
<div class="header">
|
||||
|
||||
@ -4,13 +4,13 @@
|
||||
{{- $activeStopwatch := call $data.GetActiveStopwatch -}}
|
||||
{{- $notificationUnreadCount := call $data.GetNotificationUnreadCount -}}
|
||||
<a class="item active-stopwatch{{if not $activeStopwatch}} tw-hidden{{end}} {{$itemExtraClass}}" {{if $activeStopwatch}}href="{{$activeStopwatch.IssueLink}}" data-seconds="{{$activeStopwatch.Seconds}}"{{end}} title="{{ctx.Locale.Tr "active_stopwatch"}}">
|
||||
<div class="tw-relative">
|
||||
<div class="tw-relative flex-text-block">
|
||||
{{svg "octicon-stopwatch"}}
|
||||
<span class="header-stopwatch-dot"></span>
|
||||
</div>
|
||||
</a>
|
||||
<a class="item {{$itemExtraClass}}" href="{{AppSubUrl}}/notifications" data-tooltip-content="{{ctx.Locale.Tr "notifications"}}">
|
||||
<div class="tw-relative">
|
||||
<div class="tw-relative flex-text-block">
|
||||
{{svg "octicon-bell"}}
|
||||
<span class="notification_count{{if not $notificationUnreadCount}} tw-hidden{{end}}">{{$notificationUnreadCount}}</span>
|
||||
</div>
|
||||
|
||||
@ -4,6 +4,13 @@
|
||||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
|
||||
{{if .IsOrganizationOwner}}
|
||||
<div class="flex-text-block">
|
||||
<div class="tw-flex-1">{{ctx.Locale.Tr "org.teams.manage_team_member_prompt"}}</div>
|
||||
<a class="ui primary button" href="./teams">{{ctx.Locale.Tr "org.teams.manage_team_member"}}</a>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
{{end}}
|
||||
<div class="flex-list">
|
||||
{{range .Members}}
|
||||
{{$isPublic := index $.MembersIsPublicMember .ID}}
|
||||
@ -15,27 +22,27 @@
|
||||
<div class="flex-item-title">
|
||||
{{template "shared/user/name" .}}
|
||||
{{if not $isPublic}}
|
||||
<span class="ui basic tiny label">{{ctx.Locale.Tr "org.members.private"}}</span>
|
||||
<span class="ui basic small label">{{ctx.Locale.Tr "org.members.private"}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if not $.PublicOnly}}
|
||||
<div class="flex-item-body">
|
||||
<div class="tw-flex tw-flex-col tw-gap-1">
|
||||
{{if not $.PublicOnly}}
|
||||
<div>
|
||||
{{ctx.Locale.Tr "org.members.member_role"}}
|
||||
<strong class="flex-text-inline">{{if index $.MembersIsUserOrgOwner .ID}}{{svg "octicon-shield-lock"}} {{ctx.Locale.Tr "org.members.owner"}}{{else}}{{ctx.Locale.Tr "org.members.member"}}{{end}}</strong>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if $.IsOrganizationOwner}}
|
||||
<div class="flex-item-body">
|
||||
{{ctx.Locale.Tr "admin.users.2fa"}}
|
||||
<strong>
|
||||
{{if index $.MembersTwoFaStatus .ID}}
|
||||
<span class="tw-text-green">{{svg "octicon-check"}}</span>
|
||||
{{else}}
|
||||
{{svg "octicon-x"}}
|
||||
{{end}}
|
||||
</strong>
|
||||
<div>
|
||||
{{ctx.Locale.Tr "admin.users.2fa"}}:
|
||||
{{if index $.MembersTwoFaStatus .ID}}
|
||||
<span class="tw-text-green tw-flex">{{svg "octicon-check"}}</span>
|
||||
{{else}}
|
||||
{{svg "octicon-x"}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-item-trailing">
|
||||
{{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}
|
||||
@ -46,45 +53,23 @@
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if eq $.SignedUser.ID .ID}}
|
||||
<form>
|
||||
<button class="ui red tiny button delete-button" data-modal-id="leave-organization"
|
||||
data-url="{{$.OrgLink}}/members/action/leave" data-datauid="{{.ID}}"
|
||||
data-name="{{.DisplayName}}"
|
||||
data-data-organization-name="{{$.Org.DisplayName}}">{{ctx.Locale.Tr "org.members.leave"}}</button>
|
||||
</form>
|
||||
<button class="ui red tiny button link-action"
|
||||
data-url="{{$.OrgLink}}/members/action/leave?uid={{.ID}}"
|
||||
data-modal-confirm-header="{{ctx.Locale.Tr "org.members.leave"}}"
|
||||
data-modal-confirm-content="{{ctx.Locale.Tr "org.members.leave.detail" $.Org.DisplayName}}"
|
||||
>{{ctx.Locale.Tr "org.members.leave"}}</button>
|
||||
{{else if $.IsOrganizationOwner}}
|
||||
<form>
|
||||
<button class="ui red tiny button delete-button" data-modal-id="remove-organization-member"
|
||||
data-url="{{$.OrgLink}}/members/action/remove" data-datauid="{{.ID}}"
|
||||
data-name="{{.DisplayName}}"
|
||||
data-data-organization-name="{{$.Org.DisplayName}}">{{ctx.Locale.Tr "org.members.remove"}}</button>
|
||||
</form>
|
||||
<button class="ui red tiny button link-action"
|
||||
data-url="{{$.OrgLink}}/members/action/remove?uid={{.ID}}"
|
||||
data-modal-confirm-header="{{ctx.Locale.Tr "org.members.remove"}}"
|
||||
data-modal-confirm-content="{{ctx.Locale.Tr "org.members.remove.detail" .DisplayName $.Org.DisplayName}}"
|
||||
>{{ctx.Locale.Tr "org.members.remove"}}</button>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{template "base/paginate" .}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui g-modal-confirm delete modal" id="leave-organization">
|
||||
<div class="header">
|
||||
{{ctx.Locale.Tr "org.members.leave"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{ctx.Locale.Tr "org.members.leave.detail" (HTMLFormat `<span class="%s"></span>` "dataOrganizationName")}}</p>
|
||||
</div>
|
||||
{{template "base/modal_actions_confirm" .}}
|
||||
</div>
|
||||
<div class="ui g-modal-confirm delete modal" id="remove-organization-member">
|
||||
<div class="header">
|
||||
{{ctx.Locale.Tr "org.members.remove"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{ctx.Locale.Tr "org.members.remove.detail" (HTMLFormat `<span class="%s"></span>` "name") (HTMLFormat `<span class="%s"></span>` "dataOrganizationName")}}</p>
|
||||
</div>
|
||||
{{template "base/modal_actions_confirm" .}}
|
||||
</div>
|
||||
|
||||
{{template "base/footer" .}}
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
{{template "org/team/sidebar" .}}
|
||||
<div class="ui ten wide column">
|
||||
{{template "org/team/navbar" .}}
|
||||
{{$hasTopAttachedSegment := false}}
|
||||
{{$canAddRemove := and $.IsOrganizationOwner (not $.Team.IncludesAllRepositories)}}
|
||||
{{if $canAddRemove}}
|
||||
<div class="ui top attached segment tw-flex tw-flex-wrap tw-gap-2">
|
||||
{{$hasTopAttachedSegment = true}}
|
||||
<div class="ui top attached segment flex-text-block tw-flex-wrap">
|
||||
<form class="ui form ignore-dirty tw-flex-1 tw-flex" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post">
|
||||
<div data-global-init="initSearchRepoBox" data-uid="{{.Org.ID}}" class="ui search">
|
||||
<div class="ui input">
|
||||
@ -24,7 +26,11 @@
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="ui{{if not $canAddRemove}} top{{end}} attached segment">
|
||||
{{if $.Team.IncludesAllRepositories}}
|
||||
{{$hasTopAttachedSegment = true}}
|
||||
<div class="ui top attached segment">{{ctx.Locale.Tr "org.teams.all_repositories"}}</div>
|
||||
{{end}}
|
||||
<div class="ui {{if not $hasTopAttachedSegment}}top{{end}} attached segment">
|
||||
<div class="flex-list">
|
||||
{{range $.TeamRepos}}
|
||||
<div class="flex-item tw-items-center">
|
||||
|
||||
@ -26,7 +26,8 @@
|
||||
</div>
|
||||
{{if eq .Team.LowerName "owners"}}
|
||||
<div class="item">
|
||||
{{ctx.Locale.Tr "org.teams.owners_permission_desc"}}
|
||||
<p>{{ctx.Locale.Tr "org.teams.owners_permission_desc"}}</p>
|
||||
<p>{{ctx.Locale.Tr "org.teams.owners_permission_suggestion"}}</p>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
{{if .IsOrganizationOwner}}
|
||||
<div class="flex-text-block tw-justify-end">
|
||||
<div class="flex-text-block">
|
||||
<div class="tw-flex-1">{{ctx.Locale.Tr "org.teams.manage_team_member_prompt"}}</div>
|
||||
<a class="ui primary button" href="{{.OrgLink}}/teams/new">{{svg "octicon-plus"}} {{ctx.Locale.Tr "org.create_new_team"}}</a>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
data-locale-all-jobs="{{ctx.Locale.Tr "actions.runs.all_jobs"}}"
|
||||
data-locale-triggered-via="{{ctx.Locale.Tr "actions.runs.triggered_via"}}"
|
||||
data-locale-total-duration="{{ctx.Locale.Tr "actions.runs.total_duration"}}"
|
||||
data-locale-run-details="{{ctx.Locale.Tr "actions.runs.run_details"}}"
|
||||
data-locale-workflow-file="{{ctx.Locale.Tr "actions.runs.workflow_file"}}"
|
||||
data-locale-status-unknown="{{ctx.Locale.Tr "actions.status.unknown"}}"
|
||||
data-locale-status-waiting="{{ctx.Locale.Tr "actions.status.waiting"}}"
|
||||
data-locale-status-running="{{ctx.Locale.Tr "actions.status.running"}}"
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
{{- end}}
|
||||
</h3>
|
||||
<div class="field">
|
||||
<input name="commit_summary" maxlength="100" placeholder="{{if .PageIsDelete}}{{ctx.Locale.Tr "repo.editor.delete" .TreePath}}{{else if .PageIsUpload}}{{ctx.Locale.Tr "repo.editor.upload_files_to_dir" .TreePath}}{{else if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.add_tmpl"}}{{else if .PageIsPatch}}{{ctx.Locale.Tr "repo.editor.patch"}}{{else}}{{ctx.Locale.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}" autofocus>
|
||||
<input name="commit_summary" maxlength="100" placeholder="{{if .PageIsDelete}}{{ctx.Locale.Tr "repo.editor.delete" .TreePath}}{{else if .PageIsUpload}}{{ctx.Locale.Tr "repo.editor.upload_files_to_dir" .TreePath}}{{else if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.add_tmpl"}}{{else if .PageIsPatch}}{{ctx.Locale.Tr "repo.editor.patch"}}{{else}}{{ctx.Locale.Tr "repo.editor.update" .TreePath}}{{end}}" value="{{.commit_summary}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<textarea name="commit_message" placeholder="{{ctx.Locale.Tr "repo.editor.commit_message_desc"}}" rows="5">{{.commit_message}}</textarea>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
{{range $i, $v := .TreeNames}}
|
||||
<div class="breadcrumb-divider">/</div>
|
||||
{{if eq $i $l}}
|
||||
<input id="file-name" maxlength="255" value="{{$v}}" placeholder="{{ctx.Locale.Tr (Iif $.PageIsUpload "repo.editor.add_subdir" "repo.editor.name_your_file")}}" data-code-editor-config="{{JsonUtils.EncodeToString $.CodeEditorConfig}}" {{Iif $.PageIsUpload "" "required"}} autofocus>
|
||||
<input id="file-name" maxlength="255" value="{{$v}}" placeholder="{{ctx.Locale.Tr (Iif $.PageIsUpload "repo.editor.add_subdir" "repo.editor.name_your_file")}}" {{Iif $.PageIsUpload "" "required"}}>
|
||||
<span data-tooltip-content="{{ctx.Locale.Tr "repo.editor.filename_help"}}">{{svg "octicon-info"}}</span>
|
||||
{{else}}
|
||||
<span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span>
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
<div class="flex-text-block tw-justify-between tw-flex-wrap">
|
||||
<div class="ui compact small menu small-menu-items repo-editor-menu tw-self-start">
|
||||
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a>
|
||||
<a class="item" data-tab="preview" data-preview-url="{{.Repository.Link}}/markup" data-preview-context-ref="{{.RepoLink}}/src/{{.RefTypeNameSubURL}}">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
|
||||
<a class="item{{if not .CodeEditorConfig.Previewable}} tw-hidden{{end}}" data-tab="preview" data-preview-url="{{.Repository.Link}}/markup" data-preview-context-ref="{{.RepoLink}}/src/{{.RefTypeNameSubURL}}">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
|
||||
{{if not .IsNewFile}}
|
||||
<a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a>
|
||||
{{end}}
|
||||
@ -32,8 +32,8 @@
|
||||
<div class="ui bottom attached segment tw-p-0">
|
||||
<div class="ui active tab tw-rounded-b" data-tab="write">
|
||||
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
|
||||
data-previewable-extensions="{{StringUtils.Join $.CodeEditorConfig.PreviewableExtensions ","}}"
|
||||
data-line-wrap-extensions="{{StringUtils.Join $.CodeEditorConfig.LineWrapExtensions ","}}">{{.FileContent}}</textarea>
|
||||
data-code-editor-config="{{JsonUtils.EncodeToString $.CodeEditorConfig}}"
|
||||
placeholder="{{ctx.Locale.Tr "editor.code_editor.placeholder"}}">{{.FileContent}}</textarea>
|
||||
<div class="editor-loading is-loading"></div>
|
||||
</div>
|
||||
<div class="ui tab tw-px-4 tw-py-3" data-tab="preview">
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
{{$indentStyle := $.CodeEditorConfig.IndentStyle}}
|
||||
{{$indentSize := or $.CodeEditorConfig.IndentSize 4}}
|
||||
{{$lineWrapOn := $.CodeEditorConfig.LineWrapOn}}
|
||||
{{$lineWrap := $.CodeEditorConfig.LineWrap}}
|
||||
<div class="flex-text-block code-editor-options">
|
||||
<button type="button" class="js-code-find ui compact mini icon button" aria-label="{{ctx.Locale.Tr "editor.code_editor.find"}}">{{svg "octicon-search"}}</button>
|
||||
<button type="button" class="js-code-command-palette ui compact mini icon button" aria-label="{{ctx.Locale.Tr "editor.code_editor.command_palette"}}">{{svg "octicon-command-palette"}}</button>
|
||||
<div class="native-select">
|
||||
<select class="js-indent-style-select" aria-label="{{ctx.Locale.Tr "text_indent_style"}}">
|
||||
<optgroup label="{{ctx.Locale.Tr "text_indent_style"}}">
|
||||
@ -22,8 +24,8 @@
|
||||
<div class="native-select">
|
||||
<select class="js-line-wrap-select" aria-label="{{ctx.Locale.Tr "text_line_wrap_mode"}}">
|
||||
<optgroup label="{{ctx.Locale.Tr "text_line_wrap_mode"}}">
|
||||
<option{{if $lineWrapOn}} selected{{end}} value="on">{{ctx.Locale.Tr "text_line_wrap"}}</option>
|
||||
<option{{if not $lineWrapOn}} selected{{end}} value="off">{{ctx.Locale.Tr "text_line_nowrap"}}</option>
|
||||
<option{{if $lineWrap}} selected{{end}} value="on">{{ctx.Locale.Tr "text_line_wrap"}}</option>
|
||||
<option{{if not $lineWrap}} selected{{end}} value="off">{{ctx.Locale.Tr "text_line_nowrap"}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@ -31,7 +31,9 @@
|
||||
<div class="ui bottom attached segment tw-p-0">
|
||||
<div class="ui active tab tw-rounded-b" data-tab="write">
|
||||
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-patch"
|
||||
data-context="{{.RepoLink}}">{{.FileContent}}</textarea>
|
||||
data-code-editor-config="{{JsonUtils.EncodeToString $.CodeEditorConfig}}"
|
||||
data-context="{{.RepoLink}}"
|
||||
placeholder="{{ctx.Locale.Tr "editor.code_editor.placeholder"}}">{{.FileContent}}</textarea>
|
||||
<div class="editor-loading is-loading"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="issue-content-right ui segment">
|
||||
<div class="issue-content-right ui segment" data-global-init="initRepoIssueSidebar">
|
||||
{{template "repo/issue/branch_selector_field" $}}{{/* TODO: RemoveIssueRef: template "repo/issue/branch_selector_field" $*/}}
|
||||
|
||||
{{if .PageIsComparePull}}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<div class="issue-sidebar-combo" data-selection-mode="single" data-update-algo="all"
|
||||
{{if $pageMeta.Issue}}data-update-url="{{$pageMeta.RepoLink}}/issues/projects?issue_ids={{$pageMeta.Issue.ID}}"{{end}}
|
||||
>
|
||||
<input class="combo-value" name="project_id" type="hidden" value="{{$data.SelectedProjectID}}">
|
||||
<input class="combo-value" name="project_id" type="hidden" value="{{if and $pageMeta.CanModifyIssueOrPull $data.SelectedProjectIDs}}{{index $data.SelectedProjectIDs 0}}{{end}}">
|
||||
<div class="ui dropdown full-width {{if not $pageMeta.CanModifyIssueOrPull}}disabled{{end}}">
|
||||
<a class="fixed-text muted">
|
||||
<strong>{{ctx.Locale.Tr "repo.issues.new.projects"}}</strong> {{if $pageMeta.CanModifyIssueOrPull}}{{svg "octicon-gear"}}{{end}}
|
||||
|
||||
@ -66,6 +66,7 @@
|
||||
</div>
|
||||
|
||||
{{template "repo/issue/view_content/comments" .}}
|
||||
<div class="timeline-item tw-hidden" id="timeline-comments-end"></div>
|
||||
|
||||
{{if and .Issue.IsPull (not $.Repository.IsArchived)}}
|
||||
{{template "repo/issue/view_content/pull_merge_box".}}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<div class="issue-content-right ui segment">
|
||||
<div class="issue-content-right ui segment" data-global-init="initRepoIssueSidebar">
|
||||
{{template "repo/issue/branch_selector_field" $}}{{/* TODO: RemoveIssueRef: template "repo/issue/branch_selector_field" $*/}}
|
||||
|
||||
{{if .Issue.IsPull}}
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
<input type="hidden" name="watch" value="{{if $.IssueWatch.IsWatching}}0{{else}}1{{end}}">
|
||||
<button class="fluid ui button">
|
||||
{{if $.IssueWatch.IsWatching}}
|
||||
{{svg "octicon-mute" 16 "tw-mr-2"}}
|
||||
{{svg "octicon-mute" 16}}
|
||||
{{ctx.Locale.Tr "repo.issues.unsubscribe"}}
|
||||
{{else}}
|
||||
{{svg "octicon-unmute" 16 "tw-mr-2"}}
|
||||
{{svg "octicon-unmute" 16}}
|
||||
{{ctx.Locale.Tr "repo.issues.subscribe"}}
|
||||
{{end}}
|
||||
</button>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="repo-setting-content">
|
||||
<form class="ui form" action="{{.Link}}" method="post">
|
||||
<h4 class="ui top attached header flex-text-block tw-justify-between tw-flex-wrap">
|
||||
{{ctx.Locale.Tr "repo.settings.githooks"}}
|
||||
{{.Hook.Name}}
|
||||
<div class="tw-font-normal tw-font-sans tw-text-base">
|
||||
{{template "repo/editor/options" dict "CodeEditorConfig" $.CodeEditorConfig}}
|
||||
</div>
|
||||
@ -10,13 +10,10 @@
|
||||
<div class="ui attached segment">
|
||||
<p>{{ctx.Locale.Tr "repo.settings.githook_edit_desc"}}</p>
|
||||
{{with .Hook}}
|
||||
<div class="inline field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.githook_name"}}</label>
|
||||
<span class="hook-filename">{{.Name}}</span>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="content">{{ctx.Locale.Tr "repo.settings.githook_content"}}</label>
|
||||
<textarea id="content" name="content" class="tw-hidden">{{if .IsActive}}{{.Content}}{{else}}{{.Sample}}{{end}}</textarea>
|
||||
<textarea id="content" name="content" class="tw-hidden"
|
||||
data-code-editor-config="{{JsonUtils.EncodeToString $.CodeEditorConfig}}"
|
||||
placeholder="{{ctx.Locale.Tr "editor.code_editor.placeholder"}}">{{if .IsActive}}{{.Content}}{{else}}{{.Sample}}{{end}}</textarea>
|
||||
<div class="editor-loading is-loading"></div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
|
||||
@ -14,7 +14,8 @@
|
||||
<div class="item">
|
||||
<span class="{{if eq .LastStatus 1}}tw-text-green{{else if eq .LastStatus 2}}tw-text-red{{else}}tw-text-text-light{{end}}">{{svg "octicon-dot-fill" 22}}</span>
|
||||
<div class="gt-ellipsis tw-flex-1">
|
||||
<a title="{{.URL}}" href="{{$.BaseLink}}/{{.ID}}">{{.URL}}</a>
|
||||
<a title="{{.URL}}" href="{{$.BaseLink}}/{{.ID}}">{{or .Name (ctx.Locale.Tr "repo.settings.webhook.name_empty")}}</a>
|
||||
<span class="tw-ml-2 tw-text-grey-light">{{.URL}}</span>
|
||||
</div>
|
||||
<a class="muted tw-p-2" href="{{$.BaseLink}}/{{.ID}}">{{svg "octicon-pencil"}}</a>
|
||||
<a class="tw-text-red tw-p-2 link-action"
|
||||
|
||||
@ -6,6 +6,12 @@
|
||||
*/}}
|
||||
{{$isNew := not .Webhook.ID}}
|
||||
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.webhook.name"}}</label>
|
||||
<input name="name" type="text" value="{{.Webhook.Name}}" maxlength="255">
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.webhook.name_helper"}}</p>
|
||||
</div>
|
||||
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="active" type="checkbox" {{if or $isNew .Webhook.IsActive}}checked{{end}}>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
<div class="flex-item-leading">
|
||||
{{/* using some tw helpers is the only way to align the checkbox */}}
|
||||
<div class="flex-text-inline tw-mt-[2px]">
|
||||
<div class="flex-text-inline tw-mt-[3px]">
|
||||
{{if $.CanWriteIssuesOrPulls}}
|
||||
<input type="checkbox" autocomplete="off" class="issue-checkbox tw-mr-[14px]" data-issue-id={{.ID}} aria-label="{{ctx.Locale.Tr "repo.issues.action_check"}} "{{.Title}}"">
|
||||
{{end}}
|
||||
|
||||
40
templates/swagger/v1_json.tmpl
generated
40
templates/swagger/v1_json.tmpl
generated
@ -10362,6 +10362,7 @@
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"description": "Pass `content_version` to enable optimistic locking on body edits.\nIf the version doesn't match the current value, the request fails with 409 Conflict.\n",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@ -23462,6 +23463,11 @@
|
||||
},
|
||||
"x-go-name": "Events"
|
||||
},
|
||||
"name": {
|
||||
"description": "Optional human-readable name for the webhook",
|
||||
"type": "string",
|
||||
"x-go-name": "Name"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@ -24728,6 +24734,11 @@
|
||||
"type": "string"
|
||||
},
|
||||
"x-go-name": "Events"
|
||||
},
|
||||
"name": {
|
||||
"description": "Optional human-readable name",
|
||||
"type": "string",
|
||||
"x-go-name": "Name"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
@ -24766,6 +24777,12 @@
|
||||
"type": "string",
|
||||
"x-go-name": "Body"
|
||||
},
|
||||
"content_version": {
|
||||
"description": "The current version of the issue content to detect conflicts during editing",
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"x-go-name": "ContentVersion"
|
||||
},
|
||||
"due_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
@ -24938,6 +24955,12 @@
|
||||
"type": "string",
|
||||
"x-go-name": "Body"
|
||||
},
|
||||
"content_version": {
|
||||
"description": "The current version of the pull request content to detect conflicts during editing",
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"x-go-name": "ContentVersion"
|
||||
},
|
||||
"due_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
@ -26136,6 +26159,11 @@
|
||||
"format": "int64",
|
||||
"x-go-name": "ID"
|
||||
},
|
||||
"name": {
|
||||
"description": "Optional human-readable name for the webhook",
|
||||
"type": "string",
|
||||
"x-go-name": "Name"
|
||||
},
|
||||
"type": {
|
||||
"description": "The type of the webhook (e.g., gitea, slack, discord)",
|
||||
"type": "string",
|
||||
@ -26223,6 +26251,12 @@
|
||||
"format": "int64",
|
||||
"x-go-name": "Comments"
|
||||
},
|
||||
"content_version": {
|
||||
"description": "The version of the issue content for optimistic locking",
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"x-go-name": "ContentVersion"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
@ -27725,6 +27759,12 @@
|
||||
"format": "int64",
|
||||
"x-go-name": "Comments"
|
||||
},
|
||||
"content_version": {
|
||||
"description": "The version of the pull request content for optimistic locking",
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"x-go-name": "ContentVersion"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
|
||||
18
templates/user/auth/external_auth_methods.tmpl
Normal file
18
templates/user/auth/external_auth_methods.tmpl
Normal file
@ -0,0 +1,18 @@
|
||||
<div id="external-login-navigator" class="tw-py-1 tw-flex tw-flex-col tw-gap-3">
|
||||
{{range $provider := .OAuth2Providers}}
|
||||
{{/* use QueryEscape for consistent with frontend urlQueryEscape, it is right for a path component */}}
|
||||
<a class="ui button external-login-link tw-gap-3" data-require-appurl-check="true" rel="nofollow" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName | QueryEscape}}">
|
||||
{{$provider.IconHTML 24}} {{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if .EnableOpenIDSignIn}}
|
||||
<a class="ui button external-login-link tw-gap-3" data-require-appurl-check="true" rel="nofollow" href="{{AppSubUrl}}/user/login/openid">
|
||||
{{svg "fontawesome-openid" 24}} {{ctx.Locale.Tr "sign_in_with_provider" "OpenID"}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if .EnableSSPI}}
|
||||
<a class="ui button external-login-link tw-gap-3" rel="nofollow" href="{{AppSubUrl}}/user/login?auth_with_sspi=1">
|
||||
{{svg "fontawesome-windows" 24}} Windows SSPI
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
@ -1,24 +0,0 @@
|
||||
<div id="oauth2-login-navigator" class="tw-py-1">
|
||||
<div class="tw-flex tw-flex-col tw-justify-center">
|
||||
<div id="oauth2-login-navigator-inner" class="tw-flex tw-flex-col tw-flex-wrap tw-items-center tw-gap-2">
|
||||
{{range $provider := .OAuth2Providers}}
|
||||
<a class="{{$provider.Name}} ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
|
||||
{{$provider.IconHTML 28}}
|
||||
{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if .EnableOpenIDSignIn}}
|
||||
<a class="openid ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full" href="{{AppSubUrl}}/user/login/openid">
|
||||
{{svg "fontawesome-openid" 28 "tw-mr-2"}}
|
||||
{{ctx.Locale.Tr "sign_in_with_provider" "OpenID"}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if .EnableSSPI}}
|
||||
<a class="ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full" rel="nofollow" href="{{AppSubUrl}}/user/login?auth_with_sspi=1">
|
||||
{{svg "fontawesome-windows"}}
|
||||
SSPI
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -46,14 +46,13 @@
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{{end}}{{/*if .EnablePasswordSignInForm*/}}
|
||||
{{/* "oauth_container" contains not only "oauth2" methods, but also "OIDC" and "SSPI" methods */}}
|
||||
{{$showOAuth2Methods := or .OAuth2Providers .EnableOpenIDSignIn .EnableSSPI}}
|
||||
{{if and $showOAuth2Methods .EnablePasswordSignInForm}}
|
||||
{{end}}{{/*end if .EnablePasswordSignInForm*/}}
|
||||
{{$showExternalAuthMethods := or .OAuth2Providers .EnableOpenIDSignIn .EnableSSPI}}
|
||||
{{if and $showExternalAuthMethods .EnablePasswordSignInForm}}
|
||||
<div class="divider divider-text">{{ctx.Locale.Tr "sign_in_or"}}</div>
|
||||
{{end}}
|
||||
{{if $showOAuth2Methods}}
|
||||
{{template "user/auth/oauth_container" .}}
|
||||
{{if $showExternalAuthMethods}}
|
||||
{{template "user/auth/external_auth_methods" .}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -49,12 +49,10 @@
|
||||
</button>
|
||||
</div>
|
||||
{{end}}
|
||||
{{/* "oauth_container" contains not only "oauth2" methods, but also "OIDC" and "SSPI" methods */}}
|
||||
{{/* TODO: it seems that "EnableSSPI" is only set in "sign-in" handlers, but it should use the same logic to control its display */}}
|
||||
{{$showOAuth2Methods := or .OAuth2Providers .EnableOpenIDSignIn .EnableSSPI}}
|
||||
{{if $showOAuth2Methods}}
|
||||
{{$showExternalAuthMethods := or .OAuth2Providers .EnableOpenIDSignIn .EnableSSPI}}
|
||||
{{if $showExternalAuthMethods}}
|
||||
<div class="divider divider-text">{{ctx.Locale.Tr "sign_in_or"}}</div>
|
||||
{{template "user/auth/oauth_container" .}}
|
||||
{{template "user/auth/external_auth_methods" .}}
|
||||
{{end}}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user