From 000c06d41bba900e39fd4f4b09449d9cf20fc091 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 26 Nov 2025 23:25:34 +0800 Subject: [PATCH 01/36] Fix oauth2 session gob register (#36017) `gob.Register` must be called before Sessioner Fix #36016 --- go.mod | 2 +- go.sum | 4 ++-- modules/auth/webauthn/webauthn.go | 2 +- routers/common/middleware.go | 12 ++++++++---- routers/install/install.go | 4 ++-- routers/install/routes.go | 8 ++------ routers/web/auth/oauth.go | 6 ++++-- routers/web/web.go | 6 +----- services/auth/source/oauth2/init.go | 5 +---- 9 files changed, 22 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index aa77a62338c..51cf47b2d32 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed gitea.com/go-chi/cache v0.2.1 gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 - gitea.com/go-chi/session v0.0.0-20250926004215-636cadd82e15 + 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 diff --git a/go.sum b/go.sum index 9af066f1e4a..86fe782ae7b 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,8 @@ gitea.com/go-chi/cache v0.2.1 h1:bfAPkvXlbcZxPCpcmDVCWoHgiBSBmZN/QosnZvEC0+g= gitea.com/go-chi/cache v0.2.1/go.mod h1:Qic0HZ8hOHW62ETGbonpwz8WYypj9NieU9659wFUJ8Q= gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo= gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098/go.mod h1:LjzIOHlRemuUyO7WR12fmm18VZIlCAaOt9L3yKw40pk= -gitea.com/go-chi/session v0.0.0-20250926004215-636cadd82e15 h1:qFYmz05u/s9664o7+XEgrlHXSPQ4uHO8/ccZGUb1uxA= -gitea.com/go-chi/session v0.0.0-20250926004215-636cadd82e15/go.mod h1:0iEpFKnwO5dG0aF98O4eq6FMsAiXkNBaDIlUOlq4BtM= +gitea.com/go-chi/session v0.0.0-20251124165456-68e0254e989e h1:4bugwPyGMLvblEm3pZ8fZProSPVxE4l0UXF2Kv6IJoY= +gitea.com/go-chi/session v0.0.0-20251124165456-68e0254e989e/go.mod h1:KDvcfMUoXfATPHs2mbMoXFTXT45/FAFAS39waz9tPk0= gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:+wWBi6Qfruqu7xJgjOIrKVQGiLUZdpKYCZewJ4clqhw= gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:VyMQP6ue6MKHM8UsOXfNfuMKD0oSAWZdXVcpHIN2yaY= gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 h1:IFT+hup2xejHqdhS7keYWioqfmxdnfblFDTGoOwcZ+o= diff --git a/modules/auth/webauthn/webauthn.go b/modules/auth/webauthn/webauthn.go index cbf5279c651..86f55c6b247 100644 --- a/modules/auth/webauthn/webauthn.go +++ b/modules/auth/webauthn/webauthn.go @@ -22,7 +22,7 @@ var WebAuthn *webauthn.WebAuthn // Init initializes the WebAuthn instance from the config. func Init() { - gob.Register(&webauthn.SessionData{}) + gob.Register(&webauthn.SessionData{}) // TODO: CHI-SESSION-GOB-REGISTER. appURL, _ := protocol.FullyQualifiedOrigin(setting.AppURL) diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 07adee18cec..bfa258b9765 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -5,6 +5,7 @@ package common import ( "fmt" + "log" "net/http" "strings" @@ -107,7 +108,11 @@ func ForwardedHeadersHandler(limit int, trustedProxies []string) func(h http.Han return proxy.ForwardedHeaders(opt) } -func Sessioner() (func(next http.Handler) http.Handler, error) { +func MustInitSessioner() func(next http.Handler) http.Handler { + // TODO: CHI-SESSION-GOB-REGISTER: chi-session has a design problem: it calls gob.Register for "Set" + // But if the server restarts, then the first "Get" will fail to decode the previously stored session data because the structs are not registered yet. + // So each package should make sure their structs are registered correctly during startup for session storage. + middleware, err := session.Sessioner(session.Options{ Provider: setting.SessionConfig.Provider, ProviderConfig: setting.SessionConfig.ProviderConfig, @@ -120,8 +125,7 @@ func Sessioner() (func(next http.Handler) http.Handler, error) { Domain: setting.SessionConfig.Domain, }) if err != nil { - return nil, fmt.Errorf("failed to create session middleware: %w", err) + log.Fatalf("common.Sessioner failed: %v", err) } - - return middleware, nil + return middleware } diff --git a/routers/install/install.go b/routers/install/install.go index 4a9dabac6fe..c5acf968bdd 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -55,8 +55,8 @@ func getSupportedDbTypeNames() (dbTypeNames []map[string]string) { return dbTypeNames } -// Contexter prepare for rendering installation page -func Contexter() func(next http.Handler) http.Handler { +// installContexter prepare for rendering installation page +func installContexter() func(next http.Handler) http.Handler { rnd := templates.HTMLRenderer() dbTypeNames := getSupportedDbTypeNames() envConfigKeys := setting.CollectEnvConfigKeys() diff --git a/routers/install/routes.go b/routers/install/routes.go index d47c1f61eeb..0914c921c0c 100644 --- a/routers/install/routes.go +++ b/routers/install/routes.go @@ -8,7 +8,6 @@ import ( "html" "net/http" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/public" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" @@ -25,11 +24,8 @@ func Routes() *web.Router { base.Methods("GET, HEAD", "/assets/*", public.FileHandlerFunc()) r := web.NewRouter() - if sessionMid, err := common.Sessioner(); err == nil && sessionMid != nil { - r.Use(sessionMid, Contexter()) - } else { - log.Fatal("common.Sessioner failed: %v", err) - } + r.Use(common.MustInitSessioner(), installContexter()) + r.Get("/", Install) // it must be on the root, because the "install.js" use the window.location to replace the "localhost" AppURL r.Post("/", web.Bind(forms.InstallForm{}), SubmitInstall) r.Get("/post-install", InstallDone) diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index f1c155e78f5..f7ce5875ca8 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -277,8 +277,11 @@ type LinkAccountData struct { GothUser goth.User } +func init() { + gob.Register(LinkAccountData{}) // TODO: CHI-SESSION-GOB-REGISTER +} + func oauth2GetLinkAccountData(ctx *context.Context) *LinkAccountData { - gob.Register(LinkAccountData{}) v, ok := ctx.Session.Get("linkAccountData").(LinkAccountData) if !ok { return nil @@ -287,7 +290,6 @@ func oauth2GetLinkAccountData(ctx *context.Context) *LinkAccountData { } func Oauth2SetLinkAccountData(ctx *context.Context, linkAccountData LinkAccountData) error { - gob.Register(LinkAccountData{}) return updateSession(ctx, nil, map[string]any{ "linkAccountData": linkAccountData, }) diff --git a/routers/web/web.go b/routers/web/web.go index 8b55e4469ee..dd1b391c689 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -267,11 +267,7 @@ func Routes() *web.Router { routes.Get("/ssh_info", misc.SSHInfo) routes.Get("/api/healthz", healthcheck.Check) - if sessionMid, err := common.Sessioner(); err == nil && sessionMid != nil { - mid = append(mid, sessionMid, context.Contexter()) - } else { - log.Fatal("common.Sessioner failed: %v", err) - } + mid = append(mid, common.MustInitSessioner(), context.Contexter()) // Get user from session if logged in. mid = append(mid, webAuth(buildAuthGroup())) diff --git a/services/auth/source/oauth2/init.go b/services/auth/source/oauth2/init.go index 313f375281b..2a165bac85d 100644 --- a/services/auth/source/oauth2/init.go +++ b/services/auth/source/oauth2/init.go @@ -22,9 +22,6 @@ import ( var gothRWMutex = sync.RWMutex{} -// UsersStoreKey is the key for the store -const UsersStoreKey = "gitea-oauth2-sessions" - // ProviderHeaderKey is the HTTP header key const ProviderHeaderKey = "gitea-oauth2-provider" @@ -33,7 +30,7 @@ func Init(ctx context.Context) error { // Lock our mutex gothRWMutex.Lock() - gob.Register(&sessions.Session{}) + gob.Register(&sessions.Session{}) // TODO: CHI-SESSION-GOB-REGISTER. FIXME: it seems to be an abuse, why the Session struct itself is stored in session store again? gothic.Store = &SessionsStore{ maxLength: int64(setting.OAuth2.MaxTokenLength), From 66707bc3ead8bc716890c30c2c7c3d2481ebcaa6 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 26 Nov 2025 19:13:37 +0100 Subject: [PATCH 02/36] Fix actions lint (#36029) actionlint since https://github.com/rhysd/actionlint/releases/tag/v1.7.9 detects constant conditions and this workflow was being disabled in https://github.com/go-gitea/gitea/commit/58d2a87c6c4431873340cb7c00fa43670d4418aa by such a condition which made the lint fail: https://github.com/go-gitea/gitea/actions/runs/19673752806/job/56349128912?pr=36028 Instead, remove the whole workflow file. I'm sure we can re-create it if the need arises. Also, I locked the actionlint dependency to prevent similar surprises in the future. --- .github/workflows/pull-e2e-tests.yml | 35 ---------------------------- Makefile | 2 +- tests/e2e/README.md | 12 +++------- 3 files changed, 4 insertions(+), 45 deletions(-) delete mode 100644 .github/workflows/pull-e2e-tests.yml diff --git a/.github/workflows/pull-e2e-tests.yml b/.github/workflows/pull-e2e-tests.yml deleted file mode 100644 index 4f806e93bd8..00000000000 --- a/.github/workflows/pull-e2e-tests.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: e2e-tests - -on: - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - files-changed: - uses: ./.github/workflows/files-changed.yml - - test-e2e: - # the "test-e2e" won't pass, and it seems that there is no useful test, so skip - # if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true' - if: false - needs: files-changed - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - check-latest: true - - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v5 - with: - node-version: 24 - - run: make deps-frontend frontend deps-backend - - run: pnpm exec playwright install --with-deps - - run: make test-e2e-sqlite - timeout-minutes: 40 - env: - USE_REPO_TEST_DIR: 1 diff --git a/Makefile b/Makefile index 20a90a959db..4a7e73e5825 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1 XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1 GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 -ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1 +ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.9 GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.20.0 DOCKER_IMAGE ?= gitea/gitea diff --git a/tests/e2e/README.md b/tests/e2e/README.md index db083793d8b..ea3805ab95c 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -17,13 +17,7 @@ make clean frontend ## Install playwright system dependencies ``` -npx playwright install-deps -``` - - -## Run all tests via local act_runner -``` -act_runner exec -W ./.github/workflows/pull-e2e-tests.yml --event=pull_request --default-actions-url="https://github.com" -i catthehacker/ubuntu:runner-latest +pnpm exec playwright install-deps ``` ## Run sqlite e2e tests @@ -85,8 +79,8 @@ TEST_MSSQL_HOST=localhost:1433 TEST_MSSQL_DBNAME=test TEST_MSSQL_USERNAME=sa TES Although the main goal of e2e is assertion testing, we have added a framework for visual regress testing. If you are working on front-end features, please use the following: - Check out `main`, `make clean frontend`, and run e2e tests with `VISUAL_TEST=1` to generate outputs. This will initially fail, as no screenshots exist. You can run the e2e tests again to assert it passes. - - Check out your branch, `make clean frontend`, and run e2e tests with `VISUAL_TEST=1`. You should be able to assert you front-end changes don't break any other tests unintentionally. + - Check out your branch, `make clean frontend`, and run e2e tests with `VISUAL_TEST=1`. You should be able to assert you front-end changes don't break any other tests unintentionally. -VISUAL_TEST=1 will create screenshots in tests/e2e/test-snapshots. The test will fail the first time this is enabled (until we get visual test image persistence figured out), because it will be testing against an empty screenshot folder. +VISUAL_TEST=1 will create screenshots in tests/e2e/test-snapshots. The test will fail the first time this is enabled (until we get visual test image persistence figured out), because it will be testing against an empty screenshot folder. ACCEPT_VISUAL=1 will overwrite the snapshot images with new images. From 1816c7f9c1bb62b8299c76994ea51d589f922701 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 27 Nov 2025 00:36:53 +0000 Subject: [PATCH 03/36] [skip ci] Updated translations via Crowdin --- options/locale/locale_zh-CN.ini | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 6270d353340..73e5b41f4e2 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -426,7 +426,7 @@ need_account=需要一个帐户? sign_up_tip=您正在系统中注册第一个帐户,它拥有管理员权限。请仔细记住您的用户名和密码。 如果您忘记了用户名或密码,请参阅 Gitea 文档以恢复账户。 sign_up_now=立即注册。 sign_up_successful=帐户创建成功。欢迎! -confirmation_mail_sent_prompt_ex=一封新的确认邮件已经发送到 %s。请在下一个 %s 中检查您的收件箱以完成注册流程。 如果您的注册邮箱地址不正确,您可以重新登录并更改它。 +confirmation_mail_sent_prompt_ex=一封新的确认邮件已经发送到 %s。请在 %s 内检查您的收件箱以完成注册流程。 如果您的注册邮箱地址不正确,您可以重新登录并更改它。 must_change_password=更新您的密码 allow_password_change=要求用户更改密码(推荐) reset_password_mail_sent_prompt=确认邮件已被发送到 %s。请您在 %s 内检查您的收件箱 ,完成密码重置流程。 @@ -1483,6 +1483,7 @@ projects.column.new_submit=创建列 projects.column.new=创建列 projects.column.set_default=设为默认 projects.column.set_default_desc=设置此列为未分类问题和合并请求的默认值 +projects.column.default_column_hint=添加到此项目的新议题将被添加到此列 projects.column.delete=删除列 projects.column.deletion_desc=删除项目列会将所有相关问题移至默认列。是否继续? projects.column.color=颜色 @@ -1970,6 +1971,9 @@ pulls.status_checks_requested=必须 pulls.status_checks_details=详情 pulls.status_checks_hide_all=隐藏所有检查 pulls.status_checks_show_all=显示所有检查 +pulls.status_checks_approve_all=批准所有工作流 +pulls.status_checks_need_approvals=%d 个工作流等待批准 +pulls.status_checks_need_approvals_helper=此工作流在仓库维护者批准后才会运行。 pulls.update_branch=通过合并更新分支 pulls.update_branch_rebase=通过变基更新分支 pulls.update_branch_success=分支更新成功 @@ -3036,6 +3040,7 @@ dashboard.update_migration_poster_id=更新迁移的发表者ID dashboard.git_gc_repos=对仓库进行垃圾回收 dashboard.resync_all_sshkeys=使用 Gitea 的 SSH 密钥更新「.ssh/authorized_keys」文件。 dashboard.resync_all_sshprincipals=使用 Gitea 的 SSH 规则更新「.ssh/authorized_principals」文件。 +dashboard.resync_all_hooks=重新同步所有仓库的 pre-receive、update 和 post-receive 钩子 dashboard.reinit_missing_repos=重新初始化所有丢失的 Git 仓库存在的记录 dashboard.sync_external_users=同步外部用户数据 dashboard.cleanup_hook_task_table=清理 hook_task 表 @@ -3070,7 +3075,7 @@ dashboard.total_gc_time=GC 暂停时间总量 dashboard.total_gc_pause=GC 暂停时间总量 dashboard.last_gc_pause=上次 GC 暂停时间 dashboard.gc_times=GC 执行次数 -dashboard.delete_old_actions=从数据库中删除所有旧工作流记录 +dashboard.delete_old_actions=从数据库中删除所有旧操作记录 dashboard.delete_old_actions.started=已开始从数据库中删除所有旧工作流记录。 dashboard.update_checker=更新检查器 dashboard.delete_old_system_notices=从数据库中删除所有旧系统通知 @@ -3890,6 +3895,7 @@ workflow.has_workflow_dispatch=此工作流有一个 workflow_dispatch 事件触 workflow.has_no_workflow_dispatch=工作流「%s」没有 workflow_dispatch 事件触发器。 need_approval_desc=该工作流由派生仓库的合并请求所触发,需要批准方可运行。 +approve_all_success=已成功批准所有工作流运行。 variables=变量 variables.management=变量管理 @@ -3910,6 +3916,14 @@ variables.update.success=变量已编辑。 logs.always_auto_scroll=总是自动滚动日志 logs.always_expand_running=总是展开运行日志 +general=常规 +general.enable_actions=启用工作流 +general.collaborative_owners_management=协作所有者管理 +general.collaborative_owners_management_help=协作所有者是指其私有仓库有权访问此仓库的工作流的用户或组织。 +general.add_collaborative_owner=添加协作所有者 +general.collaborative_owner_not_exist=协作所有者不存在。 +general.remove_collaborative_owner=移除协作所有者 +general.remove_collaborative_owner_desc=移除协作所有者将阻止该所有者的其他仓库访问此仓库中的工作流。是否继续? [projects] deleted.display_name=已删除项目 From ede7f1a0691484915bd94d6fc37df41a559dc114 Mon Sep 17 00:00:00 2001 From: bytedream Date: Thu, 27 Nov 2025 15:02:03 +0100 Subject: [PATCH 04/36] Fix incorrect viewed files counter if file has changed (#36009) File changes since last review didn't decrease the viewed files counter --- image Also reported here -> https://github.com/go-gitea/gitea/issues/35803#issuecomment-3567850285 --------- Co-authored-by: Lunny Xiao --- models/pull/review_state.go | 12 ++++++------ routers/web/repo/pull_review.go | 2 +- services/gitdiff/gitdiff.go | 10 ++++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/models/pull/review_state.go b/models/pull/review_state.go index e8b759c0cc6..a0f5548dd44 100644 --- a/models/pull/review_state.go +++ b/models/pull/review_state.go @@ -73,18 +73,18 @@ func GetReviewState(ctx context.Context, userID, pullID int64, commitSHA string) // UpdateReviewState updates the given review inside the database, regardless of whether it existed before or not // The given map of files with their viewed state will be merged with the previous review, if present -func UpdateReviewState(ctx context.Context, userID, pullID int64, commitSHA string, updatedFiles map[string]ViewedState) error { +func UpdateReviewState(ctx context.Context, userID, pullID int64, commitSHA string, updatedFiles map[string]ViewedState) (*ReviewState, error) { log.Trace("Updating review for user %d, repo %d, commit %s with the updated files %v.", userID, pullID, commitSHA, updatedFiles) review, exists, err := GetReviewState(ctx, userID, pullID, commitSHA) if err != nil { - return err + return nil, err } if exists { review.UpdatedFiles = mergeFiles(review.UpdatedFiles, updatedFiles) } else if previousReview, err := getNewestReviewStateApartFrom(ctx, userID, pullID, commitSHA); err != nil { - return err + return nil, err // Overwrite the viewed files of the previous review if present } else if previousReview != nil { @@ -98,11 +98,11 @@ func UpdateReviewState(ctx context.Context, userID, pullID int64, commitSHA stri if !exists { log.Trace("Inserting new review for user %d, repo %d, commit %s with the updated files %v.", userID, pullID, commitSHA, review.UpdatedFiles) _, err := engine.Insert(review) - return err + return nil, err } log.Trace("Updating already existing review with ID %d (user %d, repo %d, commit %s) with the updated files %v.", review.ID, userID, pullID, commitSHA, review.UpdatedFiles) - _, err = engine.ID(review.ID).Update(&ReviewState{UpdatedFiles: review.UpdatedFiles}) - return err + _, err = engine.ID(review.ID).Cols("updated_files").Update(review) + return review, err } // mergeFiles merges the given maps of files with their viewing state into one map. diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index 18e14e9b224..f064058221e 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -331,7 +331,7 @@ func UpdateViewedFiles(ctx *context.Context) { updatedFiles[file] = state } - if err := pull_model.UpdateReviewState(ctx, ctx.Doer.ID, pull.ID, data.HeadCommitSHA, updatedFiles); err != nil { + if _, err := pull_model.UpdateReviewState(ctx, ctx.Doer.ID, pull.ID, data.HeadCommitSHA, updatedFiles); err != nil { ctx.ServerError("UpdateReview", err) } } diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 4ad06bc04ff..6e15f716095 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1434,15 +1434,17 @@ outer: } } - // Explicitly store files that have changed in the database, if any is present at all. - // This has the benefit that the "Has Changed" attribute will be present as long as the user does not explicitly mark this file as viewed, so it will even survive a page reload after marking another file as viewed. - // On the other hand, this means that even if a commit reverting an unseen change is committed, the file will still be seen as changed. if len(filesChangedSinceLastDiff) > 0 { - err := pull_model.UpdateReviewState(ctx, review.UserID, review.PullID, review.CommitSHA, filesChangedSinceLastDiff) + // Explicitly store files that have changed in the database, if any is present at all. + // This has the benefit that the "Has Changed" attribute will be present as long as the user does not explicitly mark this file as viewed, so it will even survive a page reload after marking another file as viewed. + // On the other hand, this means that even if a commit reverting an unseen change is committed, the file will still be seen as changed. + updatedReview, err := pull_model.UpdateReviewState(ctx, review.UserID, review.PullID, review.CommitSHA, filesChangedSinceLastDiff) if err != nil { log.Warn("Could not update review for user %d, pull %d, commit %s and the changed files %v: %v", review.UserID, review.PullID, review.CommitSHA, filesChangedSinceLastDiff, err) return nil, err } + // Update the local review to reflect the changes immediately + review = updatedReview } return review, nil From 9668913d761ff215e74458e813c6f8bf1d60341d Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 28 Nov 2025 00:58:10 +0100 Subject: [PATCH 05/36] Update JS deps, fix deprecations (#36040) - Update JS deps - Regenerate SVGs - Fix air `bin` deprecation - Fix `monaco.languages.typescript` deprecation - Remove `eslint-plugin-no-use-extend-native`, it's unnecessary with typescript - Enable new `@typescript-eslint` rules - Disable `@typescript-eslint/no-redundant-type-constituents`, this rule has bugs when not running under `strictNullChecks` (pending in https://github.com/go-gitea/gitea/pull/35843). --- .air.toml | 2 +- eslint.config.ts | 10 +- options/fileicon/material-icon-rules.json | 155 +++- options/fileicon/material-icon-svgs.json | 16 +- package.json | 31 +- pnpm-lock.yaml | 728 ++++++++---------- web_src/js/features/codeeditor.ts | 4 +- .../js/features/eventsource.sharedworker.ts | 4 +- 8 files changed, 481 insertions(+), 469 deletions(-) diff --git a/.air.toml b/.air.toml index 8854041a25b..6e3c5bdc83b 100644 --- a/.air.toml +++ b/.air.toml @@ -4,7 +4,7 @@ tmp_dir = ".air" [build] pre_cmd = ["killall -9 gitea 2>/dev/null || true"] # kill off potential zombie processes from previous runs cmd = "make --no-print-directory backend" -bin = "gitea" +entrypoint = ["./gitea"] delay = 2000 include_ext = ["go", "tmpl"] include_file = ["main.go"] diff --git a/eslint.config.ts b/eslint.config.ts index 548e650bc49..c849cdbc627 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -3,7 +3,6 @@ import comments from '@eslint-community/eslint-plugin-eslint-comments'; import github from 'eslint-plugin-github'; import globals from 'globals'; import importPlugin from 'eslint-plugin-import-x'; -import noUseExtendNative from 'eslint-plugin-no-use-extend-native'; import playwright from 'eslint-plugin-playwright'; import regexp from 'eslint-plugin-regexp'; import sonarjs from 'eslint-plugin-sonarjs'; @@ -58,7 +57,6 @@ export default defineConfig([ 'array-func': arrayFunc, // @ts-expect-error -- https://github.com/un-ts/eslint-plugin-import-x/issues/203 'import-x': importPlugin, - 'no-use-extend-native': noUseExtendNative, regexp, sonarjs, unicorn, @@ -155,7 +153,7 @@ export default defineConfig([ '@typescript-eslint/ban-tslint-comment': [0], '@typescript-eslint/class-literal-property-style': [0], '@typescript-eslint/class-methods-use-this': [0], - '@typescript-eslint/consistent-generic-constructors': [0], + '@typescript-eslint/consistent-generic-constructors': [2, 'constructor'], '@typescript-eslint/consistent-indexed-object-style': [0], '@typescript-eslint/consistent-return': [0], '@typescript-eslint/consistent-type-assertions': [2, {assertionStyle: 'as', objectLiteralTypeAssertions: 'allow'}], @@ -207,7 +205,7 @@ export default defineConfig([ '@typescript-eslint/no-non-null-asserted-optional-chain': [2], '@typescript-eslint/no-non-null-assertion': [0], '@typescript-eslint/no-redeclare': [0], - '@typescript-eslint/no-redundant-type-constituents': [2], + '@typescript-eslint/no-redundant-type-constituents': [0], // rule does not properly work without strickNullChecks '@typescript-eslint/no-require-imports': [2], '@typescript-eslint/no-restricted-imports': [0], '@typescript-eslint/no-restricted-types': [0], @@ -231,6 +229,7 @@ export default defineConfig([ '@typescript-eslint/no-unsafe-return': [0], '@typescript-eslint/no-unsafe-unary-minus': [2], '@typescript-eslint/no-unused-expressions': [0], + '@typescript-eslint/no-unused-private-class-members': [2], '@typescript-eslint/no-unused-vars': [2, {vars: 'all', args: 'all', caughtErrors: 'all', ignoreRestSiblings: false, argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_'}], '@typescript-eslint/no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true, typedefs: false, enums: false, ignoreTypeReferences: true}], '@typescript-eslint/no-useless-constructor': [0], @@ -587,10 +586,9 @@ export default defineConfig([ 'no-unsafe-negation': [2], 'no-unused-expressions': [2], 'no-unused-labels': [2], - 'no-unused-private-class-members': [2], + 'no-unused-private-class-members': [0], // handled by @typescript-eslint/no-unused-private-class-members 'no-unused-vars': [0], // handled by @typescript-eslint/no-unused-vars 'no-use-before-define': [0], // handled by @typescript-eslint/no-use-before-define - 'no-use-extend-native/no-use-extend-native': [2], 'no-useless-assignment': [2], 'no-useless-backreference': [2], 'no-useless-call': [2], diff --git a/options/fileicon/material-icon-rules.json b/options/fileicon/material-icon-rules.json index d8c71562918..6b17e5be67a 100644 --- a/options/fileicon/material-icon-rules.json +++ b/options/fileicon/material-icon-rules.json @@ -3219,6 +3219,22 @@ ".favicons": "folder-favicon", "_favicons": "folder-favicon", "__favicons__": "folder-favicon", + "feature": "folder-features", + ".feature": "folder-features", + "_feature": "folder-features", + "__feature__": "folder-features", + "features": "folder-features", + ".features": "folder-features", + "_features": "folder-features", + "__features__": "folder-features", + "feat": "folder-features", + ".feat": "folder-features", + "_feat": "folder-features", + "__feat__": "folder-features", + "feats": "folder-features", + ".feats": "folder-features", + "_feats": "folder-features", + "__feats__": "folder-features", "lefthook": "folder-lefthook", ".lefthook": "folder-lefthook", "_lefthook": "folder-lefthook", @@ -3474,7 +3490,15 @@ "cues": "folder-cue", ".cues": "folder-cue", "_cues": "folder-cue", - "__cues__": "folder-cue" + "__cues__": "folder-cue", + "license": "folder-license", + ".license": "folder-license", + "_license": "folder-license", + "__license__": "folder-license", + "licenses": "folder-license", + ".licenses": "folder-license", + "_licenses": "folder-license", + "__licenses__": "folder-license" }, "folderNamesExpanded": { "rust": "folder-rust-open", @@ -6696,6 +6720,22 @@ ".favicons": "folder-favicon-open", "_favicons": "folder-favicon-open", "__favicons__": "folder-favicon-open", + "feature": "folder-features-open", + ".feature": "folder-features-open", + "_feature": "folder-features-open", + "__feature__": "folder-features-open", + "features": "folder-features-open", + ".features": "folder-features-open", + "_features": "folder-features-open", + "__features__": "folder-features-open", + "feat": "folder-features-open", + ".feat": "folder-features-open", + "_feat": "folder-features-open", + "__feat__": "folder-features-open", + "feats": "folder-features-open", + ".feats": "folder-features-open", + "_feats": "folder-features-open", + "__feats__": "folder-features-open", "lefthook": "folder-lefthook-open", ".lefthook": "folder-lefthook-open", "_lefthook": "folder-lefthook-open", @@ -6951,7 +6991,15 @@ "cues": "folder-cue-open", ".cues": "folder-cue-open", "_cues": "folder-cue-open", - "__cues__": "folder-cue-open" + "__cues__": "folder-cue-open", + "license": "folder-license-open", + ".license": "folder-license-open", + "_license": "folder-license-open", + "__license__": "folder-license-open", + "licenses": "folder-license-open", + ".licenses": "folder-license-open", + "_licenses": "folder-license-open", + "__licenses__": "folder-license-open" }, "rootFolderNames": {}, "rootFolderNamesExpanded": {}, @@ -7102,6 +7150,8 @@ "srf": "image", "srw": "image", "x3f": "image", + "ktx": "image", + "ktx2": "image", "pal": "palette", "gpl": "palette", "act": "palette", @@ -7287,6 +7337,7 @@ "cp": "cpp", "mii": "cpp", "ii": "cpp", + "cppm": "cpp", "hh": "hpp", "hpp": "hpp", "hxx": "hpp", @@ -7373,6 +7424,11 @@ "fsi": "fsharp", "fsproj": "fsharp", "swift": "swift", + "xcplayground": "swift", + "swiftdeps": "swift", + "swiftdoc": "swift", + "swiftmodule": "swift", + "swiftsourceinfo": "swift", "ino": "arduino", "dockerignore": "docker", "dockerfile": "docker", @@ -8105,10 +8161,10 @@ "css.jsx": "vanilla-extract", "toc": "toc", "cue": "cue", + "lean": "lean", "cljx": "clojure", "clojure": "clojure", "edn": "clojure", - "cppm": "cpp", "ccm": "cpp", "cxxm": "cpp", "c++m": "cpp", @@ -8412,36 +8468,36 @@ "gradlew": "gradle", "gradle-wrapper.properties": "gradle", "gradlew.bat": "gradle", - "copying": "certificate", - "copying.md": "certificate", - "copying.rst": "certificate", - "copying.txt": "certificate", - "copyright": "certificate", - "copyright.md": "certificate", - "copyright.rst": "certificate", - "copyright.txt": "certificate", - "license": "certificate", - "license-agpl": "certificate", - "license-apache": "certificate", - "license-bsd": "certificate", - "license-mit": "certificate", - "license-gpl": "certificate", - "license-lgpl": "certificate", - "license.md": "certificate", - "license.rst": "certificate", - "license.txt": "certificate", - "licence": "certificate", - "licence-agpl": "certificate", - "licence-apache": "certificate", - "licence-bsd": "certificate", - "licence-mit": "certificate", - "licence-gpl": "certificate", - "licence-lgpl": "certificate", - "licence.md": "certificate", - "licence.rst": "certificate", - "licence.txt": "certificate", - "unlicense": "certificate", - "unlicense.txt": "certificate", + "copying": "license", + "copying.md": "license", + "copying.rst": "license", + "copying.txt": "license", + "copyright": "license", + "copyright.md": "license", + "copyright.rst": "license", + "copyright.txt": "license", + "license": "license", + "license-agpl": "license", + "license-apache": "license", + "license-bsd": "license", + "license-mit": "license", + "license-gpl": "license", + "license-lgpl": "license", + "license.md": "license", + "license.rst": "license", + "license.txt": "license", + "licence": "license", + "licence-agpl": "license", + "licence-apache": "license", + "licence-bsd": "license", + "licence-mit": "license", + "licence-gpl": "license", + "licence-lgpl": "license", + "licence.md": "license", + "licence.rst": "license", + "licence.txt": "license", + "unlicense": "unlicense", + "unlicense.txt": "unlicense", ".htpasswd": "key", "sha256sums": "key", ".secrets": "key", @@ -8457,6 +8513,7 @@ ".rspec": "rspec", ".swift-format": "swift", ".swift-version": "swift", + ".swiftformat": "swift", "dockerfile": "docker", "dockerfile.prod": "docker", "dockerfile.production": "docker", @@ -8993,6 +9050,12 @@ "rspress.config.ts": "rstack", "rslint.json": "rstack", "rslint.jsonc": "rstack", + "lynx.config.js": "lynx", + "lynx.config.mjs": "lynx", + "lynx.config.cjs": "lynx", + "lynx.config.ts": "lynx", + "lynx.config.mts": "lynx", + "lynx.config.cts": "lynx", "ionic.config.json": "ionic", ".io-config.json": "ionic", "gulpfile.js": "gulp", @@ -9722,6 +9785,18 @@ "vitest.config.ts": "vitest", "vitest.config.mts": "vitest", "vitest.config.cts": "vitest", + "vitest.unit.config.js": "vitest", + "vitest.unit.config.mjs": "vitest", + "vitest.unit.config.cjs": "vitest", + "vitest.unit.config.ts": "vitest", + "vitest.unit.config.mts": "vitest", + "vitest.unit.config.cts": "vitest", + "vitest.e2e.config.js": "vitest", + "vitest.e2e.config.mjs": "vitest", + "vitest.e2e.config.cjs": "vitest", + "vitest.e2e.config.ts": "vitest", + "vitest.e2e.config.mts": "vitest", + "vitest.e2e.config.cts": "vitest", "velite.config.js": "velite", "velite.config.mjs": "velite", "velite.config.cjs": "velite", @@ -10169,6 +10244,7 @@ ".coderabbit.yml": "coderabbit-ai", ".coderabbit.yaml": "coderabbit-ai", ".aiexclude": "gemini-ai", + "gemini.md": "gemini-ai", "taze.config.js": "taze", "taze.config.mjs": "taze", "taze.config.cjs": "taze", @@ -10273,7 +10349,10 @@ "hadolint.yaml": "hadolint", "hadolint.yml": "hadolint", "tsdoc.json": "tsdoc", - ".oxlintrc.json": "oxlint", + ".oxlintrc.json": "oxc", + ".oxlintrc.jsonc": "oxc", + ".oxfmtrc.json": "oxc", + ".oxfmtrc.jsonc": "oxc", "claude.md": "claude", "claude.local.md": "claude", ".cursorignore": "cursor", @@ -10296,6 +10375,7 @@ "googleservice-info.plist": "google", ".shellcheckrc": "shellcheck", "shellcheckrc": "shellcheck", + "warp.md": "warp", "language-configuration.json": "jsonc", "icon-theme.json": "jsonc", "color-theme.json": "jsonc", @@ -10322,6 +10402,7 @@ "toml": "toml", "diff": "diff", "json": "json", + "jsonl": "json", "jsonc": "json", "json5": "json", "blink": "blink", @@ -10497,7 +10578,8 @@ "gnuplot": "gnuplot", "helm": "helm", "nginx": "nginx", - "cue": "cue" + "cue": "cue", + "lean": "lean" }, "light": { "fileExtensions": { @@ -10705,7 +10787,8 @@ "src/bashly-strings.yaml": "bashly-strings_light", "src/bashly-strings.yml": "bashly-strings_light", ".shellcheckrc": "shellcheck_light", - "shellcheckrc": "shellcheck_light" + "shellcheckrc": "shellcheck_light", + "warp.md": "warp_light" }, "languageIds": { "toml": "toml_light", diff --git a/options/fileicon/material-icon-svgs.json b/options/fileicon/material-icon-svgs.json index 61524074fd6..f5254099ad7 100644 --- a/options/fileicon/material-icon-svgs.json +++ b/options/fileicon/material-icon-svgs.json @@ -92,7 +92,7 @@ "capnp": "", "cbx": "", "cds": "", - "certificate": "", + "certificate": "", "changelog": "", "chess": "", "chess_light": "", @@ -359,6 +359,8 @@ "folder-fastlane": "", "folder-favicon-open": "", "folder-favicon": "", + "folder-features-open": "", + "folder-features": "", "folder-filter-open": "", "folder-filter": "", "folder-firebase-open": "", @@ -459,6 +461,8 @@ "folder-less": "", "folder-lib-open": "", "folder-lib": "", + "folder-license-open": "", + "folder-license": "", "folder-link-open": "", "folder-link": "", "folder-linux-open": "", @@ -829,11 +833,13 @@ "latex.clone": "", "latexmk": "", "lbx": "", + "lean": "", "lefthook": "", "lerna": "", "less": "", "liara": "", "lib": "", + "license": "", "lighthouse": "", "lilypond": "", "lintstaged": "", @@ -846,6 +852,7 @@ "lottie": "", "lua": "", "luau": "", + "lynx": "", "lyric": "", "makefile": "", "markdoc-config": "", @@ -922,7 +929,7 @@ "opentofu": "", "opentofu_light": "", "otne": "", - "oxlint": "", + "oxc": "", "packship": "", "palette": "", "panda": "", @@ -971,7 +978,7 @@ "python": "", "pytorch": "", "qsharp": "", - "quarto": "", + "quarto": "", "quasar": "", "quokka": "", "qwik": "", @@ -1126,6 +1133,7 @@ "uml": "", "uml_light": "", "unity": "", + "unlicense": "", "unocss": "", "url": "", "uv": "", @@ -1159,6 +1167,8 @@ "wakatime_light": "", "wallaby": "", "wally": "", + "warp": "", + "warp_light": "", "watchman": "", "webassembly": "", "webhint": "", diff --git a/package.json b/package.json index 2f81034952f..99cb2d5b139 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "type": "module", - "packageManager": "pnpm@10.22.0", + "packageManager": "pnpm@10.23.0", "engines": { "node": ">= 22.6.0", "pnpm": ">= 10.0.0" @@ -12,7 +12,7 @@ "@citation-js/plugin-software-formats": "0.6.1", "@github/markdown-toolbar-element": "2.2.3", "@github/paste-markdown": "1.5.3", - "@github/relative-time-element": "4.5.0", + "@github/relative-time-element": "4.5.1", "@github/text-expander-element": "2.9.2", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "19.21.0", @@ -38,7 +38,7 @@ "katex": "0.16.25", "mermaid": "11.12.1", "mini-css-extract-plugin": "2.9.4", - "monaco-editor": "0.54.0", + "monaco-editor": "0.55.1", "monaco-editor-webpack-plugin": "7.1.1", "online-3d-viewer": "0.16.0", "pdfobject": "2.3.1", @@ -46,7 +46,7 @@ "postcss": "8.5.6", "postcss-loader": "8.2.0", "sortablejs": "1.15.6", - "swagger-ui-dist": "5.30.2", + "swagger-ui-dist": "5.30.3", "tailwindcss": "3.4.17", "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", @@ -56,7 +56,7 @@ "typescript": "5.9.3", "uint8-to-base64": "0.2.1", "vanilla-colorful": "0.7.2", - "vue": "3.5.24", + "vue": "3.5.25", "vue-bar-graph": "2.2.0", "vue-chartjs": "5.3.3", "vue-loader": "17.4.2", @@ -66,7 +66,7 @@ }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.5.0", - "@playwright/test": "1.56.1", + "@playwright/test": "1.57.0", "@stylistic/eslint-plugin": "5.6.1", "@stylistic/stylelint-plugin": "4.0.0", "@types/codemirror": "5.60.17", @@ -79,40 +79,39 @@ "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", "@types/toastify-js": "1.12.4", - "@typescript-eslint/parser": "8.47.0", + "@typescript-eslint/parser": "8.48.0", "@vitejs/plugin-vue": "6.0.2", - "@vitest/eslint-plugin": "1.4.3", + "@vitest/eslint-plugin": "1.5.0", "eslint": "9.39.1", "eslint-import-resolver-typescript": "4.4.4", "eslint-plugin-array-func": "5.1.0", "eslint-plugin-github": "6.0.0", "eslint-plugin-import-x": "4.16.1", - "eslint-plugin-no-use-extend-native": "0.7.2", "eslint-plugin-playwright": "2.3.0", "eslint-plugin-regexp": "2.10.0", "eslint-plugin-sonarjs": "3.0.5", "eslint-plugin-unicorn": "62.0.0", - "eslint-plugin-vue": "10.5.1", + "eslint-plugin-vue": "10.6.1", "eslint-plugin-vue-scoped-css": "2.12.0", "eslint-plugin-wc": "3.0.2", "globals": "16.5.0", "happy-dom": "20.0.10", "markdownlint-cli": "0.46.0", - "material-icon-theme": "5.28.0", + "material-icon-theme": "5.29.0", "nolyfill": "1.0.44", "postcss-html": "1.8.0", "spectral-cli-bundle": "1.0.3", - "stylelint": "16.25.0", + "stylelint": "16.26.0", "stylelint-config-recommended": "17.0.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.11", "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "4.0.0", - "typescript-eslint": "8.47.0", - "updates": "16.9.1", + "typescript-eslint": "8.48.0", + "updates": "16.9.2", "vite-string-plugin": "1.4.9", - "vitest": "4.0.10", - "vue-tsc": "3.1.4" + "vitest": "4.0.14", + "vue-tsc": "3.1.5" }, "browserslist": [ "defaults" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 843372d094a..b2016b53cc0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,8 +45,8 @@ importers: specifier: 1.5.3 version: 1.5.3 '@github/relative-time-element': - specifier: 4.5.0 - version: 4.5.0 + specifier: 4.5.1 + version: 4.5.1 '@github/text-expander-element': specifier: 2.9.2 version: 2.9.2 @@ -61,7 +61,7 @@ importers: version: 2.6.2 '@silverwind/vue3-calendar-heatmap': specifier: 2.0.6 - version: 2.0.6(tippy.js@6.3.7)(vue@3.5.24(typescript@5.9.3)) + version: 2.0.6(tippy.js@6.3.7)(vue@3.5.25(typescript@5.9.3)) '@techknowlogick/license-checker-webpack-plugin': specifier: 0.3.0 version: 0.3.0(webpack@5.103.0) @@ -123,11 +123,11 @@ importers: specifier: 2.9.4 version: 2.9.4(webpack@5.103.0) monaco-editor: - specifier: 0.54.0 - version: 0.54.0 + specifier: 0.55.1 + version: 0.55.1 monaco-editor-webpack-plugin: specifier: 7.1.1 - version: 7.1.1(monaco-editor@0.54.0)(webpack@5.103.0) + version: 7.1.1(monaco-editor@0.55.1)(webpack@5.103.0) online-3d-viewer: specifier: 0.16.0 version: 0.16.0 @@ -147,8 +147,8 @@ importers: specifier: 1.15.6 version: 1.15.6 swagger-ui-dist: - specifier: 5.30.2 - version: 5.30.2 + specifier: 5.30.3 + version: 5.30.3 tailwindcss: specifier: 3.4.17 version: 3.4.17 @@ -177,17 +177,17 @@ importers: specifier: 0.7.2 version: 0.7.2 vue: - specifier: 3.5.24 - version: 3.5.24(typescript@5.9.3) + specifier: 3.5.25 + version: 3.5.25(typescript@5.9.3) vue-bar-graph: specifier: 2.2.0 version: 2.2.0(typescript@5.9.3) vue-chartjs: specifier: 5.3.3 - version: 5.3.3(chart.js@4.5.1)(vue@3.5.24(typescript@5.9.3)) + version: 5.3.3(chart.js@4.5.1)(vue@3.5.25(typescript@5.9.3)) vue-loader: specifier: 17.4.2 - version: 17.4.2(vue@3.5.24(typescript@5.9.3))(webpack@5.103.0) + version: 17.4.2(vue@3.5.25(typescript@5.9.3))(webpack@5.103.0) webpack: specifier: 5.103.0 version: 5.103.0(webpack-cli@6.0.1) @@ -202,14 +202,14 @@ importers: specifier: 4.5.0 version: 4.5.0(eslint@9.39.1(jiti@2.6.1)) '@playwright/test': - specifier: 1.56.1 - version: 1.56.1 + specifier: 1.57.0 + version: 1.57.0 '@stylistic/eslint-plugin': specifier: 5.6.1 version: 5.6.1(eslint@9.39.1(jiti@2.6.1)) '@stylistic/stylelint-plugin': specifier: 4.0.0 - version: 4.0.0(stylelint@16.25.0(typescript@5.9.3)) + version: 4.0.0(stylelint@16.26.0(typescript@5.9.3)) '@types/codemirror': specifier: 5.60.17 version: 5.60.17 @@ -241,20 +241,20 @@ importers: specifier: 1.12.4 version: 1.12.4 '@typescript-eslint/parser': - specifier: 8.47.0 - version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.48.0 + version: 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-vue': specifier: 6.0.2 - version: 6.0.2(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.24(typescript@5.9.3)) + version: 6.0.2(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3)) '@vitest/eslint-plugin': - specifier: 1.4.3 - version: 1.4.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.10(@types/debug@4.1.12)(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1)) + specifier: 1.5.0 + version: 1.5.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.14(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1)) eslint: specifier: 9.39.1 version: 9.39.1(jiti@2.6.1) eslint-import-resolver-typescript: specifier: 4.4.4 - version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) + version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-array-func: specifier: 5.1.0 version: 5.1.0(eslint@9.39.1(jiti@2.6.1)) @@ -263,10 +263,7 @@ importers: version: 6.0.0(@types/eslint@9.6.1)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-import-x: specifier: 4.16.1 - version: 4.16.1(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-no-use-extend-native: - specifier: 0.7.2 - version: 0.7.2(eslint@9.39.1(jiti@2.6.1)) + version: 4.16.1(@typescript-eslint/utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-playwright: specifier: 2.3.0 version: 2.3.0(eslint@9.39.1(jiti@2.6.1)) @@ -280,8 +277,8 @@ importers: specifier: 62.0.0 version: 62.0.0(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-vue: - specifier: 10.5.1 - version: 10.5.1(@stylistic/eslint-plugin@5.6.1(eslint@9.39.1(jiti@2.6.1)))(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1))) + specifier: 10.6.1 + version: 10.6.1(@stylistic/eslint-plugin@5.6.1(eslint@9.39.1(jiti@2.6.1)))(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1))) eslint-plugin-vue-scoped-css: specifier: 2.12.0 version: 2.12.0(eslint@9.39.1(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1))) @@ -298,8 +295,8 @@ importers: specifier: 0.46.0 version: 0.46.0 material-icon-theme: - specifier: 5.28.0 - version: 5.28.0 + specifier: 5.29.0 + version: 5.29.0 nolyfill: specifier: 1.0.44 version: 1.0.44 @@ -310,38 +307,38 @@ importers: specifier: 1.0.3 version: 1.0.3 stylelint: - specifier: 16.25.0 - version: 16.25.0(typescript@5.9.3) + specifier: 16.26.0 + version: 16.26.0(typescript@5.9.3) stylelint-config-recommended: specifier: 17.0.0 - version: 17.0.0(stylelint@16.25.0(typescript@5.9.3)) + version: 17.0.0(stylelint@16.26.0(typescript@5.9.3)) stylelint-declaration-block-no-ignored-properties: specifier: 2.8.0 - version: 2.8.0(stylelint@16.25.0(typescript@5.9.3)) + version: 2.8.0(stylelint@16.26.0(typescript@5.9.3)) stylelint-declaration-strict-value: specifier: 1.10.11 - version: 1.10.11(stylelint@16.25.0(typescript@5.9.3)) + version: 1.10.11(stylelint@16.26.0(typescript@5.9.3)) stylelint-value-no-unknown-custom-properties: specifier: 6.0.1 - version: 6.0.1(stylelint@16.25.0(typescript@5.9.3)) + version: 6.0.1(stylelint@16.26.0(typescript@5.9.3)) svgo: specifier: 4.0.0 version: 4.0.0 typescript-eslint: - specifier: 8.47.0 - version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.48.0 + version: 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) updates: - specifier: 16.9.1 - version: 16.9.1 + specifier: 16.9.2 + version: 16.9.2 vite-string-plugin: specifier: 1.4.9 version: 1.4.9 vitest: - specifier: 4.0.10 - version: 4.0.10(@types/debug@4.1.12)(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) + specifier: 4.0.14 + version: 4.0.14(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) vue-tsc: - specifier: 3.1.4 - version: 3.1.4(typescript@5.9.3) + specifier: 3.1.5 + version: 3.1.5(typescript@5.9.3) packages: @@ -716,8 +713,8 @@ packages: '@github/paste-markdown@1.5.3': resolution: {integrity: sha512-PzZ1b3PaqBzYqbT4fwKEhiORf38h2OcGp2+JdXNNM7inZ7egaSmfmhyNkQILpqWfS0AYtRS3CDq6z03eZ8yOMQ==} - '@github/relative-time-element@4.5.0': - resolution: {integrity: sha512-zKC/tUHeDDdbODBuZh3CkT5pCy41M8mGuUplzhtBMuiEQ5+qY/l/iu0X1IBY/6QhNeP/xdQIVkLYKh2O5En4dg==} + '@github/relative-time-element@4.5.1': + resolution: {integrity: sha512-uxCxCwe9vdwUDmRmM84tN0UERlj8MosLV44+r/VDj7DZUVUSTP4vyWlE9mRK6vHelOmT8DS3RMlaMrLlg1h1PQ==} '@github/text-expander-element@2.9.2': resolution: {integrity: sha512-XY8EUMqM4GAloNxXNA1Py1ny+engWwYntbgsnpstQN4piaTI9rIlfYldyd0nnPXhxjGCVqHPmP6yg17Q0/n9Vg==} @@ -871,8 +868,8 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@playwright/test@1.56.1': - resolution: {integrity: sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==} + '@playwright/test@1.57.0': + resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==} engines: {node: '>=18'} hasBin: true @@ -1236,63 +1233,63 @@ packages: '@types/whatwg-mimetype@3.0.2': resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} - '@typescript-eslint/eslint-plugin@8.47.0': - resolution: {integrity: sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==} + '@typescript-eslint/eslint-plugin@8.48.0': + resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.47.0 + '@typescript-eslint/parser': ^8.48.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.47.0': - resolution: {integrity: sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==} + '@typescript-eslint/parser@8.48.0': + resolution: {integrity: sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.47.0': - resolution: {integrity: sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==} + '@typescript-eslint/project-service@8.48.0': + resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.47.0': - resolution: {integrity: sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==} + '@typescript-eslint/scope-manager@8.48.0': + resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.47.0': - resolution: {integrity: sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==} + '@typescript-eslint/tsconfig-utils@8.48.0': + resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.47.0': - resolution: {integrity: sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==} + '@typescript-eslint/type-utils@8.48.0': + resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.47.0': - resolution: {integrity: sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==} + '@typescript-eslint/types@8.48.0': + resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.47.0': - resolution: {integrity: sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==} + '@typescript-eslint/typescript-estree@8.48.0': + resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.47.0': - resolution: {integrity: sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==} + '@typescript-eslint/utils@8.48.0': + resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.47.0': - resolution: {integrity: sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==} + '@typescript-eslint/visitor-keys@8.48.0': + resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -1397,8 +1394,8 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 vue: ^3.2.25 - '@vitest/eslint-plugin@1.4.3': - resolution: {integrity: sha512-ba+YDKyZdViNAOg8P86a9tIEawPA/O+nLbwhg8g7nkqsLOAVum6GoZhkNxgwX621oqWAbB8N2xb+G5kkpXehcA==} + '@vitest/eslint-plugin@1.5.0': + resolution: {integrity: sha512-j3uuIAPTYWYnSit9lspb08/EKsxEmGqjQf+Wpb1DQkxc+mMkhL58ZknDCgjYhY4Zu76oxZ0hVWTHlmRW0mJq5w==} engines: {node: '>=18'} peerDependencies: eslint: '>=8.57.0' @@ -1410,11 +1407,11 @@ packages: vitest: optional: true - '@vitest/expect@4.0.10': - resolution: {integrity: sha512-3QkTX/lK39FBNwARCQRSQr0TP9+ywSdxSX+LgbJ2M1WmveXP72anTbnp2yl5fH+dU6SUmBzNMrDHs80G8G2DZg==} + '@vitest/expect@4.0.14': + resolution: {integrity: sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==} - '@vitest/mocker@4.0.10': - resolution: {integrity: sha512-e2OfdexYkjkg8Hh3L9NVEfbwGXq5IZbDovkf30qW2tOh7Rh9sVtmSr2ztEXOFbymNxS4qjzLXUQIvATvN4B+lg==} + '@vitest/mocker@4.0.14': + resolution: {integrity: sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -1424,20 +1421,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.10': - resolution: {integrity: sha512-99EQbpa/zuDnvVjthwz5bH9o8iPefoQZ63WV8+bsRJZNw3qQSvSltfut8yu1Jc9mqOYi7pEbsKxYTi/rjaq6PA==} + '@vitest/pretty-format@4.0.14': + resolution: {integrity: sha512-SOYPgujB6TITcJxgd3wmsLl+wZv+fy3av2PpiPpsWPZ6J1ySUYfScfpIt2Yv56ShJXR2MOA6q2KjKHN4EpdyRQ==} - '@vitest/runner@4.0.10': - resolution: {integrity: sha512-EXU2iSkKvNwtlL8L8doCpkyclw0mc/t4t9SeOnfOFPyqLmQwuceMPA4zJBa6jw0MKsZYbw7kAn+gl7HxrlB8UQ==} + '@vitest/runner@4.0.14': + resolution: {integrity: sha512-BsAIk3FAqxICqREbX8SetIteT8PiaUL/tgJjmhxJhCsigmzzH8xeadtp7LRnTpCVzvf0ib9BgAfKJHuhNllKLw==} - '@vitest/snapshot@4.0.10': - resolution: {integrity: sha512-2N4X2ZZl7kZw0qeGdQ41H0KND96L3qX1RgwuCfy6oUsF2ISGD/HpSbmms+CkIOsQmg2kulwfhJ4CI0asnZlvkg==} + '@vitest/snapshot@4.0.14': + resolution: {integrity: sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==} - '@vitest/spy@4.0.10': - resolution: {integrity: sha512-AsY6sVS8OLb96GV5RoG8B6I35GAbNrC49AO+jNRF9YVGb/g9t+hzNm1H6kD0NDp8tt7VJLs6hb7YMkDXqu03iw==} + '@vitest/spy@4.0.14': + resolution: {integrity: sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==} - '@vitest/utils@4.0.10': - resolution: {integrity: sha512-kOuqWnEwZNtQxMKg3WmPK1vmhZu9WcoX69iwWjVz+jvKTsF1emzsv3eoPcDr6ykA3qP2bsCQE7CwqfNtAVzsmg==} + '@vitest/utils@4.0.14': + resolution: {integrity: sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==} '@volar/language-core@2.4.23': resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==} @@ -1448,42 +1445,42 @@ packages: '@volar/typescript@2.4.23': resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==} - '@vue/compiler-core@3.5.24': - resolution: {integrity: sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==} + '@vue/compiler-core@3.5.25': + resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} - '@vue/compiler-dom@3.5.24': - resolution: {integrity: sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==} + '@vue/compiler-dom@3.5.25': + resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} - '@vue/compiler-sfc@3.5.24': - resolution: {integrity: sha512-8EG5YPRgmTB+YxYBM3VXy8zHD9SWHUJLIGPhDovo3Z8VOgvP+O7UP5vl0J4BBPWYD9vxtBabzW1EuEZ+Cqs14g==} + '@vue/compiler-sfc@3.5.25': + resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} - '@vue/compiler-ssr@3.5.24': - resolution: {integrity: sha512-trOvMWNBMQ/odMRHW7Ae1CdfYx+7MuiQu62Jtu36gMLXcaoqKvAyh+P73sYG9ll+6jLB6QPovqoKGGZROzkFFg==} + '@vue/compiler-ssr@3.5.25': + resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} - '@vue/language-core@3.1.4': - resolution: {integrity: sha512-n/58wm8SkmoxMWkUNUH/PwoovWe4hmdyPJU2ouldr3EPi1MLoS7iDN46je8CsP95SnVBs2axInzRglPNKvqMcg==} + '@vue/language-core@3.1.5': + resolution: {integrity: sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true - '@vue/reactivity@3.5.24': - resolution: {integrity: sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg==} + '@vue/reactivity@3.5.25': + resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==} - '@vue/runtime-core@3.5.24': - resolution: {integrity: sha512-RYP/byyKDgNIqfX/gNb2PB55dJmM97jc9wyF3jK7QUInYKypK2exmZMNwnjueWwGceEkP6NChd3D2ZVEp9undQ==} + '@vue/runtime-core@3.5.25': + resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==} - '@vue/runtime-dom@3.5.24': - resolution: {integrity: sha512-Z8ANhr/i0XIluonHVjbUkjvn+CyrxbXRIxR7wn7+X7xlcb7dJsfITZbkVOeJZdP8VZwfrWRsWdShH6pngMxRjw==} + '@vue/runtime-dom@3.5.25': + resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==} - '@vue/server-renderer@3.5.24': - resolution: {integrity: sha512-Yh2j2Y4G/0/4z/xJ1Bad4mxaAk++C2v4kaa8oSYTMJBJ00/ndPuxCnWeot0/7/qafQFLh5pr6xeV6SdMcE/G1w==} + '@vue/server-renderer@3.5.25': + resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==} peerDependencies: - vue: 3.5.24 + vue: 3.5.25 - '@vue/shared@3.5.24': - resolution: {integrity: sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==} + '@vue/shared@3.5.25': + resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -1605,8 +1602,8 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - alien-signals@3.1.0: - resolution: {integrity: sha512-yufC6VpSy8tK3I0lO67pjumo5JvDQVQyr38+3OHqe6CHl1t2VZekKZ7EKKZSqk0cRmE7U7tfZbpXiKNzuc+ckg==} + alien-signals@3.1.1: + resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -1688,8 +1685,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.8.29: - resolution: {integrity: sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==} + baseline-browser-mapping@2.8.31: + resolution: {integrity: sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==} hasBin: true big.js@5.2.2: @@ -1746,8 +1743,8 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - caniuse-lite@1.0.30001756: - resolution: {integrity: sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==} + caniuse-lite@1.0.30001757: + resolution: {integrity: sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==} chai@6.2.1: resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} @@ -2189,8 +2186,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.1.7: - resolution: {integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==} + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} dompurify@3.3.0: resolution: {integrity: sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==} @@ -2204,8 +2201,8 @@ packages: easymde@2.20.0: resolution: {integrity: sha512-V1Z5f92TfR42Na852OWnIZMbM7zotWQYTddNaLYZFVKj7APBbyZ3FYJ27gBw2grMW3R6Qdv9J8n5Ij7XRSIgXQ==} - electron-to-chromium@1.5.256: - resolution: {integrity: sha512-uqYq1IQhpXXLX+HgiXdyOZml7spy4xfy42yPxcCCRjswp0fYM2X+JwCON07lqnpLEGVCj739B7Yr+FngmHBMEQ==} + electron-to-chromium@1.5.261: + resolution: {integrity: sha512-cmyHEWFqEt3ICUNF93ShneOF47DHoSDbLb7E/AonsWcbzg95N+kPXeLNfkdzgTT/vEUcoW76fxbLBkeYtfoM8A==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -2389,12 +2386,6 @@ packages: resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==} engines: {node: '>=5.0.0'} - eslint-plugin-no-use-extend-native@0.7.2: - resolution: {integrity: sha512-hUBlwaTXIO1GzTwPT6pAjvYwmSHe4XduDhAiQvur4RUujmBUFjd8Nb2+e7WQdsQ+nGHWGRlogcUWXJRGqizTWw==} - engines: {node: '>=18.18.0'} - peerDependencies: - eslint: ^9.3.0 - eslint-plugin-playwright@2.3.0: resolution: {integrity: sha512-7UeUuIb5SZrNkrUGb2F+iwHM97kn33/huajcVtAaQFCSMUYGNFvjzRPil5C0OIppslPfuOV68M/zsisXx+/ZvQ==} engines: {node: '>=16.9.0'} @@ -2439,8 +2430,8 @@ packages: eslint: '>=5.0.0' vue-eslint-parser: '>=7.1.0' - eslint-plugin-vue@10.5.1: - resolution: {integrity: sha512-SbR9ZBUFKgvWAbq3RrdCtWaW0IKm6wwUiApxf3BVTNfqUIo4IQQmreMg2iHFJJ6C/0wss3LXURBJ1OwS/MhFcQ==} + eslint-plugin-vue@10.6.1: + resolution: {integrity: sha512-OMvDAFbewocYrJamF1EoSWoT4xa7/QRb/yYouEZMiroTE+WRmFUreR+kAFQHqM45W3kg5oljVfUYfH9HEwX1Bg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 @@ -2573,8 +2564,8 @@ packages: fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - file-entry-cache@10.1.4: - resolution: {integrity: sha512-5XRUFc0WTtUbjfGzEwXc42tiGxQHBmtbUG1h9L2apu4SulCGN3Hqm//9D6FAolf8MYNL7f/YlJl9vy08pj5JuA==} + file-entry-cache@11.1.1: + resolution: {integrity: sha512-TPVFSDE7q91Dlk1xpFLvFllf8r0HyOMOlnWy7Z2HBku5H3KhIeOGInexrIeg2D64DosVB/JXkrrk6N/7Wriq4A==} file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} @@ -2630,10 +2621,6 @@ packages: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} - get-set-props@0.2.0: - resolution: {integrity: sha512-YCmOj+4YAeEB5Dd9jfp6ETdejMet4zSxXjNkgaa4npBEKRI9uDOGB5MmAdAgi2OoFGAKshYhCbmLq2DS03CgVA==} - engines: {node: '>=18.0.0'} - get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} @@ -2820,10 +2807,6 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - is-get-set-prop@2.0.0: - resolution: {integrity: sha512-C32bqXfHJfRwa0U5UIMqSGziZhALszXDJZ8n8mz8WZ6c6V7oYGHEWwJvftliBswypY3P3EQqdY5lpDSEKvTS1Q==} - engines: {node: '> 18.0.0'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -2831,18 +2814,10 @@ packages: is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} - is-js-type@3.0.0: - resolution: {integrity: sha512-IbPf3g3vxm1D902xaBaYp2TUHiXZWwWRu5bM9hgKN9oAQcFaKALV6Gd13PGhXjKE5u2n8s1PhLhdke/E1fchxQ==} - engines: {node: '>=18.0.0'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-obj-prop@2.0.0: - resolution: {integrity: sha512-2/VFrbzXSZVJIscazpxoB+pOQx2jBOAAL9Gui4cRKxflznUNBpsr8IDvBA4UGol3e40sltLNiY3qnZv/7qSUxA==} - engines: {node: '>=18.0.0'} - is-plain-object@2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} @@ -2854,10 +2829,6 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - is-proto-prop@3.0.1: - resolution: {integrity: sha512-S8xSxNMGJO4eZD86kO46zrq2gLIhA+rN9443lQEvt8Mz/l8cxk72p/AWFmofY6uL9g9ILD6cXW6j8QQj4F3Hcw==} - engines: {node: '>=18.0.0'} - is-valid-element-name@1.0.0: resolution: {integrity: sha512-GZITEJY2LkSjQfaIPBha7eyZv+ge0PhBR7KITeCCWvy7VBQrCUdFkvpI+HrAPQjVtVjy1LvlEkqQTHckoszruw==} @@ -2892,10 +2863,6 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - js-types@4.0.0: - resolution: {integrity: sha512-/c+n06zvqFQGxdz1BbElF7S3nEghjNchLN1TjQnk2j10HYDaUc57rcvl6BbnziTx8NQmrg0JOs/iwRpvcYaxjQ==} - engines: {node: '>=18.20'} - js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -3056,10 +3023,6 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - lowercase-keys@3.0.0: - resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -3091,8 +3054,8 @@ packages: engines: {node: '>= 12'} hasBin: true - material-icon-theme@5.28.0: - resolution: {integrity: sha512-71MxNSngYnNRUQ2YZpcVJg1KPsCFMlvdJV2LtSk434DjSkIjEeh0soHcJjaUp7ohbyYdpU4rukbvzfOylh+lxg==} + material-icon-theme@5.29.0: + resolution: {integrity: sha512-Kr6D+NgLCWYJjsTjGuIOoKUFG/uomUpLREhyV/9g4qWJMNfm7b1BYYMglRIdQg1IiY7WKqyTws8Ufsad6oFLUA==} engines: {vscode: ^1.55.0} mathml-tag-names@2.1.3: @@ -3237,8 +3200,8 @@ packages: monaco-editor: '>= 0.31.0' webpack: ^4.5.0 || 5.x - monaco-editor@0.54.0: - resolution: {integrity: sha512-hx45SEUoLatgWxHKCmlLJH81xBo0uXP4sRkESUpmDQevfi+e7K1VuiSprK6UpQ8u4zOcKNiH0pMvHvlMWA/4cw==} + monaco-editor@0.55.1: + resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} moo@0.5.2: resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==} @@ -3304,10 +3267,6 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - obj-props@2.0.0: - resolution: {integrity: sha512-Q/uLAAfjdhrzQWN2czRNh3fDCgXjh7yRIkdHjDgIHTwpFP0BsshxTA3HRNffHR7Iw/XGTH30u8vdMXQ+079urA==} - engines: {node: '>=18.0.0'} - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -3316,6 +3275,9 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -3423,13 +3385,13 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - playwright-core@1.56.1: - resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==} + playwright-core@1.57.0: + resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} engines: {node: '>=18'} hasBin: true - playwright@1.56.1: - resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==} + playwright@1.57.0: + resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} engines: {node: '>=18'} hasBin: true @@ -3567,10 +3529,6 @@ packages: engines: {node: '>=14'} hasBin: true - prototype-properties@5.0.0: - resolution: {integrity: sha512-uCWE2QqnGlwvvJXTwiHTPTyHE62+zORO5hpFWhAwBGDtEtTmNZZleNLJDoFsqHCL4p/CeAP2Q1uMKFUKALuRGQ==} - engines: {node: '>=18.20'} - punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -3869,8 +3827,8 @@ packages: peerDependencies: stylelint: '>=16' - stylelint@16.25.0: - resolution: {integrity: sha512-Li0avYWV4nfv1zPbdnxLYBGq4z8DVZxbRgx4Kn6V+Uftz1rMoF1qiEI3oL4kgWqyYgCgs7gT5maHNZ82Gk03vQ==} + stylelint@16.26.0: + resolution: {integrity: sha512-Y/3AVBefrkqqapVYH3LBF5TSDZ1kw+0XpdKN2KchfuhMK6lQ85S4XOG4lIZLcrcS4PWBmvcY6eS2kCQFz0jukQ==} engines: {node: '>=18.12.0'} hasBin: true @@ -3919,8 +3877,8 @@ packages: svgson@5.3.1: resolution: {integrity: sha512-qdPgvUNWb40gWktBJnbJRelWcPzkLed/ShhnRsjbayXz8OtdPOzbil9jtiZdrYvSDumAz/VNQr6JaNfPx/gvPA==} - swagger-ui-dist@5.30.2: - resolution: {integrity: sha512-HWCg1DTNE/Nmapt+0m2EPXFwNKNeKK4PwMjkwveN/zn1cV2Kxi9SURd+m0SpdcSgWEK/O64sf8bzXdtUhigtHA==} + swagger-ui-dist@5.30.3: + resolution: {integrity: sha512-giQl7/ToPxCqnUAx2wpnSnDNGZtGzw1LyUw6ZitIpTmdrvpxKFY/94v1hihm0zYNpgp1/VY0jTDk//R0BBgnRQ==} sync-fetch@0.4.5: resolution: {integrity: sha512-esiWJ7ixSKGpd9DJPBTC4ckChqdOjIwJfYhVHkcQ2Gnm41323p1TRmEI+esTQ9ppD+b5opps2OTEGTCGX5kF+g==} @@ -4038,8 +3996,8 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.47.0: - resolution: {integrity: sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q==} + typescript-eslint@8.48.0: + resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -4077,8 +4035,8 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - updates@16.9.1: - resolution: {integrity: sha512-Ct2VXiFLPG6ArPnL0Bd5KIOXjH/V26NYv84cgVZegkVBO96x58x8wG4KqxM2449YaHhgsWiM76jnTNz14pRalQ==} + updates@16.9.2: + resolution: {integrity: sha512-eV5CMKwQMldkBOsYLBgBjCyXlvpfyknbQvPOUpSP1CcTxtBDzbyWrrRMmrrw6Mw/fxwV0gULOxJiuU1RcqMhyg==} engines: {node: '>=20'} hasBin: true @@ -4098,8 +4056,8 @@ packages: vite-string-plugin@1.4.9: resolution: {integrity: sha512-mO7PVkMs8+FuTK9ZjBBCRSjabC9cobvUEbN2EjWtGJo6nu35SbW99bYesOh5Ho39ug/KSbT4VwM4GPC26Xk/mQ==} - vite@7.2.2: - resolution: {integrity: sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==} + vite@7.2.4: + resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4138,24 +4096,24 @@ packages: yaml: optional: true - vitest@4.0.10: - resolution: {integrity: sha512-2Fqty3MM9CDwOVet/jaQalYlbcjATZwPYGcqpiYQqgQ/dLC7GuHdISKgTYIVF/kaishKxLzleKWWfbSDklyIKg==} + vitest@4.0.14: + resolution: {integrity: sha512-d9B2J9Cm9dN9+6nxMnnNJKJCtcyKfnHj15N6YNJfaFHRLua/d3sRKU9RuKmO9mB0XdFtUizlxfz/VPbd3OxGhw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 + '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.10 - '@vitest/browser-preview': 4.0.10 - '@vitest/browser-webdriverio': 4.0.10 - '@vitest/ui': 4.0.10 + '@vitest/browser-playwright': 4.0.14 + '@vitest/browser-preview': 4.0.14 + '@vitest/browser-webdriverio': 4.0.14 + '@vitest/ui': 4.0.14 happy-dom: '*' jsdom: '*' peerDependenciesMeta: '@edge-runtime/vm': optional: true - '@types/debug': + '@opentelemetry/api': optional: true '@types/node': optional: true @@ -4222,14 +4180,14 @@ packages: vue: optional: true - vue-tsc@3.1.4: - resolution: {integrity: sha512-GsRJxttj4WkmXW/zDwYPGMJAN3np/4jTzoDFQTpTsI5Vg/JKMWamBwamlmLihgSVHO66y9P7GX+uoliYxeI4Hw==} + vue-tsc@3.1.5: + resolution: {integrity: sha512-L/G9IUjOWhBU0yun89rv8fKqmKC+T0HfhrFjlIml71WpfBv9eb4E9Bev8FMbyueBIU9vxQqbd+oOsVcDa5amGw==} hasBin: true peerDependencies: typescript: '>=5.0.0' - vue@3.5.24: - resolution: {integrity: sha512-uTHDOpVQTMjcGgrqFPSb8iO2m1DUvo+WbGqoXQz8Y1CeBYQ0FXf2z1gLRaBtHjlRz7zZUBHxjVB5VTLzYkvftg==} + vue@3.5.25: + resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -4642,7 +4600,7 @@ snapshots: '@github/paste-markdown@1.5.3': {} - '@github/relative-time-element@4.5.0': {} + '@github/relative-time-element@4.5.1': {} '@github/text-expander-element@2.9.2': dependencies: @@ -4793,9 +4751,9 @@ snapshots: '@pkgr/core@0.2.9': {} - '@playwright/test@1.56.1': + '@playwright/test@1.57.0': dependencies: - playwright: 1.56.1 + playwright: 1.57.0 '@popperjs/core@2.11.8': {} @@ -4877,10 +4835,10 @@ snapshots: '@scarf/scarf@1.4.0': {} - '@silverwind/vue3-calendar-heatmap@2.0.6(tippy.js@6.3.7)(vue@3.5.24(typescript@5.9.3))': + '@silverwind/vue3-calendar-heatmap@2.0.6(tippy.js@6.3.7)(vue@3.5.25(typescript@5.9.3))': dependencies: tippy.js: 6.3.7 - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) '@simonwep/pickr@1.9.0': dependencies: @@ -4905,14 +4863,14 @@ snapshots: '@stylistic/eslint-plugin@5.6.1(eslint@9.39.1(jiti@2.6.1))': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) - '@typescript-eslint/types': 8.47.0 + '@typescript-eslint/types': 8.48.0 eslint: 9.39.1(jiti@2.6.1) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.3 - '@stylistic/stylelint-plugin@4.0.0(stylelint@16.25.0(typescript@5.9.3))': + '@stylistic/stylelint-plugin@4.0.0(stylelint@16.26.0(typescript@5.9.3))': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 @@ -4921,7 +4879,7 @@ snapshots: postcss-selector-parser: 7.1.0 postcss-value-parser: 4.2.0 style-search: 0.1.0 - stylelint: 16.25.0(typescript@5.9.3) + stylelint: 16.26.0(typescript@5.9.3) '@swc/helpers@0.2.14': {} @@ -5142,14 +5100,14 @@ snapshots: '@types/whatwg-mimetype@3.0.2': {} - '@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.47.0 - '@typescript-eslint/type-utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.47.0 + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/type-utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.48.0 eslint: 9.39.1(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 @@ -5159,41 +5117,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.47.0 - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.47.0 + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.48.0 debug: 4.4.3 eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.47.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.48.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3) - '@typescript-eslint/types': 8.47.0 + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.47.0': + '@typescript-eslint/scope-manager@8.48.0': dependencies: - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/visitor-keys': 8.47.0 + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/visitor-keys': 8.48.0 - '@typescript-eslint/tsconfig-utils@8.47.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.1(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.3) @@ -5201,38 +5159,37 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.47.0': {} + '@typescript-eslint/types@8.48.0': {} - '@typescript-eslint/typescript-estree@8.47.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.47.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3) - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/visitor-keys': 8.47.0 + '@typescript-eslint/project-service': 8.48.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/visitor-keys': 8.48.0 debug: 4.4.3 - fast-glob: 3.3.3 - is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.7.3 + tinyglobby: 0.2.15 ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.47.0 - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.47.0': + '@typescript-eslint/visitor-keys@8.48.0': dependencies: - '@typescript-eslint/types': 8.47.0 + '@typescript-eslint/types': 8.48.0 eslint-visitor-keys: 4.2.1 '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -5294,60 +5251,60 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-vue@6.0.2(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.24(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.2(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.50 - vite: 7.2.2(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) - vue: 3.5.24(typescript@5.9.3) + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) + vue: 3.5.25(typescript@5.9.3) - '@vitest/eslint-plugin@1.4.3(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.10(@types/debug@4.1.12)(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1))': + '@vitest/eslint-plugin@1.5.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.14(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1))': dependencies: - '@typescript-eslint/scope-manager': 8.47.0 - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.1(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 4.0.10(@types/debug@4.1.12)(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) + vitest: 4.0.14(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@vitest/expect@4.0.10': + '@vitest/expect@4.0.14': dependencies: '@standard-schema/spec': 1.0.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.10 - '@vitest/utils': 4.0.10 + '@vitest/spy': 4.0.14 + '@vitest/utils': 4.0.14 chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.10(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1))': + '@vitest/mocker@4.0.14(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1))': dependencies: - '@vitest/spy': 4.0.10 + '@vitest/spy': 4.0.14 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.2.2(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) - '@vitest/pretty-format@4.0.10': + '@vitest/pretty-format@4.0.14': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.10': + '@vitest/runner@4.0.14': dependencies: - '@vitest/utils': 4.0.10 + '@vitest/utils': 4.0.14 pathe: 2.0.3 - '@vitest/snapshot@4.0.10': + '@vitest/snapshot@4.0.14': dependencies: - '@vitest/pretty-format': 4.0.10 + '@vitest/pretty-format': 4.0.14 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.10': {} + '@vitest/spy@4.0.14': {} - '@vitest/utils@4.0.10': + '@vitest/utils@4.0.14': dependencies: - '@vitest/pretty-format': 4.0.10 + '@vitest/pretty-format': 4.0.14 tinyrainbow: 3.0.3 '@volar/language-core@2.4.23': @@ -5362,71 +5319,71 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue/compiler-core@3.5.24': + '@vue/compiler-core@3.5.25': dependencies: '@babel/parser': 7.28.5 - '@vue/shared': 3.5.24 + '@vue/shared': 3.5.25 entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.24': + '@vue/compiler-dom@3.5.25': dependencies: - '@vue/compiler-core': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/compiler-core': 3.5.25 + '@vue/shared': 3.5.25 - '@vue/compiler-sfc@3.5.24': + '@vue/compiler-sfc@3.5.25': dependencies: '@babel/parser': 7.28.5 - '@vue/compiler-core': 3.5.24 - '@vue/compiler-dom': 3.5.24 - '@vue/compiler-ssr': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/compiler-core': 3.5.25 + '@vue/compiler-dom': 3.5.25 + '@vue/compiler-ssr': 3.5.25 + '@vue/shared': 3.5.25 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.6 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.24': + '@vue/compiler-ssr@3.5.25': dependencies: - '@vue/compiler-dom': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/compiler-dom': 3.5.25 + '@vue/shared': 3.5.25 - '@vue/language-core@3.1.4(typescript@5.9.3)': + '@vue/language-core@3.1.5(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.23 - '@vue/compiler-dom': 3.5.24 - '@vue/shared': 3.5.24 - alien-signals: 3.1.0 + '@vue/compiler-dom': 3.5.25 + '@vue/shared': 3.5.25 + alien-signals: 3.1.1 muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.3 optionalDependencies: typescript: 5.9.3 - '@vue/reactivity@3.5.24': + '@vue/reactivity@3.5.25': dependencies: - '@vue/shared': 3.5.24 + '@vue/shared': 3.5.25 - '@vue/runtime-core@3.5.24': + '@vue/runtime-core@3.5.25': dependencies: - '@vue/reactivity': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/reactivity': 3.5.25 + '@vue/shared': 3.5.25 - '@vue/runtime-dom@3.5.24': + '@vue/runtime-dom@3.5.25': dependencies: - '@vue/reactivity': 3.5.24 - '@vue/runtime-core': 3.5.24 - '@vue/shared': 3.5.24 + '@vue/reactivity': 3.5.25 + '@vue/runtime-core': 3.5.25 + '@vue/shared': 3.5.25 csstype: 3.2.3 - '@vue/server-renderer@3.5.24(vue@3.5.24(typescript@5.9.3))': + '@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.24 - '@vue/shared': 3.5.24 - vue: 3.5.24(typescript@5.9.3) + '@vue/compiler-ssr': 3.5.25 + '@vue/shared': 3.5.25 + vue: 3.5.25(typescript@5.9.3) - '@vue/shared@3.5.24': {} + '@vue/shared@3.5.25': {} '@webassemblyjs/ast@1.14.1': dependencies: @@ -5560,7 +5517,7 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - alien-signals@3.1.0: {} + alien-signals@3.1.1: {} ansi-regex@5.0.1: {} @@ -5615,7 +5572,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.8.29: {} + baseline-browser-mapping@2.8.31: {} big.js@5.2.2: {} @@ -5638,9 +5595,9 @@ snapshots: browserslist@4.28.0: dependencies: - baseline-browser-mapping: 2.8.29 - caniuse-lite: 1.0.30001756 - electron-to-chromium: 1.5.256 + baseline-browser-mapping: 2.8.31 + caniuse-lite: 1.0.30001757 + electron-to-chromium: 1.5.261 node-releases: 2.0.27 update-browserslist-db: 1.1.4(browserslist@4.28.0) @@ -5669,7 +5626,7 @@ snapshots: camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001756: {} + caniuse-lite@1.0.30001757: {} chai@6.2.1: {} @@ -6112,7 +6069,9 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.1.7: {} + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 dompurify@3.3.0: optionalDependencies: @@ -6137,7 +6096,7 @@ snapshots: codemirror-spell-checker: 1.1.2 marked: 4.3.0 - electron-to-chromium@1.5.256: {} + electron-to-chromium@1.5.261: {} emoji-regex@10.6.0: {} @@ -6231,7 +6190,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)): + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)): dependencies: debug: 4.4.3 eslint: 9.39.1(jiti@2.6.1) @@ -6242,19 +6201,19 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) + eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -6287,8 +6246,8 @@ snapshots: '@eslint/eslintrc': 3.3.1 '@eslint/js': 9.39.1 '@github/browserslist-config': 1.0.0 - '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) aria-query: 5.3.2 eslint: 9.39.1(jiti@2.6.1) eslint-config-prettier: 10.1.8(eslint@9.39.1(jiti@2.6.1)) @@ -6296,7 +6255,7 @@ snapshots: eslint-plugin-eslint-comments: 3.2.0(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-filenames: 1.3.2(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-i18n-text: 1.0.1(eslint@9.39.1(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-no-only-tests: 3.3.0 eslint-plugin-prettier: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))(prettier@3.6.2) @@ -6306,7 +6265,7 @@ snapshots: prettier: 3.6.2 svg-element-attributes: 1.3.1 typescript: 5.9.3 - typescript-eslint: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + typescript-eslint: 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - '@types/eslint' - eslint-import-resolver-typescript @@ -6317,9 +6276,9 @@ snapshots: dependencies: eslint: 9.39.1(jiti@2.6.1) - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)): dependencies: - '@typescript-eslint/types': 8.47.0 + '@typescript-eslint/types': 8.48.0 comment-parser: 1.4.1 debug: 4.4.3 eslint: 9.39.1(jiti@2.6.1) @@ -6330,12 +6289,12 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: '@nolyfill/array-includes@1.0.44' @@ -6346,7 +6305,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1(jiti@2.6.1)) hasown: '@nolyfill/hasown@1.0.44' is-core-module: '@nolyfill/is-core-module@1.0.39' is-glob: 4.0.3 @@ -6358,7 +6317,7 @@ snapshots: string.prototype.trimend: '@nolyfill/string.prototype.trimend@1.0.44' tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -6385,14 +6344,6 @@ snapshots: eslint-plugin-no-only-tests@3.3.0: {} - eslint-plugin-no-use-extend-native@0.7.2(eslint@9.39.1(jiti@2.6.1)): - dependencies: - eslint: 9.39.1(jiti@2.6.1) - is-get-set-prop: 2.0.0 - is-js-type: 3.0.0 - is-obj-prop: 2.0.0 - is-proto-prop: 3.0.1 - eslint-plugin-playwright@2.3.0(eslint@9.39.1(jiti@2.6.1)): dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -6470,19 +6421,19 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-vue@10.5.1(@stylistic/eslint-plugin@5.6.1(eslint@9.39.1(jiti@2.6.1)))(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1))): + eslint-plugin-vue@10.6.1(@stylistic/eslint-plugin@5.6.1(eslint@9.39.1(jiti@2.6.1)))(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1))): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) eslint: 9.39.1(jiti@2.6.1) natural-compare: 1.4.0 nth-check: 2.1.1 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 7.1.0 semver: 7.7.3 vue-eslint-parser: 10.2.0(eslint@9.39.1(jiti@2.6.1)) xml-name-validator: 4.0.0 optionalDependencies: '@stylistic/eslint-plugin': 5.6.1(eslint@9.39.1(jiti@2.6.1)) - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-wc@3.0.2(eslint@9.39.1(jiti@2.6.1)): dependencies: @@ -6617,7 +6568,7 @@ snapshots: fflate@0.8.2: {} - file-entry-cache@10.1.4: + file-entry-cache@11.1.1: dependencies: flat-cache: 6.1.19 @@ -6668,8 +6619,6 @@ snapshots: get-east-asian-width@1.4.0: {} - get-set-props@0.2.0: {} - get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -6831,28 +6780,14 @@ snapshots: is-fullwidth-code-point@3.0.0: {} - is-get-set-prop@2.0.0: - dependencies: - get-set-props: 0.2.0 - lowercase-keys: 3.0.0 - is-glob@4.0.3: dependencies: is-extglob: 2.1.1 is-hexadecimal@2.0.1: {} - is-js-type@3.0.0: - dependencies: - js-types: 4.0.0 - is-number@7.0.0: {} - is-obj-prop@2.0.0: - dependencies: - lowercase-keys: 3.0.0 - obj-props: 2.0.0 - is-plain-object@2.0.4: dependencies: isobject: 3.0.1 @@ -6861,11 +6796,6 @@ snapshots: is-potential-custom-element-name@1.0.1: {} - is-proto-prop@3.0.1: - dependencies: - lowercase-keys: 3.0.0 - prototype-properties: 5.0.0 - is-valid-element-name@1.0.0: dependencies: is-potential-custom-element-name: 1.0.1 @@ -6892,8 +6822,6 @@ snapshots: js-tokens@9.0.1: {} - js-types@4.0.0: {} - js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -7028,8 +6956,6 @@ snapshots: lodash@4.17.21: {} - lowercase-keys@3.0.0: {} - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -7079,7 +7005,7 @@ snapshots: marked@4.3.0: {} - material-icon-theme@5.28.0: + material-icon-theme@5.29.0: dependencies: chroma-js: 3.1.2 events: 3.3.0 @@ -7335,15 +7261,15 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.1 - monaco-editor-webpack-plugin@7.1.1(monaco-editor@0.54.0)(webpack@5.103.0): + monaco-editor-webpack-plugin@7.1.1(monaco-editor@0.55.1)(webpack@5.103.0): dependencies: loader-utils: 2.0.4 - monaco-editor: 0.54.0 + monaco-editor: 0.55.1 webpack: 5.103.0(webpack-cli@6.0.1) - monaco-editor@0.54.0: + monaco-editor@0.55.1: dependencies: - dompurify: 3.1.7 + dompurify: 3.2.7 marked: 14.0.0 moo@0.5.2: {} @@ -7386,12 +7312,12 @@ snapshots: dependencies: boolbase: 1.0.0 - obj-props@2.0.0: {} - object-assign@4.1.1: {} object-hash@3.0.0: {} + obug@2.1.1: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -7498,11 +7424,11 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 - playwright-core@1.56.1: {} + playwright-core@1.57.0: {} - playwright@1.56.1: + playwright@1.57.0: dependencies: - playwright-core: 1.56.1 + playwright-core: 1.57.0 optionalDependencies: fsevents: 2.3.2 @@ -7628,8 +7554,6 @@ snapshots: prettier@3.6.2: {} - prototype-properties@5.0.0: {} - punycode.js@2.3.1: {} punycode@2.3.1: {} @@ -7899,25 +7823,25 @@ snapshots: style-search@0.1.0: {} - stylelint-config-recommended@17.0.0(stylelint@16.25.0(typescript@5.9.3)): + stylelint-config-recommended@17.0.0(stylelint@16.26.0(typescript@5.9.3)): dependencies: - stylelint: 16.25.0(typescript@5.9.3) + stylelint: 16.26.0(typescript@5.9.3) - stylelint-declaration-block-no-ignored-properties@2.8.0(stylelint@16.25.0(typescript@5.9.3)): + stylelint-declaration-block-no-ignored-properties@2.8.0(stylelint@16.26.0(typescript@5.9.3)): dependencies: - stylelint: 16.25.0(typescript@5.9.3) + stylelint: 16.26.0(typescript@5.9.3) - stylelint-declaration-strict-value@1.10.11(stylelint@16.25.0(typescript@5.9.3)): + stylelint-declaration-strict-value@1.10.11(stylelint@16.26.0(typescript@5.9.3)): dependencies: - stylelint: 16.25.0(typescript@5.9.3) + stylelint: 16.26.0(typescript@5.9.3) - stylelint-value-no-unknown-custom-properties@6.0.1(stylelint@16.25.0(typescript@5.9.3)): + stylelint-value-no-unknown-custom-properties@6.0.1(stylelint@16.26.0(typescript@5.9.3)): dependencies: postcss-value-parser: 4.2.0 resolve: 1.22.11 - stylelint: 16.25.0(typescript@5.9.3) + stylelint: 16.26.0(typescript@5.9.3) - stylelint@16.25.0(typescript@5.9.3): + stylelint@16.26.0(typescript@5.9.3): dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 @@ -7932,7 +7856,7 @@ snapshots: debug: 4.4.3 fast-glob: 3.3.3 fastest-levenshtein: 1.0.16 - file-entry-cache: 10.1.4 + file-entry-cache: 11.1.1 global-modules: 2.0.0 globby: 11.1.0 globjoin: 0.1.4 @@ -8020,7 +7944,7 @@ snapshots: deep-rename-keys: 0.2.1 xml-reader: 2.4.3 - swagger-ui-dist@5.30.2: + swagger-ui-dist@5.30.3: dependencies: '@scarf/scarf': 1.4.0 @@ -8151,12 +8075,12 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -8206,7 +8130,7 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - updates@16.9.1: {} + updates@16.9.2: {} uri-js@4.4.1: dependencies: @@ -8220,7 +8144,7 @@ snapshots: vite-string-plugin@1.4.9: {} - vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1): + vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -8236,19 +8160,19 @@ snapshots: terser: 5.44.1 yaml: 2.8.1 - vitest@4.0.10(@types/debug@4.1.12)(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1): + vitest@4.0.14(@types/node@24.10.1)(happy-dom@20.0.10)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1): dependencies: - '@vitest/expect': 4.0.10 - '@vitest/mocker': 4.0.10(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1)) - '@vitest/pretty-format': 4.0.10 - '@vitest/runner': 4.0.10 - '@vitest/snapshot': 4.0.10 - '@vitest/spy': 4.0.10 - '@vitest/utils': 4.0.10 - debug: 4.4.3 + '@vitest/expect': 4.0.14 + '@vitest/mocker': 4.0.14(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1)) + '@vitest/pretty-format': 4.0.14 + '@vitest/runner': 4.0.14 + '@vitest/snapshot': 4.0.14 + '@vitest/spy': 4.0.14 + '@vitest/utils': 4.0.14 es-module-lexer: 1.7.0 expect-type: 1.2.2 magic-string: 0.30.21 + obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.10.0 @@ -8256,10 +8180,9 @@ snapshots: tinyexec: 0.3.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.2.2(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/debug': 4.1.12 '@types/node': 24.10.1 happy-dom: 20.0.10 transitivePeerDependencies: @@ -8271,7 +8194,6 @@ snapshots: - sass-embedded - stylus - sugarss - - supports-color - terser - tsx - yaml @@ -8297,14 +8219,14 @@ snapshots: vue-bar-graph@2.2.0(typescript@5.9.3): dependencies: - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) transitivePeerDependencies: - typescript - vue-chartjs@5.3.3(chart.js@4.5.1)(vue@3.5.24(typescript@5.9.3)): + vue-chartjs@5.3.3(chart.js@4.5.1)(vue@3.5.25(typescript@5.9.3)): dependencies: chart.js: 4.5.1 - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1)): dependencies: @@ -8318,28 +8240,28 @@ snapshots: transitivePeerDependencies: - supports-color - vue-loader@17.4.2(vue@3.5.24(typescript@5.9.3))(webpack@5.103.0): + vue-loader@17.4.2(vue@3.5.25(typescript@5.9.3))(webpack@5.103.0): dependencies: chalk: 4.1.2 hash-sum: 2.0.0 watchpack: 2.4.4 webpack: 5.103.0(webpack-cli@6.0.1) optionalDependencies: - vue: 3.5.24(typescript@5.9.3) + vue: 3.5.25(typescript@5.9.3) - vue-tsc@3.1.4(typescript@5.9.3): + vue-tsc@3.1.5(typescript@5.9.3): dependencies: '@volar/typescript': 2.4.23 - '@vue/language-core': 3.1.4(typescript@5.9.3) + '@vue/language-core': 3.1.5(typescript@5.9.3) typescript: 5.9.3 - vue@3.5.24(typescript@5.9.3): + vue@3.5.25(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.24 - '@vue/compiler-sfc': 3.5.24 - '@vue/runtime-dom': 3.5.24 - '@vue/server-renderer': 3.5.24(vue@3.5.24(typescript@5.9.3)) - '@vue/shared': 3.5.24 + '@vue/compiler-dom': 3.5.25 + '@vue/compiler-sfc': 3.5.25 + '@vue/runtime-dom': 3.5.25 + '@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3)) + '@vue/shared': 3.5.25 optionalDependencies: typescript: 5.9.3 diff --git a/web_src/js/features/codeeditor.ts b/web_src/js/features/codeeditor.ts index c1c367c5c28..1e620ce6287 100644 --- a/web_src/js/features/codeeditor.ts +++ b/web_src/js/features/codeeditor.ts @@ -62,9 +62,9 @@ function initLanguages(monaco: Monaco): void { languagesByExt[extension] = id; } if (id === 'typescript') { - monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ + monaco.typescript.typescriptDefaults.setCompilerOptions({ // this is needed to suppress error annotations in tsx regarding missing --jsx flag. - jsx: monaco.languages.typescript.JsxEmit.Preserve, + jsx: monaco.typescript.JsxEmit.Preserve, }); } } diff --git a/web_src/js/features/eventsource.sharedworker.ts b/web_src/js/features/eventsource.sharedworker.ts index 7a2fb817a7a..cfc31e111f4 100644 --- a/web_src/js/features/eventsource.sharedworker.ts +++ b/web_src/js/features/eventsource.sharedworker.ts @@ -69,8 +69,8 @@ class Source { } } -const sourcesByUrl: Map = new Map(); -const sourcesByPort: Map = new Map(); +const sourcesByUrl = new Map(); +const sourcesByPort = new Map(); // @ts-expect-error: typescript bug? self.addEventListener('connect', (e: MessageEvent) => { From a36951aef6361c0ca55cd778fe8811a7dbb4a226 Mon Sep 17 00:00:00 2001 From: hamkido Date: Fri, 28 Nov 2025 08:36:27 +0800 Subject: [PATCH 06/36] Fix error handling in mailer and wiki services (#36041) - Updated error message in `incoming.go` to remove unnecessary wrapping of the error. - Corrected typo in error message in `wiki.go` for clarity. --------- Co-authored-by: Giteabot --- services/mailer/incoming/incoming.go | 3 ++- services/wiki/wiki.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/services/mailer/incoming/incoming.go b/services/mailer/incoming/incoming.go index eade0cf271b..1efaa845b81 100644 --- a/services/mailer/incoming/incoming.go +++ b/services/mailer/incoming/incoming.go @@ -6,6 +6,7 @@ package incoming import ( "context" "crypto/tls" + "errors" "fmt" net_mail "net/mail" "regexp" @@ -221,7 +222,7 @@ loop: err := func() error { r := msg.GetBody(section) if r == nil { - return fmt.Errorf("could not get body from message: %w", err) + return errors.New("could not get body from message") } env, err := enmime.ReadEnvelope(r) diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index a9dc7269829..6a57a9a63e7 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -135,7 +135,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model if hasDefaultBranch { if err := gitRepo.ReadTreeToIndex("HEAD"); err != nil { log.Error("Unable to read HEAD tree to index in: %s %v", basePath, err) - return fmt.Errorf("fnable to read HEAD tree to index in: %s %w", basePath, err) + return fmt.Errorf("unable to read HEAD tree to index in: %s %w", basePath, err) } } From f4e38e6367326276c9493d950cdb85718d244fdf Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Fri, 28 Nov 2025 12:33:52 -0700 Subject: [PATCH 07/36] Fix Actions `pull_request.paths` being triggered incorrectly by rebase (#36045) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partially fix #34710 The bug described in #34710 can be divided into two parts: `push.paths` and `pull_request.paths`. This PR fixes the issue related to `pull_request.paths`. The root cause is that the check for whether the workflow can be triggered happens **before** updating the PR’s merge base. This causes the file-change detection to use the old merge base. Therefore, we need to update the merge base first and then check whether the workflow can be triggered. --- services/pull/pull.go | 30 ++++++++----- services/pull/review.go | 2 +- tests/integration/actions_trigger_test.go | 54 +++++++++++++++++++++++ 3 files changed, 73 insertions(+), 13 deletions(-) diff --git a/services/pull/pull.go b/services/pull/pull.go index 6f0318ea49c..04f48f05655 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -427,10 +427,16 @@ func AddTestPullRequestTask(opts TestPullRequestOptions) { for _, pr := range headBranchPRs { objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName) if opts.NewCommitID != "" && opts.NewCommitID != objectFormat.EmptyObjectID().String() { - changed, err := checkIfPRContentChanged(ctx, pr, opts.OldCommitID, opts.NewCommitID) + changed, newMergeBase, err := checkIfPRContentChanged(ctx, pr, opts.OldCommitID, opts.NewCommitID) if err != nil { log.Error("checkIfPRContentChanged: %v", err) } + if newMergeBase != "" && pr.MergeBase != newMergeBase { + pr.MergeBase = newMergeBase + if _, err := pr.UpdateColsIfNotMerged(ctx, "merge_base"); err != nil { + log.Error("Update merge base for %-v: %v", pr, err) + } + } if changed { // Mark old reviews as stale if diff to mergebase has changed if err := issues_model.MarkReviewsAsStale(ctx, pr.IssueID); err != nil { @@ -496,30 +502,30 @@ func AddTestPullRequestTask(opts TestPullRequestOptions) { // checkIfPRContentChanged checks if diff to target branch has changed by push // A commit can be considered to leave the PR untouched if the patch/diff with its merge base is unchanged -func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest, oldCommitID, newCommitID string) (hasChanged bool, err error) { +func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest, oldCommitID, newCommitID string) (hasChanged bool, mergeBase string, err error) { prCtx, cancel, err := createTemporaryRepoForPR(ctx, pr) // FIXME: why it still needs to create a temp repo, since the alongside calls like GetDiverging doesn't do so anymore if err != nil { log.Error("CreateTemporaryRepoForPR %-v: %v", pr, err) - return false, err + return false, "", err } defer cancel() tmpRepo, err := git.OpenRepository(ctx, prCtx.tmpBasePath) if err != nil { - return false, fmt.Errorf("OpenRepository: %w", err) + return false, "", fmt.Errorf("OpenRepository: %w", err) } defer tmpRepo.Close() // Find the merge-base - _, base, err := tmpRepo.GetMergeBase("", "base", "tracking") + mergeBase, _, err = tmpRepo.GetMergeBase("", "base", "tracking") if err != nil { - return false, fmt.Errorf("GetMergeBase: %w", err) + return false, "", fmt.Errorf("GetMergeBase: %w", err) } - cmd := gitcmd.NewCommand("diff", "--name-only", "-z").AddDynamicArguments(newCommitID, oldCommitID, base) + cmd := gitcmd.NewCommand("diff", "--name-only", "-z").AddDynamicArguments(newCommitID, oldCommitID, mergeBase) stdoutReader, stdoutWriter, err := os.Pipe() if err != nil { - return false, fmt.Errorf("unable to open pipe for to run diff: %w", err) + return false, mergeBase, fmt.Errorf("unable to open pipe for to run diff: %w", err) } stderr := new(bytes.Buffer) @@ -535,19 +541,19 @@ func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest, }). Run(ctx); err != nil { if err == util.ErrNotEmpty { - return true, nil + return true, mergeBase, nil } err = gitcmd.ConcatenateError(err, stderr.String()) log.Error("Unable to run diff on %s %s %s in tempRepo for PR[%d]%s/%s...%s/%s: Error: %v", - newCommitID, oldCommitID, base, + newCommitID, oldCommitID, mergeBase, pr.ID, pr.BaseRepo.FullName(), pr.BaseBranch, pr.HeadRepo.FullName(), pr.HeadBranch, err) - return false, fmt.Errorf("Unable to run git diff --name-only -z %s %s %s: %w", newCommitID, oldCommitID, base, err) + return false, mergeBase, fmt.Errorf("Unable to run git diff --name-only -z %s %s %s: %w", newCommitID, oldCommitID, mergeBase, err) } - return false, nil + return false, mergeBase, nil } // PushToBaseRepo pushes commits from branches of head repository to diff --git a/services/pull/review.go b/services/pull/review.go index 3977e351ca7..9aeeb4c31d6 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -333,7 +333,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos if headCommitID == commitID { stale = false } else { - stale, err = checkIfPRContentChanged(ctx, pr, commitID, headCommitID) + stale, _, err = checkIfPRContentChanged(ctx, pr, commitID, headCommitID) if err != nil { return nil, nil, err } diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index d5486b6a392..9dc0ddb9df8 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -30,6 +30,7 @@ import ( "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" release_service "code.gitea.io/gitea/services/release" @@ -1595,3 +1596,56 @@ jobs: assert.NotNil(t, run) }) } + +func TestPullRequestWithPathsRebase(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + + repoName := "actions-pr-paths-rebase" + apiRepo := createActionsTestRepo(t, token, repoName, false) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}) + apiCtx := NewAPITestContext(t, "user2", repoName, auth_model.AccessTokenScopeWriteRepository) + runner := newMockRunner() + runner.registerAsRepoRunner(t, "user2", repoName, "mock-runner", []string{"ubuntu-latest"}, false) + + // init files and dirs + testCreateFile(t, session, "user2", repoName, repo.DefaultBranch, "", "dir1/dir1.txt", "1") + testCreateFile(t, session, "user2", repoName, repo.DefaultBranch, "", "dir2/dir2.txt", "2") + wfFileContent := `name: ci +on: + pull_request: + paths: + - 'dir1/**' +jobs: + ci-job: + runs-on: ubuntu-latest + steps: + - run: echo 'ci' +` + testCreateFile(t, session, "user2", repoName, repo.DefaultBranch, "", ".gitea/workflows/ci.yml", wfFileContent) + + // create a PR to modify "dir1/dir1.txt", the workflow will be triggered + testEditFileToNewBranch(t, session, "user2", repoName, repo.DefaultBranch, "update-dir1", "dir1/dir1.txt", "11") + _, err := doAPICreatePullRequest(apiCtx, "user2", repoName, repo.DefaultBranch, "update-dir1")(t) + assert.NoError(t, err) + pr1Task := runner.fetchTask(t) + _, _, pr1Run := getTaskAndJobAndRunByTaskID(t, pr1Task.Id) + assert.Equal(t, webhook_module.HookEventPullRequest, pr1Run.Event) + + // create a PR to modify "dir2/dir2.txt" then update main branch and rebase, the workflow will not be triggered + testEditFileToNewBranch(t, session, "user2", repoName, repo.DefaultBranch, "update-dir2", "dir2/dir2.txt", "22") + apiPull, err := doAPICreatePullRequest(apiCtx, "user2", repoName, repo.DefaultBranch, "update-dir2")(t) + runner.fetchNoTask(t) + assert.NoError(t, err) + testEditFile(t, session, "user2", repoName, repo.DefaultBranch, "dir1/dir1.txt", "11") // change the file in "dir1" + req := NewRequestWithValues(t, "POST", + fmt.Sprintf("/%s/%s/pulls/%d/update?style=rebase", "user2", repoName, apiPull.Index), // update by rebase + map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusSeeOther) + runner.fetchNoTask(t) + }) +} From b54af8811efb8e37b9c2e2d56dbc67f689132f83 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 29 Nov 2025 15:13:22 +0100 Subject: [PATCH 08/36] Replace `lint-go-gopls` with additional `govet` linters (#36028) Many (but not all) analyzers ran by `gopls check` are available in `golangci-lint` as part of default-disabled `govet` linters, so I think it's best we remove this manual linting step and let `golangci-lint` handle it. I hand-picked two available linters that were previously linted using gopls and this list is not exhaustive. This will reduce CI time by about 3 minutes. --- .golangci.yml | 4 ++++ Makefile | 9 +-------- tools/lint-go-gopls.sh | 23 ----------------------- 3 files changed, 5 insertions(+), 31 deletions(-) delete mode 100755 tools/lint-go-gopls.sh diff --git a/.golangci.yml b/.golangci.yml index 60482c415fd..2f1587a1e6d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -114,6 +114,10 @@ linters: - stringsbuilder perfsprint: concat-loop: false + govet: + enable: + - nilness + - unusedwrite exclusions: generated: lax presets: diff --git a/Makefile b/Makefile index 4a7e73e5825..647ab38e143 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,6 @@ XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1 GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.9 -GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.20.0 DOCKER_IMAGE ?= gitea/gitea DOCKER_TAG ?= latest @@ -333,7 +332,7 @@ lint-frontend: lint-js lint-css ## lint frontend files lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues .PHONY: lint-backend -lint-backend: lint-go lint-go-gitea-vet lint-go-gopls lint-editorconfig ## lint backend files +lint-backend: lint-go lint-go-gitea-vet lint-editorconfig ## lint backend files .PHONY: lint-backend-fix lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backend files and fix issues @@ -396,11 +395,6 @@ lint-go-gitea-vet: ## lint go files with gitea-vet @echo "Running gitea-vet..." @$(GO) vet -vettool="$(shell GOOS= GOARCH= go tool -n gitea-vet)" ./... -.PHONY: lint-go-gopls -lint-go-gopls: ## lint go files with gopls - @echo "Running gopls check..." - @GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES) - .PHONY: lint-editorconfig lint-editorconfig: @echo "Running editorconfig check..." @@ -844,7 +838,6 @@ deps-tools: ## install tool dependencies $(GO) install $(GO_LICENSES_PACKAGE) & \ $(GO) install $(GOVULNCHECK_PACKAGE) & \ $(GO) install $(ACTIONLINT_PACKAGE) & \ - $(GO) install $(GOPLS_PACKAGE) & \ wait node_modules: pnpm-lock.yaml diff --git a/tools/lint-go-gopls.sh b/tools/lint-go-gopls.sh deleted file mode 100755 index 2cd26ca6fe4..00000000000 --- a/tools/lint-go-gopls.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -set -uo pipefail - -cd "$(dirname -- "${BASH_SOURCE[0]}")" && cd .. - -IGNORE_PATTERNS=( - "is deprecated" # TODO: fix these -) - -# lint all go files with 'gopls check' and look for lines starting with the -# current absolute path, indicating a error was found. This is necessary -# because the tool does not set non-zero exit code when errors are found. -# ref: https://github.com/golang/go/issues/67078 -ERROR_LINES=$("$GO" run "$GOPLS_PACKAGE" check -severity=warning "$@" 2>/dev/null | grep -E "^$PWD" | grep -vFf <(printf '%s\n' "${IGNORE_PATTERNS[@]}")); -NUM_ERRORS=$(echo -n "$ERROR_LINES" | wc -l) - -if [ "$NUM_ERRORS" -eq "0" ]; then - exit 0; -else - echo "$ERROR_LINES" - echo "Found $NUM_ERRORS 'gopls check' errors" - exit 1; -fi From 7d6861ac54f6040b73ae3c929be6fb523a392660 Mon Sep 17 00:00:00 2001 From: Bryan Mutai Date: Sun, 30 Nov 2025 06:58:15 +0300 Subject: [PATCH 09/36] Add "Go to file", "Delete Directory" to repo file list page (#35911) /claim #35898 Resolves #35898 ### Summary of key changes: 1. Add file name search/Go to file functionality to repo button row. 2. Add backend functionality to delete directory 3. Add context menu for directories with functionality to copy path & delete a directory 4. Move Add/Upload file dropdown to right for parity with Github UI 5. Add tree view to the edit/upload UI --------- Co-authored-by: wxiaoguang --- options/locale/locale_en-US.ini | 3 + routers/api/v1/repo/file.go | 4 - routers/web/repo/blame.go | 14 +- routers/web/repo/editor.go | 50 +++- routers/web/repo/editor_apply_patch.go | 2 +- routers/web/repo/editor_cherry_pick.go | 2 +- routers/web/repo/find.go | 24 -- routers/web/repo/view.go | 51 ++-- routers/web/repo/view_home.go | 51 ++-- routers/web/web.go | 1 - services/repository/files/temp_repo.go | 8 + services/repository/files/update.go | 53 +--- templates/repo/editor/delete.tmpl | 29 ++- templates/repo/editor/edit.tmpl | 92 +++---- templates/repo/editor/upload.tmpl | 28 ++- templates/repo/find/files.tmpl | 21 -- templates/repo/view.tmpl | 4 +- templates/repo/view_content.tmpl | 86 ++++--- templates/repo/view_file_tree.tmpl | 30 +-- .../repo/view_file_tree_toggle_button.tmpl | 6 + templates/repo/view_list.tmpl | 2 +- tests/integration/api_repo_file_helpers.go | 3 +- tests/integration/repofiles_change_test.go | 197 ++++++--------- web_src/css/editor/fileeditor.css | 20 -- web_src/css/modules/animations.css | 2 +- web_src/css/repo.css | 58 +++-- web_src/css/repo/home.css | 10 +- web_src/css/themes/theme-gitea-dark.css | 1 + web_src/css/themes/theme-gitea-light.css | 1 + web_src/js/components/RepoFileSearch.vue | 230 ++++++++++++++++++ web_src/js/features/repo-findfile.ts | 65 +---- web_src/js/features/repo-view-file-tree.ts | 8 +- web_src/js/index-domready.ts | 4 +- 33 files changed, 671 insertions(+), 489 deletions(-) delete mode 100644 routers/web/repo/find.go delete mode 100644 templates/repo/find/files.tmpl create mode 100644 templates/repo/view_file_tree_toggle_button.tmpl create mode 100644 web_src/js/components/RepoFileSearch.vue diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index b5b90b31a53..67122509243 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1354,8 +1354,11 @@ editor.this_file_locked = File is locked editor.must_be_on_a_branch = You must be on a branch to make or propose changes to this file. editor.fork_before_edit = You must fork this repository to make or propose changes to this file. editor.delete_this_file = Delete File +editor.delete_this_directory = Delete Directory editor.must_have_write_access = You must have write access to make or propose changes to this file. editor.file_delete_success = File "%s" has been deleted. +editor.directory_delete_success = Directory "%s" has been deleted. +editor.delete_directory = Delete directory '%s' editor.name_your_file = Name your file… editor.filename_help = Add a directory by typing its name followed by a slash ('/'). Remove a directory by typing backspace at the beginning of the input field. editor.or = or diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index ec34d54d224..27a0827a10f 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -610,10 +610,6 @@ func handleChangeRepoFilesError(ctx *context.APIContext, err error) { ctx.APIError(http.StatusUnprocessableEntity, err) return } - if git.IsErrBranchNotExist(err) || files_service.IsErrRepoFileDoesNotExist(err) || git.IsErrNotExist(err) { - ctx.APIError(http.StatusNotFound, err) - return - } if errors.Is(err, util.ErrNotExist) { ctx.APIError(http.StatusNotFound, err) return diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index e304633f952..0eebff6aa88 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -10,7 +10,6 @@ import ( "net/url" "path" "strconv" - "strings" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -42,8 +41,8 @@ type blameRow struct { // RefBlame render blame page func RefBlame(ctx *context.Context) { - ctx.Data["PageIsViewCode"] = true ctx.Data["IsBlame"] = true + prepareRepoViewContent(ctx, ctx.Repo.RefTypeNameSubURL()) // Get current entry user currently looking at. if ctx.Repo.TreePath == "" { @@ -56,17 +55,6 @@ func RefBlame(ctx *context.Context) { return } - treeNames := strings.Split(ctx.Repo.TreePath, "/") - var paths []string - for i := range treeNames { - paths = append(paths, strings.Join(treeNames[:i+1], "/")) - } - - ctx.Data["Paths"] = paths - ctx.Data["TreeNames"] = treeNames - ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() - ctx.Data["RawFileLink"] = ctx.Repo.RepoLink + "/raw/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath) - blob := entry.Blob() fileSize := blob.Size() ctx.Data["FileSize"] = fileSize diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 8c630cb35f0..983249a6d24 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -41,7 +41,12 @@ const ( editorCommitChoiceNewBranch string = "commit-to-new-branch" ) -func prepareEditorCommitFormOptions(ctx *context.Context, editorAction string) *context.CommitFormOptions { +func prepareEditorPage(ctx *context.Context, editorAction string) *context.CommitFormOptions { + prepareHomeTreeSideBarSwitch(ctx) + return prepareEditorPageFormOptions(ctx, editorAction) +} + +func prepareEditorPageFormOptions(ctx *context.Context, editorAction string) *context.CommitFormOptions { cleanedTreePath := files_service.CleanGitTreePath(ctx.Repo.TreePath) if cleanedTreePath != ctx.Repo.TreePath { redirectTo := fmt.Sprintf("%s/%s/%s/%s", ctx.Repo.RepoLink, editorAction, util.PathEscapeSegments(ctx.Repo.BranchName), util.PathEscapeSegments(cleanedTreePath)) @@ -283,7 +288,7 @@ func EditFile(ctx *context.Context) { // on the "New File" page, we should add an empty path field to make end users could input a new name prepareTreePathFieldsAndPaths(ctx, util.Iif(isNewFile, ctx.Repo.TreePath+"/", ctx.Repo.TreePath)) - prepareEditorCommitFormOptions(ctx, editorAction) + prepareEditorPage(ctx, editorAction) if ctx.Written() { return } @@ -376,15 +381,16 @@ func EditFilePost(ctx *context.Context) { // DeleteFile render delete file page func DeleteFile(ctx *context.Context) { - prepareEditorCommitFormOptions(ctx, "_delete") + prepareEditorPage(ctx, "_delete") if ctx.Written() { return } ctx.Data["PageIsDelete"] = true + prepareTreePathFieldsAndPaths(ctx, ctx.Repo.TreePath) ctx.HTML(http.StatusOK, tplDeleteFile) } -// DeleteFilePost response for deleting file +// DeleteFilePost response for deleting file or directory func DeleteFilePost(ctx *context.Context) { parsed := prepareEditorCommitSubmittedForm[*forms.DeleteRepoFileForm](ctx) if ctx.Written() { @@ -392,17 +398,37 @@ func DeleteFilePost(ctx *context.Context) { } treePath := ctx.Repo.TreePath - _, err := files_service.ChangeRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.ChangeRepoFilesOptions{ + if treePath == "" { + ctx.JSONError("cannot delete root directory") // it should not happen unless someone is trying to be malicious + return + } + + // Check if the path is a directory + entry, err := ctx.Repo.Commit.GetTreeEntryByPath(treePath) + if err != nil { + ctx.NotFoundOrServerError("GetTreeEntryByPath", git.IsErrNotExist, err) + return + } + + var commitMessage string + if entry.IsDir() { + commitMessage = parsed.GetCommitMessage(ctx.Locale.TrString("repo.editor.delete_directory", treePath)) + } else { + commitMessage = parsed.GetCommitMessage(ctx.Locale.TrString("repo.editor.delete", treePath)) + } + + _, err = files_service.ChangeRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.ChangeRepoFilesOptions{ LastCommitID: parsed.form.LastCommit, OldBranch: parsed.OldBranchName, NewBranch: parsed.NewBranchName, Files: []*files_service.ChangeRepoFile{ { - Operation: "delete", - TreePath: treePath, + Operation: "delete", + TreePath: treePath, + DeleteRecursively: true, }, }, - Message: parsed.GetCommitMessage(ctx.Locale.TrString("repo.editor.delete", treePath)), + Message: commitMessage, Signoff: parsed.form.Signoff, Author: parsed.GitCommitter, Committer: parsed.GitCommitter, @@ -412,7 +438,11 @@ func DeleteFilePost(ctx *context.Context) { return } - ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", treePath)) + if entry.IsDir() { + ctx.Flash.Success(ctx.Tr("repo.editor.directory_delete_success", treePath)) + } else { + ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", treePath)) + } redirectTreePath := getClosestParentWithFiles(ctx.Repo.GitRepo, parsed.NewBranchName, treePath) redirectForCommitChoice(ctx, parsed, redirectTreePath) } @@ -420,7 +450,7 @@ func DeleteFilePost(ctx *context.Context) { func UploadFile(ctx *context.Context) { ctx.Data["PageIsUpload"] = true prepareTreePathFieldsAndPaths(ctx, ctx.Repo.TreePath) - opts := prepareEditorCommitFormOptions(ctx, "_upload") + opts := prepareEditorPage(ctx, "_upload") if ctx.Written() { return } diff --git a/routers/web/repo/editor_apply_patch.go b/routers/web/repo/editor_apply_patch.go index aad7b4129c7..357c6f3a21a 100644 --- a/routers/web/repo/editor_apply_patch.go +++ b/routers/web/repo/editor_apply_patch.go @@ -14,7 +14,7 @@ import ( ) func NewDiffPatch(ctx *context.Context) { - prepareEditorCommitFormOptions(ctx, "_diffpatch") + prepareEditorPage(ctx, "_diffpatch") if ctx.Written() { return } diff --git a/routers/web/repo/editor_cherry_pick.go b/routers/web/repo/editor_cherry_pick.go index 099814a9fa9..32e3c58e874 100644 --- a/routers/web/repo/editor_cherry_pick.go +++ b/routers/web/repo/editor_cherry_pick.go @@ -16,7 +16,7 @@ import ( ) func CherryPick(ctx *context.Context) { - prepareEditorCommitFormOptions(ctx, "_cherrypick") + prepareEditorPage(ctx, "_cherrypick") if ctx.Written() { return } diff --git a/routers/web/repo/find.go b/routers/web/repo/find.go deleted file mode 100644 index 3a3a7610e77..00000000000 --- a/routers/web/repo/find.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package repo - -import ( - "net/http" - - "code.gitea.io/gitea/modules/templates" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/context" -) - -const ( - tplFindFiles templates.TplName = "repo/find/files" -) - -// FindFiles render the page to find repository files -func FindFiles(ctx *context.Context) { - path := ctx.PathParam("*") - ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + util.PathEscapeSegments(path) - ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + util.PathEscapeSegments(path) - ctx.HTML(http.StatusOK, tplFindFiles) -} diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 09ac33cff43..8e85cc32785 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -245,27 +245,17 @@ func LastCommit(ctx *context.Context) { return } + // The "/lastcommit/" endpoint is used to render the embedded HTML content for the directory file listing with latest commit info + // It needs to construct correct links to the file items, but the route only accepts a commit ID, not a full ref name (branch or tag). + // So we need to get the ref name from the query parameter "refSubUrl". + // TODO: LAST-COMMIT-ASYNC-LOADING: it needs more tests to cover this + refSubURL := path.Clean(ctx.FormString("refSubUrl")) + prepareRepoViewContent(ctx, util.IfZero(refSubURL, ctx.Repo.RefTypeNameSubURL())) renderDirectoryFiles(ctx, 0) if ctx.Written() { return } - var treeNames []string - paths := make([]string, 0, 5) - if len(ctx.Repo.TreePath) > 0 { - treeNames = strings.Split(ctx.Repo.TreePath, "/") - for i := range treeNames { - paths = append(paths, strings.Join(treeNames[:i+1], "/")) - } - - ctx.Data["HasParentPath"] = true - if len(paths)-2 >= 0 { - ctx.Data["ParentPath"] = "/" + paths[len(paths)-2] - } - } - branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() - ctx.Data["BranchLink"] = branchLink - ctx.HTML(http.StatusOK, tplRepoViewList) } @@ -289,7 +279,9 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri return nil } - ctx.Data["LastCommitLoaderURL"] = ctx.Repo.RepoLink + "/lastcommit/" + url.PathEscape(ctx.Repo.CommitID) + "/" + util.PathEscapeSegments(ctx.Repo.TreePath) + // TODO: LAST-COMMIT-ASYNC-LOADING: search this keyword to see more details + lastCommitLoaderURL := ctx.Repo.RepoLink + "/lastcommit/" + url.PathEscape(ctx.Repo.CommitID) + "/" + util.PathEscapeSegments(ctx.Repo.TreePath) + ctx.Data["LastCommitLoaderURL"] = lastCommitLoaderURL + "?refSubUrl=" + url.QueryEscape(ctx.Repo.RefTypeNameSubURL()) // Get current entry user currently looking at. entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) @@ -322,6 +314,21 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri ctx.ServerError("GetCommitsInfo", err) return nil } + + { + if timeout != 0 && !setting.IsProd && !setting.IsInTesting { + log.Debug("first call to get directory file commit info") + clearFilesCommitInfo := func() { + log.Warn("clear directory file commit info to force async loading on frontend") + for i := range files { + files[i].Commit = nil + } + } + _ = clearFilesCommitInfo + // clearFilesCommitInfo() // TODO: LAST-COMMIT-ASYNC-LOADING: debug the frontend async latest commit info loading, uncomment this line, and it needs more tests + } + } + ctx.Data["Files"] = files prepareDirectoryFileIcons(ctx, files) for _, f := range files { @@ -334,16 +341,6 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri if !loadLatestCommitData(ctx, latestCommit) { return nil } - - branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() - treeLink := branchLink - - if len(ctx.Repo.TreePath) > 0 { - treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath) - } - - ctx.Data["TreeLink"] = treeLink - return allEntries } diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go index 17043055e5f..00d30bedef5 100644 --- a/routers/web/repo/view_home.go +++ b/routers/web/repo/view_home.go @@ -362,6 +362,32 @@ func redirectFollowSymlink(ctx *context.Context, treePathEntry *git.TreeEntry) b return false } +func prepareRepoViewContent(ctx *context.Context, refTypeNameSubURL string) { + // for: home, file list, file view, blame + ctx.Data["PageIsViewCode"] = true + ctx.Data["RepositoryUploadEnabled"] = setting.Repository.Upload.Enabled // show Upload File button or menu item + + // prepare the tree path navigation + var treeNames, paths []string + branchLink := ctx.Repo.RepoLink + "/src/" + refTypeNameSubURL + treeLink := branchLink + if ctx.Repo.TreePath != "" { + treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath) + treeNames = strings.Split(ctx.Repo.TreePath, "/") + for i := range treeNames { + paths = append(paths, strings.Join(treeNames[:i+1], "/")) + } + ctx.Data["HasParentPath"] = true + if len(paths)-2 >= 0 { + ctx.Data["ParentPath"] = "/" + paths[len(paths)-2] + } + } + ctx.Data["Paths"] = paths + ctx.Data["TreeLink"] = treeLink + ctx.Data["TreeNames"] = treeNames + ctx.Data["BranchLink"] = branchLink +} + // Home render repository home page func Home(ctx *context.Context) { if handleRepoHomeFeed(ctx) { @@ -383,8 +409,7 @@ func Home(ctx *context.Context) { title += ": " + ctx.Repo.Repository.Description } ctx.Data["Title"] = title - ctx.Data["PageIsViewCode"] = true - ctx.Data["RepositoryUploadEnabled"] = setting.Repository.Upload.Enabled // show New File / Upload File buttons + prepareRepoViewContent(ctx, ctx.Repo.RefTypeNameSubURL()) if ctx.Repo.Commit == nil || ctx.Repo.Repository.IsEmpty || ctx.Repo.Repository.IsBroken() { // empty or broken repositories need to be handled differently @@ -405,26 +430,6 @@ func Home(ctx *context.Context) { return } - // prepare the tree path - var treeNames, paths []string - branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() - treeLink := branchLink - if ctx.Repo.TreePath != "" { - treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath) - treeNames = strings.Split(ctx.Repo.TreePath, "/") - for i := range treeNames { - paths = append(paths, strings.Join(treeNames[:i+1], "/")) - } - ctx.Data["HasParentPath"] = true - if len(paths)-2 >= 0 { - ctx.Data["ParentPath"] = "/" + paths[len(paths)-2] - } - } - ctx.Data["Paths"] = paths - ctx.Data["TreeLink"] = treeLink - ctx.Data["TreeNames"] = treeNames - ctx.Data["BranchLink"] = branchLink - // some UI components are only shown when the tree path is root isTreePathRoot := ctx.Repo.TreePath == "" @@ -455,7 +460,7 @@ func Home(ctx *context.Context) { if isViewHomeOnlyContent(ctx) { ctx.HTML(http.StatusOK, tplRepoViewContent) - } else if len(treeNames) != 0 { + } else if ctx.Repo.TreePath != "" { ctx.HTML(http.StatusOK, tplRepoView) } else { ctx.HTML(http.StatusOK, tplRepoHome) diff --git a/routers/web/web.go b/routers/web/web.go index dd1b391c689..89a570dce07 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1184,7 +1184,6 @@ func registerWebRoutes(m *web.Router) { m.Post("/{username}/{reponame}/markup", optSignIn, context.RepoAssignment, reqUnitsWithMarkdown, web.Bind(structs.MarkupOption{}), misc.Markup) m.Group("/{username}/{reponame}", func() { - m.Get("/find/*", repo.FindFiles) m.Group("/tree-list", func() { m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.TreeList) m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.TreeList) diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go index feb4811bb02..731f23855d2 100644 --- a/services/repository/files/temp_repo.go +++ b/services/repository/files/temp_repo.go @@ -135,6 +135,14 @@ func (t *TemporaryUploadRepository) LsFiles(ctx context.Context, filenames ...st return fileList, nil } +func (t *TemporaryUploadRepository) RemoveRecursivelyFromIndex(ctx context.Context, path string) error { + _, _, err := gitcmd.NewCommand("rm", "--cached", "-r"). + AddDynamicArguments(path). + WithDir(t.basePath). + RunStdBytes(ctx) + return err +} + // RemoveFilesFromIndex removes the given files from the index func (t *TemporaryUploadRepository) RemoveFilesFromIndex(ctx context.Context, filenames ...string) error { objFmt, err := t.gitRepo.GetObjectFormat() diff --git a/services/repository/files/update.go b/services/repository/files/update.go index b07055d57aa..4830f711fc2 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -46,7 +46,10 @@ type ChangeRepoFile struct { FromTreePath string ContentReader io.ReadSeeker SHA string - Options *RepoFileOptions + + DeleteRecursively bool // when deleting, work as `git rm -r ...` + + Options *RepoFileOptions // FIXME: need to refactor, internal usage only } // ChangeRepoFilesOptions holds the repository files update options @@ -69,26 +72,6 @@ type RepoFileOptions struct { executable bool } -// ErrRepoFileDoesNotExist represents a "RepoFileDoesNotExist" kind of error. -type ErrRepoFileDoesNotExist struct { - Path string - Name string -} - -// IsErrRepoFileDoesNotExist checks if an error is a ErrRepoDoesNotExist. -func IsErrRepoFileDoesNotExist(err error) bool { - _, ok := err.(ErrRepoFileDoesNotExist) - return ok -} - -func (err ErrRepoFileDoesNotExist) Error() string { - return fmt.Sprintf("repository file does not exist [path: %s]", err.Path) -} - -func (err ErrRepoFileDoesNotExist) Unwrap() error { - return util.ErrNotExist -} - type LazyReadSeeker interface { io.ReadSeeker io.Closer @@ -217,24 +200,6 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use } } - for _, file := range opts.Files { - if file.Operation == "delete" { - // Get the files in the index - filesInIndex, err := t.LsFiles(ctx, file.TreePath) - if err != nil { - return nil, fmt.Errorf("DeleteRepoFile: %w", err) - } - - // Find the file we want to delete in the index - inFilelist := slices.Contains(filesInIndex, file.TreePath) - if !inFilelist { - return nil, ErrRepoFileDoesNotExist{ - Path: file.TreePath, - } - } - } - } - if hasOldBranch { // Get the commit of the original branch commit, err := t.GetBranchCommit(opts.OldBranch) @@ -272,8 +237,14 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use addedLfsPointers = append(addedLfsPointers, *addedLfsPointer) } case "delete": - if err = t.RemoveFilesFromIndex(ctx, file.TreePath); err != nil { - return nil, err + if file.DeleteRecursively { + if err = t.RemoveRecursivelyFromIndex(ctx, file.TreePath); err != nil { + return nil, err + } + } else { + if err = t.RemoveFilesFromIndex(ctx, file.TreePath); err != nil { + return nil, err + } } default: return nil, fmt.Errorf("invalid file operation: %s %s, supported operations are create, update, delete", file.Operation, file.Options.treePath) diff --git a/templates/repo/editor/delete.tmpl b/templates/repo/editor/delete.tmpl index bf6143f1cb9..70769326a7c 100644 --- a/templates/repo/editor/delete.tmpl +++ b/templates/repo/editor/delete.tmpl @@ -1,13 +1,30 @@ {{template "base/head" .}}
{{template "repo/header" .}} -
+
{{template "base/alert" .}} -
- {{.CsrfTokenHtml}} - {{template "repo/editor/common_top" .}} - {{template "repo/editor/commit_form" .}} -
+
+ {{template "repo/view_file_tree" .}} +
+
+ {{.CsrfTokenHtml}} + {{template "repo/editor/common_top" .}} +
+ {{/* although the UI isn't good enough, this header is necessary for the "left file tree view" toggle button, this button must exist */}} + {{template "repo/view_file_tree_toggle_button" .}} + {{/* then, to make the page looks overall good, add the breadcrumb here to make the toggle button can be shown in a text row, but not a single button*/}} + +
+ {{template "repo/editor/commit_form" .}} +
+
+
{{template "base/footer" .}} diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl index 0911d02e1f4..e6b9c557700 100644 --- a/templates/repo/editor/edit.tmpl +++ b/templates/repo/editor/edit.tmpl @@ -1,53 +1,59 @@ {{template "base/head" .}}
{{template "repo/header" .}} -
+
{{template "base/alert" .}} -
+ {{template "repo/view_file_tree" .}} +
+ - {{.CsrfTokenHtml}} - {{template "repo/editor/common_top" .}} -
- {{template "repo/editor/common_breadcrumb" .}} + > + {{.CsrfTokenHtml}} + {{template "repo/editor/common_top" .}} +
+ {{template "repo/view_file_tree_toggle_button" .}} + {{template "repo/editor/common_breadcrumb" .}} +
+ {{if not .NotEditableReason}} + + {{else}} +
+
+

{{.NotEditableReason}}

+

{{ctx.Locale.Tr "repo.editor.file_not_editable_hint"}}

+
+
+ {{end}} + {{template "repo/editor/commit_form" .}} +
- {{if not .NotEditableReason}} - - {{else}} -
-
-

{{.NotEditableReason}}

-

{{ctx.Locale.Tr "repo.editor.file_not_editable_hint"}}

-
-
- {{end}} - {{template "repo/editor/commit_form" .}} - +
{{template "base/footer" .}} diff --git a/templates/repo/editor/upload.tmpl b/templates/repo/editor/upload.tmpl index 3e36c77b3b9..847d6df88d7 100644 --- a/templates/repo/editor/upload.tmpl +++ b/templates/repo/editor/upload.tmpl @@ -1,19 +1,25 @@ {{template "base/head" .}}
{{template "repo/header" .}} -
+
{{template "base/alert" .}} -
- {{.CsrfTokenHtml}} - {{template "repo/editor/common_top" .}} -
- {{template "repo/editor/common_breadcrumb" .}} +
+ {{template "repo/view_file_tree" .}} +
+ + {{.CsrfTokenHtml}} + {{template "repo/editor/common_top" .}} +
+ {{template "repo/view_file_tree_toggle_button" .}} + {{template "repo/editor/common_breadcrumb" .}} +
+
+ {{template "repo/upload" .}} +
+ {{template "repo/editor/commit_form" .}} +
-
- {{template "repo/upload" .}} -
- {{template "repo/editor/commit_form" .}} - +
{{template "base/footer" .}} diff --git a/templates/repo/find/files.tmpl b/templates/repo/find/files.tmpl deleted file mode 100644 index ce242796bec..00000000000 --- a/templates/repo/find/files.tmpl +++ /dev/null @@ -1,21 +0,0 @@ -{{template "base/head" .}} -
- {{template "repo/header" .}} -
-
- {{.RepoName}} - / -
- -
-
- - - -
-
-

{{ctx.Locale.Tr "repo.find_file.no_matching"}}

-
-
-
-{{template "base/footer" .}} diff --git a/templates/repo/view.tmpl b/templates/repo/view.tmpl index f99fe2f57ab..99f2a7da7ee 100644 --- a/templates/repo/view.tmpl +++ b/templates/repo/view.tmpl @@ -17,9 +17,7 @@ {{template "repo/code/recently_pushed_new_branches" dict "RecentBranchesPromptData" .RecentBranchesPromptData}}
-
- {{template "repo/view_file_tree" .}} -
+ {{template "repo/view_file_tree" .}}
{{template "repo/view_content" .}}
diff --git a/templates/repo/view_content.tmpl b/templates/repo/view_content.tmpl index 66e4fffcb9b..b31648fbbe7 100644 --- a/templates/repo/view_content.tmpl +++ b/templates/repo/view_content.tmpl @@ -5,11 +5,7 @@
{{if not $isTreePathRoot}} - + {{template "repo/view_file_tree_toggle_button" .}} {{end}} {{template "repo/branch_dropdown" dict @@ -37,31 +33,6 @@ {{end}} - - {{if $isTreePathRoot}} - {{ctx.Locale.Tr "repo.find_file.go_to_file"}} - {{end}} - - {{if and .RefFullName.IsBranch (not .IsViewFile)}} - - {{end}} - {{if and $isTreePathRoot .Repository.IsTemplate}} {{ctx.Locale.Tr "repo.use_template"}} @@ -86,12 +57,65 @@
+
+ + {{if .RefFullName.IsBranch}} + {{$addFilePath := .TreePath}} + {{if .IsViewFile}} + {{if gt (len .TreeNames) 1}} + {{$addFilePath = StringUtils.Join (slice .TreeNames 0 (Eval (len .TreeNames) "-" 1)) "/"}} + {{else}} + {{$addFilePath = ""}} + {{end}} + {{end}} +
+ + {{if and (not .IsViewFile) (not $isTreePathRoot)}} + + {{end}} + {{end}} {{if $isTreePathRoot}} {{template "repo/clone_panel" .}} {{end}} {{if and (not $isTreePathRoot) (not .IsViewFile) (not .IsBlame)}}{{/* IsViewDirectory (not home), TODO: split the templates, avoid using "if" tricks */}} - + {{svg "octicon-history" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.file_history"}} {{end}} diff --git a/templates/repo/view_file_tree.tmpl b/templates/repo/view_file_tree.tmpl index 8aed05f3469..f79fcc22aa3 100644 --- a/templates/repo/view_file_tree.tmpl +++ b/templates/repo/view_file_tree.tmpl @@ -1,15 +1,17 @@ -
- - {{ctx.Locale.Tr "files"}} -
+
+
+ + {{ctx.Locale.Tr "files"}} +
-{{/* TODO: Dynamically move components such as refSelector and createPR here */}} -
+ {{/* TODO: Dynamically move components such as refSelector and createPR here */}} +
+
diff --git a/templates/repo/view_file_tree_toggle_button.tmpl b/templates/repo/view_file_tree_toggle_button.tmpl new file mode 100644 index 00000000000..3d6ea928edd --- /dev/null +++ b/templates/repo/view_file_tree_toggle_button.tmpl @@ -0,0 +1,6 @@ + diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl index 145494aa1a9..61443ac4652 100644 --- a/templates/repo/view_list.tmpl +++ b/templates/repo/view_list.tmpl @@ -47,7 +47,7 @@ {{end}} {{end}}
-
+
{{if $commit}} {{$commitLink := printf "%s/commit/%s" $.RepoLink (PathEscape $commit.ID.String)}} {{ctx.RenderUtils.RenderCommitMessageLinkSubject $commit.Message $commitLink $.Repository}} diff --git a/tests/integration/api_repo_file_helpers.go b/tests/integration/api_repo_file_helpers.go index f8d6fc803f1..9a4c4486646 100644 --- a/tests/integration/api_repo_file_helpers.go +++ b/tests/integration/api_repo_file_helpers.go @@ -5,6 +5,7 @@ package integration import ( "context" + "errors" "strings" "testing" @@ -72,7 +73,7 @@ func deleteFileInBranch(user *user_model.User, repo *repo_model.Repository, tree func createOrReplaceFileInBranch(user *user_model.User, repo *repo_model.Repository, treePath, branchName, content string) error { _, err := deleteFileInBranch(user, repo, treePath, branchName) - if err != nil && !files_service.IsErrRepoFileDoesNotExist(err) { + if err != nil && !errors.Is(err, util.ErrNotExist) { return err } diff --git a/tests/integration/repofiles_change_test.go b/tests/integration/repofiles_change_test.go index 6821f8bf611..6fd42401c52 100644 --- a/tests/integration/repofiles_change_test.go +++ b/tests/integration/repofiles_change_test.go @@ -5,6 +5,7 @@ package integration import ( "fmt" + "net/http" "net/url" "path" "strings" @@ -12,7 +13,6 @@ import ( "time" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" @@ -22,6 +22,7 @@ import ( files_service "code.gitea.io/gitea/services/repository/files" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func getCreateRepoFilesOptions(repo *repo_model.Repository) *files_service.ChangeRepoFilesOptions { @@ -93,55 +94,6 @@ func getUpdateRepoFilesRenameOptions(repo *repo_model.Repository) *files_service } } -func getDeleteRepoFilesOptions(repo *repo_model.Repository) *files_service.ChangeRepoFilesOptions { - return &files_service.ChangeRepoFilesOptions{ - Files: []*files_service.ChangeRepoFile{ - { - Operation: "delete", - TreePath: "README.md", - SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", - }, - }, - LastCommitID: "", - OldBranch: repo.DefaultBranch, - NewBranch: repo.DefaultBranch, - Message: "Deletes README.md", - Author: &files_service.IdentityOptions{ - GitUserName: "Bob Smith", - GitUserEmail: "bob@smith.com", - }, - Committer: nil, - } -} - -func getExpectedFileResponseForRepoFilesDelete() *api.FileResponse { - // Just returns fields that don't change, i.e. fields with commit SHAs and dates can't be determined - return &api.FileResponse{ - Content: nil, - Commit: &api.FileCommitResponse{ - Author: &api.CommitUser{ - Identity: api.Identity{ - Name: "Bob Smith", - Email: "bob@smith.com", - }, - }, - Committer: &api.CommitUser{ - Identity: api.Identity{ - Name: "Bob Smith", - Email: "bob@smith.com", - }, - }, - Message: "Deletes README.md\n", - }, - Verification: &api.PayloadCommitVerification{ - Verified: false, - Reason: "gpg.error.not_signed_commit", - Signature: "", - Payload: "", - }, - } -} - func getExpectedFileResponseForRepoFilesCreate(commitID string, lastCommit *git.Commit) *api.FileResponse { treePath := "new/file.txt" encoding := "base64" @@ -578,75 +530,88 @@ func TestChangeRepoFilesWithoutBranchNames(t *testing.T) { } func TestChangeRepoFilesForDelete(t *testing.T) { - onGiteaRun(t, testDeleteRepoFiles) -} + onGiteaRun(t, func(t *testing.T, u *url.URL) { + ctx, _ := contexttest.MockContext(t, "user2/repo1") + ctx.SetPathParam("id", "1") + contexttest.LoadRepo(t, ctx, 1) + contexttest.LoadRepoCommit(t, ctx) + contexttest.LoadUser(t, ctx, 2) + contexttest.LoadGitRepo(t, ctx) + defer ctx.Repo.GitRepo.Close() + repo := ctx.Repo.Repository + doer := ctx.Doer -func testDeleteRepoFiles(t *testing.T, u *url.URL) { - // setup - unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam("id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - repo := ctx.Repo.Repository - doer := ctx.Doer - opts := getDeleteRepoFilesOptions(repo) + t.Run("Delete README.md by commit", func(t *testing.T) { + urlRaw := "/user2/repo1/raw/branch/branch2/README.md" + MakeRequest(t, NewRequest(t, "GET", urlRaw), http.StatusOK) + opts := &files_service.ChangeRepoFilesOptions{ + OldBranch: "branch2", + LastCommitID: "985f0301dba5e7b34be866819cd15ad3d8f508ee", + Files: []*files_service.ChangeRepoFile{ + { + Operation: "delete", + TreePath: "README.md", + }, + }, + Message: "test message", + } + filesResponse, err := files_service.ChangeRepoFiles(t.Context(), repo, doer, opts) + require.NoError(t, err) + assert.NotNil(t, filesResponse) + assert.Nil(t, filesResponse.Files[0]) + assert.Equal(t, "test message\n", filesResponse.Commit.Message) + MakeRequest(t, NewRequest(t, "GET", urlRaw), http.StatusNotFound) + }) - t.Run("Delete README.md file", func(t *testing.T) { - filesResponse, err := files_service.ChangeRepoFiles(t.Context(), repo, doer, opts) - assert.NoError(t, err) - expectedFileResponse := getExpectedFileResponseForRepoFilesDelete() - assert.NotNil(t, filesResponse) - assert.Nil(t, filesResponse.Files[0]) - assert.Equal(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) - assert.Equal(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity) - assert.Equal(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity) - assert.Equal(t, expectedFileResponse.Verification, filesResponse.Verification) - }) + t.Run("Delete README.md with options", func(t *testing.T) { + urlRaw := "/user2/repo1/raw/branch/master/README.md" + MakeRequest(t, NewRequest(t, "GET", urlRaw), http.StatusOK) + opts := &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "delete", + TreePath: "README.md", + SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f", + }, + }, + OldBranch: repo.DefaultBranch, + NewBranch: repo.DefaultBranch, + Message: "Message for deleting README.md", + Author: &files_service.IdentityOptions{GitUserName: "Bob Smith", GitUserEmail: "bob@smith.com"}, + } + filesResponse, err := files_service.ChangeRepoFiles(t.Context(), repo, doer, opts) + require.NoError(t, err) + require.NotNil(t, filesResponse) + assert.Nil(t, filesResponse.Files[0]) + assert.Equal(t, "Message for deleting README.md\n", filesResponse.Commit.Message) + assert.Equal(t, api.Identity{Name: "Bob Smith", Email: "bob@smith.com"}, filesResponse.Commit.Author.Identity) + assert.Equal(t, api.Identity{Name: "Bob Smith", Email: "bob@smith.com"}, filesResponse.Commit.Committer.Identity) + assert.Equal(t, &api.PayloadCommitVerification{Reason: "gpg.error.not_signed_commit"}, filesResponse.Verification) + MakeRequest(t, NewRequest(t, "GET", urlRaw), http.StatusNotFound) + }) - t.Run("Verify README.md has been deleted", func(t *testing.T) { - filesResponse, err := files_service.ChangeRepoFiles(t.Context(), repo, doer, opts) - assert.Nil(t, filesResponse) - expectedError := "repository file does not exist [path: " + opts.Files[0].TreePath + "]" - assert.EqualError(t, err, expectedError) - }) -} - -// Test opts with branch names removed, same results -func TestChangeRepoFilesForDeleteWithoutBranchNames(t *testing.T) { - onGiteaRun(t, testDeleteRepoFilesWithoutBranchNames) -} - -func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { - // setup - unittest.PrepareTestEnv(t) - ctx, _ := contexttest.MockContext(t, "user2/repo1") - ctx.SetPathParam("id", "1") - contexttest.LoadRepo(t, ctx, 1) - contexttest.LoadRepoCommit(t, ctx) - contexttest.LoadUser(t, ctx, 2) - contexttest.LoadGitRepo(t, ctx) - defer ctx.Repo.GitRepo.Close() - - repo := ctx.Repo.Repository - doer := ctx.Doer - opts := getDeleteRepoFilesOptions(repo) - opts.OldBranch = "" - opts.NewBranch = "" - - t.Run("Delete README.md without Branch Name", func(t *testing.T) { - filesResponse, err := files_service.ChangeRepoFiles(t.Context(), repo, doer, opts) - assert.NoError(t, err) - expectedFileResponse := getExpectedFileResponseForRepoFilesDelete() - assert.NotNil(t, filesResponse) - assert.Nil(t, filesResponse.Files[0]) - assert.Equal(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message) - assert.Equal(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity) - assert.Equal(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity) - assert.Equal(t, expectedFileResponse.Verification, filesResponse.Verification) + t.Run("Delete directory", func(t *testing.T) { + urlRaw := "/user2/repo1/raw/branch/sub-home-md-img-check/docs/README.md" + MakeRequest(t, NewRequest(t, "GET", urlRaw), http.StatusOK) + opts := &files_service.ChangeRepoFilesOptions{ + OldBranch: "sub-home-md-img-check", + LastCommitID: "4649299398e4d39a5c09eb4f534df6f1e1eb87cc", + Files: []*files_service.ChangeRepoFile{ + { + Operation: "delete", + TreePath: "docs", + DeleteRecursively: true, + }, + }, + Message: "test message", + } + filesResponse, err := files_service.ChangeRepoFiles(t.Context(), repo, doer, opts) + require.NoError(t, err) + assert.NotNil(t, filesResponse) + assert.Nil(t, filesResponse.Files[0]) + assert.Equal(t, "test message\n", filesResponse.Commit.Message) + MakeRequest(t, NewRequest(t, "GET", urlRaw), http.StatusNotFound) + }) }) } diff --git a/web_src/css/editor/fileeditor.css b/web_src/css/editor/fileeditor.css index 698efffc992..12ae97a1094 100644 --- a/web_src/css/editor/fileeditor.css +++ b/web_src/css/editor/fileeditor.css @@ -1,23 +1,3 @@ -.repository.file.editor .tab[data-tab="write"] { - padding: 0 !important; -} - -.repository.file.editor .tab[data-tab="write"] .editor-toolbar { - border: 0 !important; -} - -.repository.file.editor .tab[data-tab="write"] .CodeMirror { - border-left: 0; - border-right: 0; - border-bottom: 0; -} - -.repo-editor-header { - display: flex; - margin: 1rem 0; - padding: 3px 0; -} - .editor-toolbar { border-color: var(--color-secondary); } diff --git a/web_src/css/modules/animations.css b/web_src/css/modules/animations.css index 779339c46b3..aedf53569a9 100644 --- a/web_src/css/modules/animations.css +++ b/web_src/css/modules/animations.css @@ -28,7 +28,7 @@ aspect-ratio: 1; transform: translate(-50%, -50%); animation: isloadingspin 1000ms infinite linear; - border-width: 4px; + border-width: 3px; border-style: solid; border-color: var(--color-secondary) var(--color-secondary) var(--color-secondary-dark-8) var(--color-secondary-dark-8); border-radius: var(--border-radius-full); diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 9b70e0e6dba..0bf37ca0838 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -150,63 +150,68 @@ td .commit-summary { } } -.repository.file.list .non-diff-file-content .header .icon { +.non-diff-file-content .header .icon { font-size: 1em; } -.repository.file.list .non-diff-file-content .header .small.icon { +.non-diff-file-content .header .small.icon { font-size: 0.75em; } -.repository.file.list .non-diff-file-content .header .tiny.icon { +.non-diff-file-content .header .tiny.icon { font-size: 0.5em; } -.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon { +.non-diff-file-content .header .file-actions .btn-octicon { line-height: var(--line-height-default); padding: 8px; vertical-align: middle; color: var(--color-text); } -.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon:hover { +.non-diff-file-content .header .file-actions .btn-octicon:hover { color: var(--color-primary); } -.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon-danger:hover { +.non-diff-file-content .header .file-actions .btn-octicon-danger:hover { color: var(--color-red); } -.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon.disabled { +.non-diff-file-content .header .file-actions .btn-octicon.disabled { color: inherit; opacity: var(--opacity-disabled); cursor: default; } -.repository.file.list .non-diff-file-content .plain-text { +.non-diff-file-content .plain-text { padding: 1em 2em; } -.repository.file.list .non-diff-file-content .plain-text pre { +.non-diff-file-content .plain-text pre { overflow-wrap: anywhere; white-space: pre-wrap; } -.repository.file.list .non-diff-file-content .csv { +.non-diff-file-content .csv { overflow-x: auto; padding: 0 !important; } -.repository.file.list .non-diff-file-content pre { +.non-diff-file-content pre { overflow: auto; } -.repository.file.list .non-diff-file-content .asciicast { +.non-diff-file-content .asciicast { padding: 0 !important; } .repo-editor-header { + display: flex; + margin: 1rem 0; + padding: 3px 0; width: 100%; + gap: 0.5em; + align-items: center; } .repo-editor-header input { @@ -216,17 +221,13 @@ td .commit-summary { margin-right: 5px !important; } -.repository.file.editor .tabular.menu .svg { - margin-right: 5px; -} - .repository.file.editor .commit-form-wrapper { - padding-left: 48px; + padding-left: 58px; } .repository.file.editor .commit-form-wrapper .commit-avatar { float: left; - margin-left: -48px; + margin-left: -58px; } .repository.file.editor .commit-form-wrapper .commit-form { @@ -1409,12 +1410,25 @@ td .commit-summary { flex-grow: 1; } -.repo-button-row .ui.button { +.repo-button-row .ui.button, +.repo-view-container .ui.button.repo-view-file-tree-toggle { flex-shrink: 0; margin: 0; min-height: 30px; } +.repo-view-container .ui.button.repo-view-file-tree-toggle { + padding: 0 6px; +} + +.repo-button-row .repo-file-search-container .ui.input { + height: 30px; +} + +.repo-button-row .ui.dropdown > .menu { + margin-top: 4px; +} + tbody.commit-list { vertical-align: baseline; } @@ -1483,6 +1497,12 @@ tbody.commit-list { line-height: initial; } +.commit-body a.commit code, +.commit-summary a.commit code { + /* these links are generated by the render: ... */ + background: inherit; +} + .git-notes.top { text-align: left; } diff --git a/web_src/css/repo/home.css b/web_src/css/repo/home.css index ee371f1b1c9..60bf1f17f94 100644 --- a/web_src/css/repo/home.css +++ b/web_src/css/repo/home.css @@ -54,7 +54,9 @@ gap: var(--page-spacing); } -.repo-view-container .repo-view-file-tree-container { +.repo-view-file-tree-container { + display: flex; + flex-direction: column; flex: 0 0 15%; min-width: 0; max-height: 100vh; @@ -65,6 +67,12 @@ overflow-y: hidden; } +@media (max-width: 767.98px) { + .repo-view-file-tree-container { + display: none; + } +} + .repo-view-content { flex: 1; min-width: 0; diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 1718a1f06b7..f89752dc791 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -244,6 +244,7 @@ gitea-theme-meta-info { --color-highlight-fg: #87651e; --color-highlight-bg: #352c1c; --color-overlay-backdrop: #080808c0; + --color-danger: var(--color-red); accent-color: var(--color-accent); color-scheme: dark; } diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index db54f5e5fbf..1261ef8be03 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -244,6 +244,7 @@ gitea-theme-meta-info { --color-highlight-fg: #eed200; --color-highlight-bg: #fffbdd; --color-overlay-backdrop: #080808c0; + --color-danger: var(--color-red); accent-color: var(--color-accent); color-scheme: light; } diff --git a/web_src/js/components/RepoFileSearch.vue b/web_src/js/components/RepoFileSearch.vue new file mode 100644 index 00000000000..cbc1d50656d --- /dev/null +++ b/web_src/js/components/RepoFileSearch.vue @@ -0,0 +1,230 @@ + + + + + diff --git a/web_src/js/features/repo-findfile.ts b/web_src/js/features/repo-findfile.ts index 59c827126fb..7a35a3c7ffe 100644 --- a/web_src/js/features/repo-findfile.ts +++ b/web_src/js/features/repo-findfile.ts @@ -1,13 +1,8 @@ -import {svg} from '../svg.ts'; -import {toggleElem} from '../utils/dom.ts'; -import {pathEscapeSegments} from '../utils/url.ts'; -import {GET} from '../modules/fetch.ts'; +import {createApp} from 'vue'; +import RepoFileSearch from '../components/RepoFileSearch.vue'; +import {registerGlobalInitFunc} from '../modules/observer.ts'; const threshold = 50; -let files: Array = []; -let repoFindFileInput: HTMLInputElement; -let repoFindFileTableBody: HTMLElement; -let repoFindFileNoResult: HTMLElement; // return the case-insensitive sub-match result as an array: [unmatched, matched, unmatched, matched, ...] // res[even] is unmatched, res[odd] is matched, see unit tests for examples @@ -73,48 +68,14 @@ export function filterRepoFilesWeighted(files: Array, filter: string) { return filterResult; } -function filterRepoFiles(filter: string) { - const treeLink = repoFindFileInput.getAttribute('data-url-tree-link'); - repoFindFileTableBody.innerHTML = ''; - - const filterResult = filterRepoFilesWeighted(files, filter); - - toggleElem(repoFindFileNoResult, !filterResult.length); - for (const r of filterResult) { - const row = document.createElement('tr'); - const cell = document.createElement('td'); - const a = document.createElement('a'); - a.setAttribute('href', `${treeLink}/${pathEscapeSegments(r.matchResult.join(''))}`); - a.innerHTML = svg('octicon-file', 16, 'tw-mr-2'); - row.append(cell); - cell.append(a); - for (const [index, part] of r.matchResult.entries()) { - const span = document.createElement('span'); - // safely escape by using textContent - span.textContent = part; - span.title = span.textContent; - // if the target file path is "abc/xyz", to search "bx", then the matchResult is ['a', 'b', 'c/', 'x', 'yz'] - // the matchResult[odd] is matched and highlighted to red. - if (index % 2 === 1) span.classList.add('ui', 'text', 'red'); - a.append(span); - } - repoFindFileTableBody.append(row); - } -} - -async function loadRepoFiles() { - const response = await GET(repoFindFileInput.getAttribute('data-url-data-link')); - files = await response.json(); - filterRepoFiles(repoFindFileInput.value); -} - -export function initFindFileInRepo() { - repoFindFileInput = document.querySelector('#repo-file-find-input'); - if (!repoFindFileInput) return; - - repoFindFileTableBody = document.querySelector('#repo-find-file-table tbody'); - repoFindFileNoResult = document.querySelector('#repo-find-file-no-result'); - repoFindFileInput.addEventListener('input', () => filterRepoFiles(repoFindFileInput.value)); - - loadRepoFiles(); +export function initRepoFileSearch() { + registerGlobalInitFunc('initRepoFileSearch', (el) => { + createApp(RepoFileSearch, { + repoLink: el.getAttribute('data-repo-link'), + currentRefNameSubURL: el.getAttribute('data-current-ref-name-sub-url'), + treeListUrl: el.getAttribute('data-tree-list-url'), + noResultsText: el.getAttribute('data-no-results-text'), + placeholder: el.getAttribute('data-placeholder'), + }).mount(el); + }); } diff --git a/web_src/js/features/repo-view-file-tree.ts b/web_src/js/features/repo-view-file-tree.ts index f52b64cc51d..98ffdb8a86a 100644 --- a/web_src/js/features/repo-view-file-tree.ts +++ b/web_src/js/features/repo-view-file-tree.ts @@ -6,8 +6,12 @@ import {registerGlobalEventFunc} from '../modules/observer.ts'; const {appSubUrl} = window.config; +function isUserSignedIn() { + return Boolean(document.querySelector('#navbar .user-menu')); +} + async function toggleSidebar(btn: HTMLElement) { - const elToggleShow = document.querySelector('.repo-view-file-tree-toggle-show'); + const elToggleShow = document.querySelector('.repo-view-file-tree-toggle[data-toggle-action="show"]'); const elFileTreeContainer = document.querySelector('.repo-view-file-tree-container'); const shouldShow = btn.getAttribute('data-toggle-action') === 'show'; toggleElem(elFileTreeContainer, shouldShow); @@ -15,7 +19,7 @@ async function toggleSidebar(btn: HTMLElement) { // FIXME: need to remove "full height" style from parent element - if (!elFileTreeContainer.hasAttribute('data-user-is-signed-in')) return; + if (!isUserSignedIn()) return; await POST(`${appSubUrl}/user/settings/update_preferences`, { data: {codeViewShowFileTree: shouldShow}, }); diff --git a/web_src/js/index-domready.ts b/web_src/js/index-domready.ts index df56c85c868..8f5d4ecb152 100644 --- a/web_src/js/index-domready.ts +++ b/web_src/js/index-domready.ts @@ -16,7 +16,7 @@ import {initMarkupAnchors} from './markup/anchors.ts'; import {initNotificationCount} from './features/notification.ts'; import {initRepoIssueContentHistory} from './features/repo-issue-content.ts'; import {initStopwatch} from './features/stopwatch.ts'; -import {initFindFileInRepo} from './features/repo-findfile.ts'; +import {initRepoFileSearch} from './features/repo-findfile.ts'; import {initMarkupContent} from './markup/content.ts'; import {initRepoFileView} from './features/file-view.ts'; import {initUserAuthOauth2, initUserCheckAppUrl} from './features/user-auth.ts'; @@ -101,7 +101,7 @@ const initPerformanceTracer = callInitFunctions([ initSshKeyFormParser, initStopwatch, initTableSort, - initFindFileInRepo, + initRepoFileSearch, initCopyContent, initAdminCommon, From 5340db4dbe400c7d03bddbe0bcfc7eddc4a768b5 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 1 Dec 2025 15:50:10 -0800 Subject: [PATCH 10/36] Fix bug when updating user email (#36058) Fix #20390 We should use `ReplacePrimaryEmailAddress` instead of `AdminAddOrSetPrimaryEmailAddress` when modify user's email from admin panel. And also we need a database transaction to keep deletion and insertion succeed at the same time. --- routers/web/admin/users.go | 2 +- services/user/email.go | 67 +++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index a3389361513..ed0eecf90a6 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -409,7 +409,7 @@ func EditUserPost(ctx *context.Context) { } if form.Email != "" { - if err := user_service.AdminAddOrSetPrimaryEmailAddress(ctx, u, form.Email); err != nil { + if err := user_service.ReplacePrimaryEmailAddress(ctx, u, form.Email); err != nil { switch { case user_model.IsErrEmailCharIsNotSupported(err), user_model.IsErrEmailInvalid(err): ctx.Data["Err_Email"] = true diff --git a/services/user/email.go b/services/user/email.go index 5c0de708e9a..de1e024bd15 100644 --- a/services/user/email.go +++ b/services/user/email.go @@ -77,43 +77,44 @@ func ReplacePrimaryEmailAddress(ctx context.Context, u *user_model.User, emailSt return err } - if !u.IsOrganization() { - // Check if address exists already - email, err := user_model.GetEmailAddressByEmail(ctx, emailStr) - if err != nil && !errors.Is(err, util.ErrNotExist) { - return err - } - if email != nil { - if email.IsPrimary && email.UID == u.ID { - return nil + return db.WithTx(ctx, func(ctx context.Context) error { + if !u.IsOrganization() { + // Check if address exists already + email, err := user_model.GetEmailAddressByEmail(ctx, emailStr) + if err != nil && !errors.Is(err, util.ErrNotExist) { + return err + } + if email != nil { + if email.IsPrimary && email.UID == u.ID { + return nil + } + return user_model.ErrEmailAlreadyUsed{Email: emailStr} + } + + // Remove old primary address + primary, err := user_model.GetPrimaryEmailAddressOfUser(ctx, u.ID) + if err != nil { + return err + } + if _, err := db.DeleteByID[user_model.EmailAddress](ctx, primary.ID); err != nil { + return err + } + + // Insert new primary address + if _, err := user_model.InsertEmailAddress(ctx, &user_model.EmailAddress{ + UID: u.ID, + Email: emailStr, + IsActivated: true, + IsPrimary: true, + }); err != nil { + return err } - return user_model.ErrEmailAlreadyUsed{Email: emailStr} } - // Remove old primary address - primary, err := user_model.GetPrimaryEmailAddressOfUser(ctx, u.ID) - if err != nil { - return err - } - if _, err := db.DeleteByID[user_model.EmailAddress](ctx, primary.ID); err != nil { - return err - } + u.Email = emailStr - // Insert new primary address - email = &user_model.EmailAddress{ - UID: u.ID, - Email: emailStr, - IsActivated: true, - IsPrimary: true, - } - if _, err := user_model.InsertEmailAddress(ctx, email); err != nil { - return err - } - } - - u.Email = emailStr - - return user_model.UpdateUserCols(ctx, u, "email") + return user_model.UpdateUserCols(ctx, u, "email") + }) } func AddEmailAddresses(ctx context.Context, u *user_model.User, emails []string) error { From 1e777f92c79d4a5c96aa0183b0bdd62bf6150b80 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 2 Dec 2025 00:38:36 +0000 Subject: [PATCH 11/36] [skip ci] Updated translations via Crowdin --- options/locale/locale_ga-IE.ini | 5 +++++ options/locale/locale_pt-PT.ini | 3 +++ 2 files changed, 8 insertions(+) diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini index abda334ff5b..6b9ae41e9bd 100644 --- a/options/locale/locale_ga-IE.ini +++ b/options/locale/locale_ga-IE.ini @@ -1354,8 +1354,11 @@ editor.this_file_locked=Tá an comhad faoi ghlas editor.must_be_on_a_branch=Caithfidh tú a bheith ar bhrainse chun athruithe a dhéanamh nó a mholadh ar an gcomhad seo. editor.fork_before_edit=Ní mór duit an stór seo a fhorcáil chun athruithe a dhéanamh nó a mholadh ar an gcomhad seo. editor.delete_this_file=Scrios Comhad +editor.delete_this_directory=Scrios Eolaire editor.must_have_write_access=Caithfidh rochtain scríofa a bheith agat chun athruithe a dhéanamh nó a mholadh ar an gcomhad seo. editor.file_delete_success=Tá an comhad "%s" scriosta. +editor.directory_delete_success=Scriosadh an eolaire "%s". +editor.delete_directory=Scrios an eolaire '%s' editor.name_your_file=Ainmnigh do chomhad… editor.filename_help=Cuir eolaire leis trína ainm a chlóscríobh ina dhiaidh sin le slash ('/'). Bain eolaire trí backspace a chlóscríobh ag tús an réimse ionchuir. editor.or=nó @@ -1482,6 +1485,7 @@ projects.column.new_submit=Cruthaigh Colún projects.column.new=Colún Nua projects.column.set_default=Socraigh Réamhshocrú projects.column.set_default_desc=Socraigh an colún seo mar réamhshocrú le haghaidh saincheisteanna agus tarraingtí gan chatagóir +projects.column.default_column_hint=Cuirfear saincheisteanna nua a chuirtear leis an tionscadal seo leis an gcolún seo projects.column.delete=Scrios Colún projects.column.deletion_desc=Ag scriosadh colún tionscadail aistríonn gach saincheist ghaolmhar chuig an gcolún. Lean ar aghaidh? projects.column.color=Dath @@ -3038,6 +3042,7 @@ dashboard.update_migration_poster_id=Nuashonraigh ID póstaer imir dashboard.git_gc_repos=Bailitheoir bruscair gach stórais dashboard.resync_all_sshkeys=Nuashonraigh an comhad '.ssh/authorized_keys' le heochracha SSH Gitea dashboard.resync_all_sshprincipals=Nuashonraigh an comhad '.ssh/authorized_principals' le príomhoidí SSH Gitea +dashboard.resync_all_hooks=Athshioncrónaigh crúcaí git na stórtha uile (réamhghlacadh, nuashonrú, iarghlacadh, próiseasghlacadh, ...) dashboard.reinit_missing_repos=Aththosaigh gach stórais Git atá in easnamh a bhfuil taifid ann dóibh dashboard.sync_external_users=Sioncrónaigh sonraí úsáideoirí seachtracha dashboard.cleanup_hook_task_table=Glan suas an tábla hook_task diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 22e16de93f9..0b2e57ea00c 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -1354,8 +1354,11 @@ editor.this_file_locked=Ficheiro bloqueado editor.must_be_on_a_branch=Tem que estar num ramo para fazer ou propor modificações neste ficheiro. editor.fork_before_edit=Tem que fazer uma derivação deste repositório para fazer ou propor modificações neste ficheiro. editor.delete_this_file=Eliminar ficheiro +editor.delete_this_directory=Eliminar pasta editor.must_have_write_access=Tem que ter permissões de escrita para fazer ou propor modificações neste ficheiro. editor.file_delete_success=O ficheiro "%s" foi eliminado. +editor.directory_delete_success=A pasta "%s" foi eliminada. +editor.delete_directory=Eliminar a pasta '%s' editor.name_your_file=Nomeie o seu ficheiro… editor.filename_help=Adicione uma pasta escrevendo o nome dessa pasta seguido de uma barra('/'). Remova uma pasta carregando na tecla de apagar ('←') no início do campo. editor.or=ou From a04a16dc2b3d4ebc7c56fa3cf40c6321516c22b4 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 2 Dec 2025 21:37:14 +0100 Subject: [PATCH 12/36] adopt changes --- models/issues/review_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/issues/review_test.go b/models/issues/review_test.go index 6795ea8e661..54adbef8c5f 100644 --- a/models/issues/review_test.go +++ b/models/issues/review_test.go @@ -161,7 +161,7 @@ func TestGetReviewersByIssueID(t *testing.T) { UpdatedUnix: 946684815, }, &issues_model.Review{ - ID: 22, + ID: 23, Reviewer: user5, Type: issues_model.ReviewTypeRequest, UpdatedUnix: 946684817, From ca4b21c3054d9e510f2b07d8f224a999d188b9d3 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 2 Dec 2025 21:51:00 +0100 Subject: [PATCH 13/36] Revert "adopt changes" (was intendet for #33356) This reverts commit a04a16dc2b3d4ebc7c56fa3cf40c6321516c22b4. --- models/issues/review_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/issues/review_test.go b/models/issues/review_test.go index 54adbef8c5f..6795ea8e661 100644 --- a/models/issues/review_test.go +++ b/models/issues/review_test.go @@ -161,7 +161,7 @@ func TestGetReviewersByIssueID(t *testing.T) { UpdatedUnix: 946684815, }, &issues_model.Review{ - ID: 23, + ID: 22, Reviewer: user5, Type: issues_model.ReviewTypeRequest, UpdatedUnix: 946684817, From 9f268edd2fbe43c8f97cdac607383dc86d05f9af Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 3 Dec 2025 00:26:07 +0100 Subject: [PATCH 14/36] Update go toolchain to 1.25.5 (#36074) Fixes: https://pkg.go.dev/vuln/GO-2025-4155 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 51cf47b2d32..6806e76ffc5 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module code.gitea.io/gitea go 1.25.0 -toolchain go1.25.4 +toolchain go1.25.5 // rfc5280 said: "The serial number is an integer assigned by the CA to each certificate." // But some CAs use negative serial number, just relax the check. related: From 46d7adefe08e5fde1400261278449dccd082d0f4 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 3 Dec 2025 03:13:16 +0100 Subject: [PATCH 15/36] Enable TypeScript `strictNullChecks` (#35843) A big step towards enabling strict mode in Typescript. There was definitely a good share of potential bugs while refactoring this. When in doubt, I opted to keep the potentially broken behaviour. Notably, the `DOMEvent` type is gone, it was broken and we're better of with type assertions on `e.target`. --------- Signed-off-by: silverwind Signed-off-by: wxiaoguang Co-authored-by: delvh Co-authored-by: wxiaoguang --- eslint.config.ts | 2 +- tsconfig.json | 2 +- web_src/js/bootstrap.ts | 2 +- web_src/js/components/ActivityHeatmap.vue | 4 +- web_src/js/components/ContextPopup.vue | 4 +- web_src/js/components/DashboardRepoList.vue | 4 +- web_src/js/components/DiffCommitSelector.vue | 10 +- web_src/js/components/DiffFileTree.vue | 12 +- web_src/js/components/RepoActionView.vue | 4 +- .../js/components/RepoActivityTopAuthors.vue | 6 +- .../js/components/RepoBranchTagSelector.vue | 45 +++--- web_src/js/components/RepoContributors.vue | 14 +- web_src/js/components/RepoFileSearch.vue | 14 +- web_src/js/components/ViewFileTree.vue | 6 +- web_src/js/components/ViewFileTreeItem.vue | 2 +- web_src/js/components/ViewFileTreeStore.ts | 7 +- web_src/js/features/admin/common.ts | 38 ++--- web_src/js/features/admin/config.ts | 2 +- web_src/js/features/admin/selfcheck.ts | 4 +- web_src/js/features/captcha.ts | 4 +- web_src/js/features/citation.ts | 6 +- web_src/js/features/clipboard.ts | 7 +- web_src/js/features/colorpicker.ts | 15 +- web_src/js/features/common-button.ts | 18 +-- web_src/js/features/common-fetch-action.ts | 2 +- web_src/js/features/common-form.ts | 8 +- web_src/js/features/common-issue-list.ts | 11 +- web_src/js/features/common-organization.ts | 2 +- web_src/js/features/common-page.ts | 4 +- .../js/features/comp/ComboMarkdownEditor.ts | 53 +++---- web_src/js/features/comp/Cropper.ts | 11 +- .../js/features/comp/EditorMarkdown.test.ts | 2 +- web_src/js/features/comp/EditorMarkdown.ts | 7 +- web_src/js/features/comp/EditorUpload.ts | 11 +- web_src/js/features/comp/LabelEdit.ts | 28 ++-- web_src/js/features/comp/ReactionSelector.ts | 9 +- web_src/js/features/comp/SearchUserBox.ts | 2 +- web_src/js/features/comp/TextExpander.ts | 3 +- web_src/js/features/comp/WebHookEditor.ts | 9 +- web_src/js/features/copycontent.ts | 2 +- web_src/js/features/dropzone.ts | 17 +-- .../js/features/eventsource.sharedworker.ts | 15 +- web_src/js/features/file-view.ts | 6 +- web_src/js/features/heatmap.ts | 2 +- web_src/js/features/imagediff.ts | 16 +-- web_src/js/features/install.ts | 56 ++++---- web_src/js/features/notification.ts | 6 +- web_src/js/features/oauth2-settings.ts | 8 +- web_src/js/features/pull-view-file.ts | 20 +-- web_src/js/features/repo-branch.ts | 18 +-- web_src/js/features/repo-code.ts | 22 +-- web_src/js/features/repo-commit.ts | 4 +- web_src/js/features/repo-common.ts | 18 +-- web_src/js/features/repo-diff-commit.ts | 14 +- web_src/js/features/repo-diff.ts | 41 +++--- web_src/js/features/repo-editor.ts | 36 ++--- web_src/js/features/repo-graph.ts | 6 +- web_src/js/features/repo-home.ts | 20 +-- web_src/js/features/repo-issue-content.ts | 8 +- web_src/js/features/repo-issue-edit.ts | 42 +++--- web_src/js/features/repo-issue-list.ts | 30 ++-- web_src/js/features/repo-issue-pull.ts | 16 +-- .../features/repo-issue-sidebar-combolist.ts | 18 +-- web_src/js/features/repo-issue-sidebar.ts | 12 +- web_src/js/features/repo-issue.ts | 133 +++++++++--------- web_src/js/features/repo-legacy.ts | 4 +- web_src/js/features/repo-migrate.ts | 10 +- web_src/js/features/repo-migration.ts | 4 +- web_src/js/features/repo-milestone.ts | 4 +- web_src/js/features/repo-new.ts | 28 ++-- web_src/js/features/repo-projects.ts | 40 +++--- web_src/js/features/repo-release.ts | 18 +-- web_src/js/features/repo-search.ts | 6 +- .../features/repo-settings-branches.test.ts | 6 +- web_src/js/features/repo-settings-branches.ts | 4 +- web_src/js/features/repo-settings.ts | 32 ++--- web_src/js/features/repo-unicode-escape.ts | 4 +- web_src/js/features/repo-view-file-tree.ts | 6 +- web_src/js/features/repo-wiki.ts | 4 +- web_src/js/features/sshkey-helper.ts | 2 +- web_src/js/features/tablesort.ts | 6 +- web_src/js/features/user-auth-webauthn.ts | 10 +- web_src/js/features/user-auth.ts | 2 +- web_src/js/features/user-settings.ts | 6 +- web_src/js/htmx.ts | 4 +- web_src/js/markup/anchors.ts | 4 +- web_src/js/markup/codecopy.ts | 2 +- web_src/js/markup/mermaid.ts | 2 +- web_src/js/markup/refissue.ts | 2 +- web_src/js/markup/render-iframe.ts | 2 +- web_src/js/markup/tasklist.ts | 14 +- web_src/js/modules/diff-file.ts | 4 +- web_src/js/modules/fetch.ts | 4 +- web_src/js/modules/fomantic/tab.ts | 2 +- web_src/js/modules/observer.ts | 4 +- web_src/js/modules/sortable.ts | 4 +- web_src/js/modules/tippy.ts | 6 +- web_src/js/modules/toast.ts | 9 +- web_src/js/standalone/devtest.ts | 10 +- .../js/standalone/external-render-iframe.ts | 2 +- web_src/js/standalone/swagger.ts | 2 +- web_src/js/types.ts | 2 +- web_src/js/utils.ts | 36 ++--- web_src/js/utils/dom.test.ts | 6 +- web_src/js/utils/dom.ts | 25 ++-- web_src/js/webcomponents/absolute-date.ts | 8 +- web_src/js/webcomponents/origin-url.ts | 2 +- web_src/js/webcomponents/overflow-menu.ts | 12 +- 108 files changed, 686 insertions(+), 658 deletions(-) diff --git a/eslint.config.ts b/eslint.config.ts index c849cdbc627..c2fddc856cd 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -205,7 +205,7 @@ export default defineConfig([ '@typescript-eslint/no-non-null-asserted-optional-chain': [2], '@typescript-eslint/no-non-null-assertion': [0], '@typescript-eslint/no-redeclare': [0], - '@typescript-eslint/no-redundant-type-constituents': [0], // rule does not properly work without strickNullChecks + '@typescript-eslint/no-redundant-type-constituents': [2], '@typescript-eslint/no-require-imports': [2], '@typescript-eslint/no-restricted-imports': [0], '@typescript-eslint/no-restricted-types': [0], diff --git a/tsconfig.json b/tsconfig.json index 1daf4b7233b..2466faf592c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -40,7 +40,7 @@ "strictBindCallApply": true, "strictBuiltinIteratorReturn": true, "strictFunctionTypes": true, - "strictNullChecks": false, + "strictNullChecks": true, "stripInternal": true, "verbatimModuleSyntax": true, "types": [ diff --git a/web_src/js/bootstrap.ts b/web_src/js/bootstrap.ts index 4d3f39f5bfa..a94e1d66b0c 100644 --- a/web_src/js/bootstrap.ts +++ b/web_src/js/bootstrap.ts @@ -35,7 +35,7 @@ export function showGlobalErrorMessage(msg: string, msgType: Intent = 'error') { const msgCount = Number(msgDiv.getAttribute(`data-global-error-msg-count`)) + 1; msgDiv.setAttribute(`data-global-error-msg-compact`, msgCompact); msgDiv.setAttribute(`data-global-error-msg-count`, msgCount.toString()); - msgDiv.querySelector('.ui.message').textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); + msgDiv.querySelector('.ui.message')!.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); msgContainer.prepend(msgDiv); } diff --git a/web_src/js/components/ActivityHeatmap.vue b/web_src/js/components/ActivityHeatmap.vue index d805817630c..7c7e0cd94ca 100644 --- a/web_src/js/components/ActivityHeatmap.vue +++ b/web_src/js/components/ActivityHeatmap.vue @@ -5,7 +5,7 @@ import {onMounted, shallowRef} from 'vue'; import type {Value as HeatmapValue, Locale as HeatmapLocale} from '@silverwind/vue3-calendar-heatmap'; defineProps<{ - values?: HeatmapValue[]; + values: HeatmapValue[]; locale: { textTotalContributions: string; heatMapLocale: Partial; @@ -28,7 +28,7 @@ const endDate = shallowRef(new Date()); onMounted(() => { // work around issue with first legend color being rendered twice and legend cut off - const legend = document.querySelector('.vch__external-legend-wrapper'); + const legend = document.querySelector('.vch__external-legend-wrapper')!; legend.setAttribute('viewBox', '12 0 80 10'); legend.style.marginRight = '-12px'; }); diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index 31db902adce..733144aae1a 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -11,15 +11,17 @@ const props = defineProps<{ }>(); const loading = shallowRef(false); -const issue = shallowRef(null); +const issue = shallowRef(null); const renderedLabels = shallowRef(''); const errorMessage = shallowRef(''); const createdAt = computed(() => { + if (!issue?.value) return ''; return new Date(issue.value.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'}); }); const body = computed(() => { + if (!issue?.value) return ''; const body = issue.value.body.replace(/\n+/g, ' '); return body.length > 85 ? `${body.substring(0, 85)}…` : body; }); diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index e938814ec6c..e1f8475ea83 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -110,9 +110,9 @@ export default defineComponent({ }, mounted() { - const el = document.querySelector('#dashboard-repo-list'); + const el = document.querySelector('#dashboard-repo-list')!; this.changeReposFilter(this.reposFilter); - fomanticQuery(el.querySelector('.ui.dropdown')).dropdown(); + fomanticQuery(el.querySelector('.ui.dropdown')!).dropdown(); this.textArchivedFilterTitles = { 'archived': this.textShowOnlyArchived, diff --git a/web_src/js/components/DiffCommitSelector.vue b/web_src/js/components/DiffCommitSelector.vue index e9aa3c67442..fcc7af1fa08 100644 --- a/web_src/js/components/DiffCommitSelector.vue +++ b/web_src/js/components/DiffCommitSelector.vue @@ -23,7 +23,7 @@ type CommitListResult = { export default defineComponent({ components: {SvgIcon}, data: () => { - const el = document.querySelector('#diff-commit-select'); + const el = document.querySelector('#diff-commit-select')!; return { menuVisible: false, isLoading: false, @@ -35,7 +35,7 @@ export default defineComponent({ mergeBase: el.getAttribute('data-merge-base'), commits: [] as Array, hoverActivated: false, - lastReviewCommitSha: '', + lastReviewCommitSha: '' as string | null, uniqueIdMenu: generateElemId('diff-commit-selector-menu-'), uniqueIdShowAll: generateElemId('diff-commit-selector-show-all-'), }; @@ -165,7 +165,7 @@ export default defineComponent({ }, /** Called when user clicks on since last review */ changesSinceLastReviewClick() { - window.location.assign(`${this.issueLink}/files/${this.lastReviewCommitSha}..${this.commits.at(-1).id}${this.queryParams}`); + window.location.assign(`${this.issueLink}/files/${this.lastReviewCommitSha}..${this.commits.at(-1)!.id}${this.queryParams}`); }, /** Clicking on a single commit opens this specific commit */ commitClicked(commitId: string, newWindow = false) { @@ -193,7 +193,7 @@ export default defineComponent({ // find all selected commits and generate a link const firstSelected = this.commits.findIndex((x) => x.selected); const lastSelected = this.commits.findLastIndex((x) => x.selected); - let beforeCommitID: string; + let beforeCommitID: string | null = null; if (firstSelected === 0) { beforeCommitID = this.mergeBase; } else { @@ -204,7 +204,7 @@ export default defineComponent({ if (firstSelected === lastSelected) { // if the start and end are the same, we show this single commit window.location.assign(`${this.issueLink}/commits/${afterCommitID}${this.queryParams}`); - } else if (beforeCommitID === this.mergeBase && afterCommitID === this.commits.at(-1).id) { + } else if (beforeCommitID === this.mergeBase && afterCommitID === this.commits.at(-1)!.id) { // if the first commit is selected and the last commit is selected, we show all commits window.location.assign(`${this.issueLink}/files${this.queryParams}`); } else { diff --git a/web_src/js/components/DiffFileTree.vue b/web_src/js/components/DiffFileTree.vue index 981d10c1c16..e2934b967eb 100644 --- a/web_src/js/components/DiffFileTree.vue +++ b/web_src/js/components/DiffFileTree.vue @@ -12,14 +12,14 @@ const store = diffTreeStore(); onMounted(() => { // Default to true if unset store.fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) !== 'false'; - document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', toggleVisibility); + document.querySelector('.diff-toggle-file-tree-button')!.addEventListener('click', toggleVisibility); hashChangeListener(); window.addEventListener('hashchange', hashChangeListener); }); onUnmounted(() => { - document.querySelector('.diff-toggle-file-tree-button').removeEventListener('click', toggleVisibility); + document.querySelector('.diff-toggle-file-tree-button')!.removeEventListener('click', toggleVisibility); window.removeEventListener('hashchange', hashChangeListener); }); @@ -33,7 +33,7 @@ function expandSelectedFile() { if (store.selectedItem) { const box = document.querySelector(store.selectedItem); const folded = box?.getAttribute('data-folded') === 'true'; - if (folded) setFileFolding(box, box.querySelector('.fold-file'), false); + if (folded) setFileFolding(box, box.querySelector('.fold-file')!, false); } } @@ -48,10 +48,10 @@ function updateVisibility(visible: boolean) { } function updateState(visible: boolean) { - const btn = document.querySelector('.diff-toggle-file-tree-button'); + const btn = document.querySelector('.diff-toggle-file-tree-button')!; const [toShow, toHide] = btn.querySelectorAll('.icon'); - const tree = document.querySelector('#diff-file-tree'); - const newTooltip = btn.getAttribute(visible ? 'data-hide-text' : 'data-show-text'); + const tree = document.querySelector('#diff-file-tree')!; + const newTooltip = btn.getAttribute(visible ? 'data-hide-text' : 'data-show-text')!; btn.setAttribute('data-tooltip-content', newTooltip); toggleElem(tree, visible); toggleElem(toShow, !visible); diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 00748ee9bb2..357a2ba10ee 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -402,7 +402,7 @@ export default defineComponent({ } // auto-scroll to the last log line of the last step - let autoScrollJobStepElement: HTMLElement; + let autoScrollJobStepElement: HTMLElement | undefined; for (let stepIndex = 0; stepIndex < this.currentJob.steps.length; stepIndex++) { if (!autoScrollStepIndexes.get(stepIndex)) continue; autoScrollJobStepElement = this.getJobStepLogsContainer(stepIndex); @@ -468,7 +468,7 @@ export default defineComponent({ } const logLine = this.elStepsContainer().querySelector(selectedLogStep); if (!logLine) return; - logLine.querySelector('.line-num').click(); + logLine.querySelector('.line-num')!.click(); }, }, }); diff --git a/web_src/js/components/RepoActivityTopAuthors.vue b/web_src/js/components/RepoActivityTopAuthors.vue index 5a925f99431..1d04fa52397 100644 --- a/web_src/js/components/RepoActivityTopAuthors.vue +++ b/web_src/js/components/RepoActivityTopAuthors.vue @@ -1,7 +1,7 @@