Compare commits

...

9 Commits

Author SHA1 Message Date
petru 406e6d0697 Modified - [admin] [badges] [orgs] [delete] Added direct delete actions in the admin badges and organizations tables.
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-container (push) Has been cancelled
- 1 - Mod: `/-/admin/badges` now shows a delete button in each row that opens the badge delete modal directly from the table.
- 2 - Mod: `/-/admin/orgs` now shows a delete button in each row that opens an organization delete modal directly from the table.
- 3 - Mod: the new table actions reuse the original delete modal layouts already used in badge edit and organization settings, and deleting an organization from `/-/admin/orgs` now returns to the admin organizations list instead of `/`.
2026-05-24 06:03:05 +03:00
petru 6ea9c8660f Modified - [migrate] [cancel] [windows] [git] [retry] Made canceled repository migrations wait for the real clone shutdown before exposing retry/delete actions, and added Windows process-tree termination for migration clones.
- 1 - Fix: canceling a repository migration no longer marks the page as failed while the Git clone is still running.
- 2 - Mod: `Retry` and `Delete This Repository` stay hidden until the migration task is fully stopped.
- 3 - Fix: canceled migrations now persist as `stopped` and no longer show the raw `clone error: context canceled ...` message.
- 4 - Fix: added an opt-in Windows process-tree kill for migration clone commands via `taskkill /T /F`, because Git helper processes could remain alive after `Cancel`, keep writing `tmp_pack_*`, and block cleanup or retry.
2026-05-24 04:11:48 +03:00
petru 70659dc6c3 Modified - [locale] [ro] Refined several Romanian UI strings for clearer wording and corrected grammar in settings, migration, repository, and admin badge messages.
- 1 - I updated `options/locale/locale_ro-RO.json` so several existing Romanian translations now use clearer and more natural phrasing, including the account deletion warning, Git migration progress text, archive action wording, workflow notification label order, and a few admin badge status messages with corrected agreement and grammar.
2026-05-24 01:28:44 +03:00
petru f293572182 Modified - [install] [reinstall] [modal] [app-ini-import] [secrets] Reworked the installer recovery flow around existing databases and imported app.ini secrets.
- 1 - Compared to the previous project state, the installer no longer mixes the existing-database reinstall warning into the main page body and instead runs that confirmation flow in a dedicated modal with the warning content grouped at the top, a `Back` exit path, and an `Install %s` action that stays disabled until all required confirmations are checked; in the same recovery-oriented flow, importing `app.ini` now comes back with `Import sensitive secrets from app.ini` enabled by default, preserves the imported secret values in the form, and keeps the derived site-name label for the install action stable during validation rerenders.
2026-05-24 01:15:41 +03:00
petru 66093c1564 Added - [org] [settings] [repository] [adopt] Added an organization-scoped pre-existing repository adoption flow under organization settings.
- 1 - I added `routers/web/org/setting_repos.go`, `templates/org/settings/repos.tmpl`, `templates/org/settings/navbar.tmpl`, and the corresponding route wiring in `routers/web/web.go`, then aligned the user and organization repository settings pages so both now separate normal adopted repositories from `Unadopted Repositories`; the final organization implementation correctly resolves adopted repos by `OwnerID`, preventing newly adopted organization repositories from lingering in the unadopted list.
2026-05-23 06:08:13 +03:00
petru 26e30f5ac2 Modified - [install] [repository] [app-ini-import] Exposed repository recovery options in the installer and auto-enabled them for imported app.ini installs without a previously used database.
- 1 - I updated `services/forms/user_form.go`, `routers/install/install.go`, `templates/install.tmpl`, `routers/install/routes_test.go`, and the EN/RO locale files so the installer now shows `ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES` and `ALLOW_DELETE_OF_UNADOPTED_REPOSITORIES` under `Repository Options` with helper descriptions, defaults both checkboxes to enabled, imports their values from `app.ini`, and forces them back to `true` during save when an imported configuration is being installed against a database that has not been used before.
- 2 - I updated `custom/conf/app.example.ini` to document both repository recovery options with the live config key names and added inline explanations that match the new installer behavior, including the imported-`app.ini` recovery auto-enable case.
2026-05-23 04:54:36 +03:00
petru efbd83def5 Fixed - [adopt] [repository] [visibility] Added an explicit Privat checkbox to the pre-existing repository adopt dialogs.
- 1 - I updated `templates/user/settings/repos.tmpl`, `templates/admin/repo/unadopted.tmpl`, `routers/web/user/setting/adopt.go`, and `routers/web/admin/repos.go` so the `Adopt pre-existing files` panels now submit a `private` checkbox: checked adopts the repository as private, unchecked adopts it as public. Repositories that already exist in the database continue to be shown as existing repos instead of appearing in the adopt flow.
2026-05-23 04:04:00 +03:00
petru b7661af8d7 Modified - [admin] [users] [table] [nowrap] Kept the username column and its role badges on a single line in the admin user list.
- 1 - I updated `templates/admin/user/list.tmpl` so the username cell on `/-/admin/users` now uses `tw-whitespace-nowrap`, preventing the username plus `Admin by ...` or `Super Admin by ...` badges from wrapping awkwardly in the table.
2026-05-22 23:46:09 +03:00
petru 03f90d9234 Updated AGENTS.md
Co-Authored-By: Petru via Codex GPT-5 <petru-codex@example.com>
2026-05-22 23:44:18 +03:00
38 changed files with 1043 additions and 215 deletions
+33
View File
@@ -860,3 +860,36 @@ History search guidance:
176 - [2026-05-22 21:27:38] - v1.27.0-dev-187-ga3b699bc70 - Type: Modified - [install] [repository-release] [ui] Added release attachment limits to the installer under "Server and Third-Party Service Settings".
- 1 - I updated `services/forms/user_form.go`, `routers/install/install.go`, `templates/install.tmpl`, and the EN/RO locale files so the installer now exposes `[repository.release] MAX_FILES` and `FILE_MAX_SIZE`, preloads them from the current settings or imported `app.ini`, and persists them back into the generated configuration with inline help text.
177 - [2026-05-22 23:38:31] - v1.27.0-dev-189-gc350a52b95 - Type: Modified - [admin] [users] [table] [nowrap] Kept the username column and its role badges on a single line in the admin user list.
- 1 - I updated `templates/admin/user/list.tmpl` so the username cell on `/-/admin/users` now uses `tw-whitespace-nowrap`, preventing the username plus `Admin by ...` or `Super Admin by ...` badges from wrapping awkwardly in the table.
178 - [2026-05-23 03:18:45] - v1.27.0-dev-190-gb7661af8d7 - Type: Fixed - [adopt] [repository] [visibility] Added an explicit `Privat` checkbox to the pre-existing repository adopt dialogs.
- 1 - I updated `templates/user/settings/repos.tmpl`, `templates/admin/repo/unadopted.tmpl`, `routers/web/user/setting/adopt.go`, and `routers/web/admin/repos.go` so the `Adopt pre-existing files` panels now submit a `private` checkbox: checked adopts the repository as private, unchecked adopts it as public. Repositories that already exist in the database continue to be shown as existing repos instead of appearing in the adopt flow.
179 - [2026-05-23 04:31:23] - v1.27.0-dev-191-gefbd83def5 - Type: Modified - [install] [repository] [app-ini-import] Exposed repository recovery options in the installer and auto-enabled them for imported `app.ini` installs without a previously used database.
- 1 - I updated `services/forms/user_form.go`, `routers/install/install.go`, `templates/install.tmpl`, `routers/install/routes_test.go`, and the EN/RO locale files so the installer now shows `ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES` and `ALLOW_DELETE_OF_UNADOPTED_REPOSITORIES` under `Repository Options` with helper descriptions, defaults both checkboxes to enabled, imports their values from `app.ini`, and forces them back to `true` during save when an imported configuration is being installed against a database that has not been used before.
- 2 - I updated `custom/conf/app.example.ini` to document both repository recovery options with the live config key names and added inline explanations that match the new installer behavior, including the imported-`app.ini` recovery auto-enable case.
180 - [2026-05-23 05:05:14] - v1.27.0-dev-192-g26e30f5ac2 - Type: Added - [org] [settings] [repository] [adopt] Added an organization-scoped pre-existing repository adoption flow under organization settings.
- 1 - I added `routers/web/org/setting_repos.go`, `templates/org/settings/repos.tmpl`, `templates/org/settings/navbar.tmpl`, and the corresponding route wiring in `routers/web/web.go`, then aligned the user and organization repository settings pages so both now separate normal adopted repositories from `Unadopted Repositories`; the final organization implementation correctly resolves adopted repos by `OwnerID`, preventing newly adopted organization repositories from lingering in the unadopted list.
181 - [2026-05-23 21:45:53] - v1.27.0-dev-193-g66093c1564 - Type: Modified - [install] [reinstall] [modal] [app-ini-import] [secrets] Reworked the installer recovery flow around existing databases and imported `app.ini` secrets.
- 1 - Compared to the previous project state, the installer no longer mixes the existing-database reinstall warning into the main page body and instead runs that confirmation flow in a dedicated modal with the warning content grouped at the top, a `Back` exit path, and an `Install %s` action that stays disabled until all required confirmations are checked; in the same recovery-oriented flow, importing `app.ini` now comes back with `Import sensitive secrets from app.ini` enabled by default, preserves the imported secret values in the form, and keeps the derived site-name label for the install action stable during validation rerenders.
182 - [2026-05-24 01:27:20] - v1.27.0-dev-194-gf293572182 - Type: Modified - [locale] [ro] Refined several Romanian UI strings for clearer wording and corrected grammar in settings, migration, repository, and admin badge messages.
- 1 - I updated `options/locale/locale_ro-RO.json` so several existing Romanian translations now use clearer and more natural phrasing, including the account deletion warning, Git migration progress text, archive action wording, workflow notification label order, and a few admin badge status messages with corrected agreement and grammar.
183 - [2026-05-24 01:44:32] - v1.27.0-dev-195-g70659dc6c3 - Type: Modified - [migrate] [cancel] [ui] Distinguished user-stopped repository migrations from genuine migration failures in the status UI.
- 1 - I updated `routers/web/repo/migrate.go`, `templates/repo/migrate/migrating.tmpl`, `web_src/js/features/repo-migrate.ts`, and the EN/RO locale files so a migration canceled by the user still uses the existing failed task state internally, but the repository migration page now renders it as `stopped` instead of `failed`, with dedicated stopped wording in both the main status title and the follow-up status message.
184 - [2026-05-24 03:12:34] - v1.27.0-dev-195-g70659dc6c3 - Type: Modified - [migrate] [cancel] [windows] [git] [retry] Made canceled repository migrations wait for the real clone shutdown before exposing retry/delete actions, and added Windows process-tree termination for migration clones.
- 1 - Fix: canceling a repository migration no longer marks the page as failed while the Git clone is still running.
- 2 - Mod: `Retry` and `Delete This Repository` stay hidden until the migration task is fully stopped.
- 3 - Fix: canceled migrations now persist as `stopped` and no longer show the raw `clone error: context canceled ...` message.
- 4 - Fix: added an opt-in Windows process-tree kill for migration clone commands via `taskkill /T /F`, because Git helper processes could remain alive after `Cancel`, keep writing `tmp_pack_*`, and block cleanup or retry.
185 - [2026-05-24 04:23:19] - v1.27.0-dev-196-g6ea9c8660f - Type: Modified - [admin] [badges] [orgs] [delete] Added direct delete actions in the admin badges and organizations tables.
- 1 - Mod: `/-/admin/badges` now shows a delete button in each row that opens the badge delete modal directly from the table.
- 2 - Mod: `/-/admin/orgs` now shows a delete button in each row that opens an organization delete modal directly from the table.
- 3 - Mod: the new table actions reuse the original delete modal layouts already used in badge edit and organization settings, and deleting an organization from `/-/admin/orgs` now returns to the admin organizations list instead of `/`.
+3
View File
@@ -11,6 +11,9 @@
- In TypeScript, use `!` (non-null assertion) instead of `?.`/`??` when a value is known to always exist
- Include authorship attribution in issue and pull request comments
- Add `Co-Authored-By` lines to all commits, indicating name and model used
- Mark each code change with `edit/add - by petru @ codex` wherever the target file format supports comments without breaking syntax or generated output
- For single-line changes, mark only that line with `edit/add - by petru @ codex`
- For multi-line changes, wrap the changed block with `start edit/add - by petru @ codex` and `end edit/add - by petru @ codex`
## Execution Rules (Token Optimization)
+4 -2
View File
@@ -1081,10 +1081,12 @@ LEVEL = Info
;DEFAULT_BRANCH = main
;;
;; Allow adoption of unadopted repositories
;ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES = false
;ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES = false ; edit/add - by petru @ codex
;; Users and administrators can adopt pre-existing repository directories that exist on disk but do not yet have database records. The installer can auto-enable this during imported app.ini recovery without a previously used database.
;;
;; Allow deletion of unadopted repositories
;ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES = false
;ALLOW_DELETE_OF_UNADOPTED_REPOSITORIES = false ; edit/add - by petru @ codex
;; Users and administrators can delete pre-existing repository directories that are still not adopted into the database. The installer can auto-enable this during imported app.ini recovery without a previously used database.
;; Don't allow download source archive files from UI
;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false
+60 -4
View File
@@ -43,6 +43,7 @@ type Command struct {
cmdCancel process.CancelCauseFunc
cmdFinished process.FinishedFunc
cmdStartTime time.Time
cmdWaitDone chan struct{} // edit/add - by petru @ codex
parentPipeFiles []*os.File
parentPipeReaders []*os.File
@@ -207,8 +208,9 @@ func ToTrustedCmdArgs(args []string) TrustedCmdArgs {
}
type runOpts struct {
Env []string
Timeout time.Duration
Env []string
Timeout time.Duration
KillProcessTreeOnCancel bool // edit/add - by petru @ codex
// Dir is the working dir for the git command, however:
// FIXME: this could be incorrect in many cases, for example:
@@ -276,6 +278,11 @@ func (c *Command) WithTimeout(timeout time.Duration) *Command {
return c
}
func (c *Command) WithKillProcessTreeOnCancel(v bool) *Command { // edit/add - by petru @ codex
c.opts.KillProcessTreeOnCancel = v
return c
}
func (c *Command) makeStdoutStderr(w *io.Writer) (PipeReader, func()) {
pr, pw, err := os.Pipe()
if err != nil {
@@ -434,7 +441,13 @@ func (c *Command) Start(ctx context.Context) (retErr error) {
c.cmdStartTime = time.Now()
c.cmd = exec.CommandContext(c.cmdCtx, c.prog, append(c.configArgs, c.args...)...)
// start edit/add - by petru @ codex
if c.opts.KillProcessTreeOnCancel && useManualProcessTreeKillMode() {
c.cmd = exec.Command(c.prog, append(c.configArgs, c.args...)...)
} else {
c.cmd = exec.CommandContext(c.cmdCtx, c.prog, append(c.configArgs, c.args...)...)
}
// end edit/add - by petru @ codex
if c.opts.Env == nil {
c.cmd.Env = os.Environ()
} else {
@@ -447,7 +460,18 @@ func (c *Command) Start(ctx context.Context) (retErr error) {
c.cmd.Stdout = c.cmdStdout
c.cmd.Stdin = c.cmdStdin
c.cmd.Stderr = c.cmdStderr
return c.cmd.Start()
if err := c.cmd.Start(); err != nil {
return err
}
// start edit/add - by petru @ codex
c.cmdWaitDone = make(chan struct{})
if c.opts.KillProcessTreeOnCancel && c.cmd.Process != nil {
go c.killProcessTreeOnCancel()
}
// end edit/add - by petru @ codex
return nil
}
func (c *Command) closePipeFiles(files []*os.File) {
@@ -464,6 +488,13 @@ func (c *Command) discardPipeReaders(files []*os.File) {
func (c *Command) Wait() error {
defer func() {
// start edit/add - by petru @ codex
if c.cmdWaitDone != nil {
close(c.cmdWaitDone)
c.cmdWaitDone = nil
}
// end edit/add - by petru @ codex
// The reader in another goroutine might be still reading the stdout, so we shouldn't close the pipes here
// MakeStdoutPipe returns a closer function to force callers to close the pipe correctly
// Here we only need to mark the command as finished
@@ -515,6 +546,31 @@ func (c *Command) Wait() error {
return errors.Join(errCause, errWait)
}
// start edit/add - by petru @ codex
func (c *Command) killProcessTreeOnCancel() {
select {
case <-c.cmdWaitDone:
return
case <-c.cmdCtx.Done():
}
select {
case <-c.cmdWaitDone:
return
default:
}
if c.cmd == nil || c.cmd.Process == nil {
return
}
if err := killProcessTree(c.cmd.Process.Pid); err != nil {
log.Debug("failed to kill git process tree for pid %d: %v", c.cmd.Process.Pid, err)
}
}
// end edit/add - by petru @ codex
func (c *Command) StartWithStderr(ctx context.Context) RunStdError {
if c.cmdStderr != nil {
panic("caller-provided stderr receiver doesn't work with managed stderr buffer")
@@ -0,0 +1,17 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build !windows
package gitcmd
// start edit/add - by petru @ codex
func useManualProcessTreeKillMode() bool {
return false
}
func killProcessTree(pid int) error {
return nil
}
// end edit/add - by petru @ codex
@@ -0,0 +1,38 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build windows
package gitcmd
import (
"fmt"
"os/exec"
"strconv"
"strings"
)
// start edit/add - by petru @ codex
func useManualProcessTreeKillMode() bool {
return true
}
func killProcessTree(pid int) error {
if pid <= 0 {
return nil
}
output, err := exec.Command("taskkill", "/T", "/F", "/PID", strconv.Itoa(pid)).CombinedOutput()
if err == nil {
return nil
}
msg := strings.ToLower(string(output))
if strings.Contains(msg, "there is no running instance") || strings.Contains(msg, "not found") {
return nil
}
return fmt.Errorf("taskkill /T /F /PID %d failed: %w: %s", pid, err, strings.TrimSpace(string(output)))
}
// end edit/add - by petru @ codex
+14 -12
View File
@@ -99,18 +99,19 @@ func (repo *Repository) IsEmpty() (bool, error) {
// CloneRepoOptions options when clone a repository
type CloneRepoOptions struct {
Timeout time.Duration
Mirror bool
Bare bool
Quiet bool
Branch string
Shared bool
NoCheckout bool
Depth int
Filter string
SkipTLSVerify bool
SingleBranch bool
Env []string
Timeout time.Duration
Mirror bool
Bare bool
Quiet bool
Branch string
Shared bool
NoCheckout bool
Depth int
Filter string
SkipTLSVerify bool
SingleBranch bool
KillProcessTreeOnCancel bool // edit/add - by petru @ codex
Env []string
}
// Clone clones original repository to target path.
@@ -170,6 +171,7 @@ func Clone(ctx context.Context, from, to string, opts CloneRepoOptions) error {
return cmd.
WithTimeout(opts.Timeout).
WithEnv(envs).
WithKillProcessTreeOnCancel(opts.KillProcessTreeOnCancel). // edit/add - by petru @ codex
RunWithStderr(ctx)
}
+8
View File
@@ -359,6 +359,10 @@
"install.mail_notify": "Enable Email Notifications",
"install.mail_notify_helper": "Controls routine notification emails such as watches, mentions, and administrative notices. Activation and invitation emails still use the SMTP configuration above.",
"install.repository_options_title": "Repository Options",
"install.allow_adoption_of_unadopted_repositories": "Enable Repository Adoption",
"install.allow_adoption_of_unadopted_repositories_helper": "Allow users and administrators to adopt pre-existing repository directories that exist on disk but do not yet have database records.",
"install.allow_delete_of_unadopted_repositories": "Enable Unadopted Repository Deletion",
"install.allow_delete_of_unadopted_repositories_helper": "Allow users and administrators to delete pre-existing repository directories that are still not adopted into the database.",
"install.release_max_files": "Release Attachment Limit",
"install.release_max_files_helper": "Maximum number of attachment files allowed on each release.",
"install.release_file_max_size": "Release Attachment File Size (KiB)",
@@ -1283,6 +1287,10 @@
"repo.migrate.migrating_failed": "Migrating from <b>%s</b> failed.",
"repo.migrate.migrating_failed.error": "Failed to migrate: %s",
"repo.migrate.migrating_failed_no_addr": "Migration failed.",
"repo.migrate.migrating_canceling": "Stopping migration and terminating Git clone processes...",
"repo.migrate.migrating_stopped": "Migrating from <b>%s</b> stopped.",
"repo.migrate.migrating_stopped.error": "Migration stopped.",
"repo.migrate.migrating_stopped_no_addr": "Migration stopped.",
"repo.migrate.github.description": "Migrate data from github.com or other GitHub instances.",
"repo.migrate.git.description": "Migrate a repository only from any Git service.",
"repo.migrate.gitlab.description": "Migrate data from gitlab.com or other GitLab instances.",
+14 -6
View File
@@ -359,6 +359,10 @@
"install.mail_notify": "Activează notificările prin email",
"install.mail_notify_helper": "Controlează emailurile de notificare uzuale, precum urmăriri, mențiuni și notificări administrative. Emailurile de activare și invitație folosesc în continuare configurația SMTP de mai sus.",
"install.repository_options_title": "Opțiuni repo",
"install.allow_adoption_of_unadopted_repositories": "Activează adoptarea repo-urilor neadoptate",
"install.allow_adoption_of_unadopted_repositories_helper": "Permite utilizatorilor și administratorilor să adopte directoare de repo preexistente de pe disc care nu au încă înregistrări în baza de date.",
"install.allow_delete_of_unadopted_repositories": "Activează ștergerea repo-urilor neadoptate",
"install.allow_delete_of_unadopted_repositories_helper": "Permite utilizatorilor și administratorilor să șteargă directoare de repo preexistente care încă nu au fost adoptate în baza de date.",
"install.release_max_files": "Limita atașamentelor la lansare",
"install.release_max_files_helper": "Numărul maxim de fișiere atașate permis pentru fiecare lansare.",
"install.release_file_max_size": "Dimensiunea fișierului atașat la lansare (KiB)",
@@ -1091,7 +1095,7 @@
"settings.orgs_none": "Nu ești membru al niciunei organizații.",
"settings.repos_none": "Nu deții niciun proiect.",
"settings.delete_account": "Șterge-ți contul",
"settings.delete_prompt": "Această operațiune va șterge definitiv contul tău de utilizator. Se anulează <strong>CANNOT</strong>.",
"settings.delete_prompt": "Această operațiune va șterge definitiv contul tău de utilizator. Datele <strong>NU POT</strong> fi restaurate.",
"settings.delete_with_all_comments": "Contul tău este mai tânăr decât %s. Pentru a evita comentariile fantomă, toate comentariile despre probleme/PR vor fi șterse împreună cu acesta.",
"settings.confirm_delete_account": "Confirmă ştergerea",
"settings.delete_account_title": "Șterge contul de utilizator",
@@ -1104,7 +1108,7 @@
"settings.email_notifications.new_account_requests": "Notificări de solicitare a unui cont nou",
"settings.email_notifications.new_account_requests.desc": "Trimite-mi un e-mail când un nou cont de utilizator așteaptă aprobarea administratorului.",
"settings.email_notifications.new_account_requests.last_admin": "Cel puțin un administrator trebuie să mențină activate notificările de solicitare a unui cont nou.",
"settings.email_notifications.actions.desc": "Notificările pentru fluxul de lucru rulează pe proiectele configurate cu <a target=\"_blank\" href=\"%s\">Gitea Acțiuni</a>.",
"settings.email_notifications.actions.desc": "Notificările pentru fluxul de lucru rulează pe proiectele configurate cu <a target=\"_blank\" href=\"%s\">Acțiuni Gitea</a>.",
"settings.email_notifications.actions.failure_only": "Notifică numai pentru rulările eșuate ale fluxului de lucru",
"settings.visibility": "Vizibilitatea utilizatorului",
"settings.visibility.public": "Public",
@@ -1283,6 +1287,10 @@
"repo.migrate.migrating_failed": "Migrarea de la <b>%s</b> a eșuat.",
"repo.migrate.migrating_failed.error": "Migrare eșuată: %s",
"repo.migrate.migrating_failed_no_addr": "Migrarea a eșuat.",
"repo.migrate.migrating_canceling": "Se oprește migrarea și se închid procesele Git de clonare...",
"repo.migrate.migrating_stopped": "Migrarea de la <b>%s</b> a fost oprită.",
"repo.migrate.migrating_stopped.error": "Migrarea a fost oprită.",
"repo.migrate.migrating_stopped_no_addr": "Migrarea a fost oprită.",
"repo.migrate.github.description": "Migrează datele de pe github.com sau alte instanțe GitHub.",
"repo.migrate.git.description": "Migrează un repozitoriu de pe orice serviciu de tip Git.",
"repo.migrate.gitlab.description": "Migrează datele de pe gitlab.com sau alte instanțe GitLab.",
@@ -1296,7 +1304,7 @@
"repo.migrate.codecommit.aws_secret_access_key": "Cheie de acces secretă AWS",
"repo.migrate.codecommit.https_git_credentials_username": "Nume de utilizator HTTPS Git",
"repo.migrate.codecommit.https_git_credentials_password": "Parola de acreditări Git HTTPS",
"repo.migrate.migrating_git": "Migrare datelor Git",
"repo.migrate.migrating_git": "Migrare date Git",
"repo.migrate.migrating_topics": "Migrare subiecte",
"repo.migrate.migrating_milestones": "Migrare repere",
"repo.migrate.migrating_labels": "Migrare etichete",
@@ -2654,7 +2662,7 @@
"repo.settings.visibility.success": "Vizibilitatea repozitoriului a fost schimbată.",
"repo.settings.visibility.error": "A apărut o eroare la încercarea de a modifica vizibilitatea rezitoriului.",
"repo.settings.visibility.fork_error": "Nu se poate modifica vizibilitatea unui repozitoriu bifurcat.",
"repo.settings.archive.button": "Arhivă Repozitoriu",
"repo.settings.archive.button": "Arhivează Repozitoriu",
"repo.settings.archive.header": "Arhivează acest Repozitoriu",
"repo.settings.archive.text": "Prin arhivare, repozitoriul nu va mai putea fi modificat. Acesta nu va mai fi vizibil in tabloul de bord. Nimeni (nici măcar tu!) nu va putea să facă noi commit-uri, să deschidă probleme sau sa facă noi cereri de poll.",
"repo.settings.archive.success": "Repozitoriul a fost arhivat cu succes.",
@@ -3044,13 +3052,13 @@
"admin.badges.slug_been_taken": "Identificator ecuson este deja luat.",
"admin.badges.description": "Descriere",
"admin.badges.image_url": "Adresa URL a imaginii",
"admin.badges.new_success": "Ecusonul „%s” a fost creată.",
"admin.badges.new_success": "Ecusonul „%s” a fost creat.",
"admin.badges.update_success": "Ecusonul a fost actualizat.",
"admin.badges.deletion_success": "Ecusonul a fost ștears.",
"admin.badges.edit_badge": "Modifică ecusonul",
"admin.badges.update_badge": "Actualizează ecusonul",
"admin.badges.delete_badge": "Șterge ecusonul",
"admin.badges.delete_badge_desc": "Sigur dorești să ștergi definitiv aceast ecuson?",
"admin.badges.delete_badge_desc": "Sigur dorești să ștergi definitiv acest ecuson?",
"admin.badges.users_with_badge": "Utilizatori cu ecusoane: %s",
"admin.badges.not_found": "Ecusonul nu a fost găsit.",
"admin.badges.user_already_has": "Utilizatorul are deja aceast ecuson.",
+34 -11
View File
@@ -367,6 +367,8 @@ func newInstallFormFromSettings() (forms.InstallForm, string) {
form.AdminManagementPolicy = setting.Admin.AdminManagementPolicy
form.ReleaseMaxFiles = setting.Repository.Release.MaxFiles
form.ReleaseFileMaxSize = setting.Repository.Release.FileMaxSize
form.AllowAdoptionOfUnadoptedRepositories = true // edit/add - by petru @ codex
form.AllowDeleteOfUnadoptedRepositories = true // edit/add - by petru @ codex
normalizeInstallRegistrationOptions(&form)
return form, curDBType
@@ -446,6 +448,8 @@ func populateInstallFormFromConfig(form *forms.InstallForm, cfg setting.ConfigPr
form.DefaultLanguage = importedFirstLang(setting.ConfigSectionKeyString(i18nSec, "LANGS"), form.DefaultLanguage)
form.RepoRootPath = setting.ConfigSectionKeyString(repoSec, "ROOT", form.RepoRootPath)
form.AllowAdoptionOfUnadoptedRepositories = setting.ConfigSectionKeyBool(repoSec, "ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES", form.AllowAdoptionOfUnadoptedRepositories) // edit/add - by petru @ codex
form.AllowDeleteOfUnadoptedRepositories = setting.ConfigSectionKeyBool(repoSec, "ALLOW_DELETE_OF_UNADOPTED_REPOSITORIES", form.AllowDeleteOfUnadoptedRepositories) // edit/add - by petru @ codex
form.LFSRootPath = setting.ConfigSectionKeyString(lfsSec, "PATH", form.LFSRootPath)
form.Domain = setting.ConfigSectionKeyString(serverSec, "DOMAIN", setting.ConfigSectionKeyString(serverSec, "SSH_DOMAIN", form.Domain))
form.SSHPort = importedInt(serverSec, "SSH_PORT", form.SSHPort)
@@ -647,7 +651,8 @@ func ImportAppINI(ctx *context.Context) {
}
form, curDBType := newInstallFormFromSettings()
form.ImportSensitiveSecrets = ctx.FormBool("import_sensitive_secrets")
form.ImportSensitiveSecrets = true // edit/add - by petru @ codex
form.ImportedAppINI = true // edit/add - by petru @ codex
cfg, err := readImportedInstallConfig(ctx)
if err != nil {
ctx.Data["CurDbType"] = curDBType
@@ -727,6 +732,16 @@ func populateInstallSMTPFromFields(form *forms.InstallForm) {
}
}
// start edit/add - by petru @ codex
func applyImportedAppINIRepositoryRecoveryDefaults(form *forms.InstallForm, dbPreviouslyUsed bool) {
if form.ImportedAppINI && !dbPreviouslyUsed {
form.AllowAdoptionOfUnadoptedRepositories = true
form.AllowDeleteOfUnadoptedRepositories = true
}
}
// end edit/add - by petru @ codex
// TestMail checks the mail settings entered on the install page.
func TestMail(ctx *context.Context) {
email := strings.TrimSpace(ctx.FormString("test_mail_email"))
@@ -830,14 +845,14 @@ func inferInstallMailProtocol(smtpAddr, smtpPort string) string {
}
}
func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
func checkDatabase(ctx *context.Context, form *forms.InstallForm) (bool, bool) {
var err error
if (setting.Database.Type == "sqlite3") &&
len(setting.Database.Path) == 0 {
ctx.Data["Err_DbPath"] = true
ctx.RenderWithErrDeprecated(ctx.Tr("install.err_empty_db_path"), tplInstall, form)
return false
return false, false
}
// Check if the user is trying to re-install in an installed database
@@ -852,46 +867,48 @@ func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
ctx.Data["Err_DbSetting"] = true
ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_db_setting", err), tplInstall, form)
}
return false
return false, false
}
err = db_install.CheckDatabaseConnection(ctx)
if err != nil {
ctx.Data["Err_DbSetting"] = true
ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_db_setting", err), tplInstall, form)
return false
return false, false
}
hasPostInstallationUser, err := db_install.HasPostInstallationUsers(ctx)
if err != nil {
ctx.Data["Err_DbSetting"] = true
ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_db_table", "user", err), tplInstall, form)
return false
return false, false
}
dbMigrationVersion, err := db_install.GetMigrationVersion(ctx)
if err != nil {
ctx.Data["Err_DbSetting"] = true
ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_db_table", "version", err), tplInstall, form)
return false
return false, false
}
dbPreviouslyUsed := hasPostInstallationUser || dbMigrationVersion > 0 // edit/add - by petru @ codex
if hasPostInstallationUser && dbMigrationVersion > 0 {
log.Error("The database is likely to have been used by Gitea before, database migration version=%d", dbMigrationVersion)
confirmed := form.ReinstallConfirmFirst && form.ReinstallConfirmSecond && form.ReinstallConfirmThird
if !confirmed {
ctx.Data["Err_DbInstalledBefore"] = true
ctx.RenderWithErrDeprecated(ctx.Tr("install.reinstall_error"), tplInstall, form)
return false
return false, dbPreviouslyUsed
}
log.Info("User confirmed re-installation of Gitea into a pre-existing database")
}
if hasPostInstallationUser || dbMigrationVersion > 0 {
if dbPreviouslyUsed {
log.Info("Gitea will be installed in a database with: hasPostInstallationUser=%v, dbMigrationVersion=%v", hasPostInstallationUser, dbMigrationVersion)
}
return true
return true, dbPreviouslyUsed
}
// SubmitInstall response for submit install items
@@ -905,6 +922,7 @@ func SubmitInstall(ctx *context.Context) {
form := *web.GetForm(ctx).(*forms.InstallForm)
form.ImportSensitiveSecrets = ctx.FormBool("import_sensitive_secrets")
form.ImportedAppINI = ctx.FormBool("imported_app_ini") // edit/add - by petru @ codex
form.ImportedLFSJWTSecret = ctx.FormString("imported_lfs_jwt_secret")
form.ImportedInternalToken = ctx.FormString("imported_internal_token")
form.ImportedOAuth2JWTSecret = ctx.FormString("imported_o_auth2_jwt_secret")
@@ -924,6 +942,7 @@ func SubmitInstall(ctx *context.Context) {
form.DefaultLanguage = strings.TrimSpace(form.DefaultLanguage)
normalizeInstallRegistrationOptions(&form)
populateInstallSMTPFromFields(&form)
ctx.Data["InstallerSiteName"] = installMailerDisplayName(form.AppName) // edit/add - by petru @ codex
if form.DefaultLanguage == "" {
form.DefaultLanguage = resolveInstallDefaultLanguage("")
@@ -961,7 +980,8 @@ func SubmitInstall(ctx *context.Context) {
setting.Database.Path = form.DbPath
setting.Database.LogSQL = !setting.IsProd
if !checkDatabase(ctx, &form) {
dbOK, dbPreviouslyUsed := checkDatabase(ctx, &form)
if !dbOK {
return
}
@@ -1080,6 +1100,9 @@ func SubmitInstall(ctx *context.Context) {
cfg.Section("database").Key("LOG_SQL").SetValue("false") // LOG_SQL is rarely helpful
cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)
applyImportedAppINIRepositoryRecoveryDefaults(&form, dbPreviouslyUsed) // edit/add - by petru @ codex
cfg.Section("repository").Key("ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES").SetValue(strconv.FormatBool(form.AllowAdoptionOfUnadoptedRepositories)) // edit/add - by petru @ codex
cfg.Section("repository").Key("ALLOW_DELETE_OF_UNADOPTED_REPOSITORIES").SetValue(strconv.FormatBool(form.AllowDeleteOfUnadoptedRepositories)) // edit/add - by petru @ codex
cfg.Section("repository.release").Key("MAX_FILES").SetValue(strconv.FormatInt(form.ReleaseMaxFiles, 10))
cfg.Section("repository.release").Key("FILE_MAX_SIZE").SetValue(strconv.FormatInt(form.ReleaseFileMaxSize, 10))
cfg.Section("server").Key("SSH_DOMAIN").SetValue(form.Domain)
+66
View File
@@ -87,6 +87,8 @@ SSL_MODE = require
[repository]
ROOT = /srv/gitea/repos
ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES = false
ALLOW_DELETE_OF_UNADOPTED_REPOSITORIES = true
[server]
DOMAIN = gitea.example.com
@@ -157,6 +159,8 @@ LANGS = de-DE,en-US
assert.Equal(t, "custom", form.DbSchema)
assert.Equal(t, "require", form.SSLMode)
assert.Equal(t, "/srv/gitea/repos", form.RepoRootPath)
assert.False(t, form.AllowAdoptionOfUnadoptedRepositories)
assert.True(t, form.AllowDeleteOfUnadoptedRepositories)
assert.Equal(t, "/srv/gitea/lfs", form.LFSRootPath)
assert.Equal(t, "gitea.example.com", form.Domain)
assert.Equal(t, 2222, form.SSHPort)
@@ -191,6 +195,31 @@ LANGS = de-DE,en-US
assert.EqualValues(t, 2048, form.ReleaseFileMaxSize)
}
// start edit/add - by petru @ codex
func TestApplyImportedAppINIRepositoryRecoveryDefaults(t *testing.T) {
form := forms.InstallForm{
ImportedAppINI: true,
AllowAdoptionOfUnadoptedRepositories: false,
AllowDeleteOfUnadoptedRepositories: false,
}
applyImportedAppINIRepositoryRecoveryDefaults(&form, false)
assert.True(t, form.AllowAdoptionOfUnadoptedRepositories)
assert.True(t, form.AllowDeleteOfUnadoptedRepositories)
form = forms.InstallForm{
ImportedAppINI: true,
AllowAdoptionOfUnadoptedRepositories: false,
AllowDeleteOfUnadoptedRepositories: false,
}
applyImportedAppINIRepositoryRecoveryDefaults(&form, true)
assert.False(t, form.AllowAdoptionOfUnadoptedRepositories)
assert.False(t, form.AllowDeleteOfUnadoptedRepositories)
}
// end edit/add - by petru @ codex
func TestPopulateInstallFormFromConfigReplacesSMTPFromSplitFields(t *testing.T) {
cfg, err := setting.NewConfigProviderFromData(`
APP_NAME = gitSafe: for your code
@@ -332,6 +361,43 @@ JWT_SECRET = oauth-secret
assert.Contains(t, w.Body.String(), `name="imported_o_auth2_jwt_secret" value="oauth-secret"`)
}
// start edit/add - by petru @ codex
func TestImportAppINIDefaultsSensitiveSecretsToEnabled(t *testing.T) {
defer test.MockVariableValue(&setting.InstallLock, false)()
var body bytes.Buffer
writer := multipart.NewWriter(&body)
fileWriter, err := writer.CreateFormFile("app_ini_file", "app.ini")
require.NoError(t, err)
_, err = fileWriter.Write([]byte(`
[server]
LFS_JWT_SECRET = lfs-secret
[security]
INTERNAL_TOKEN = internal-secret
[oauth2]
JWT_SECRET = oauth-secret
`))
require.NoError(t, err)
require.NoError(t, writer.Close())
r := Routes()
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/import_app_ini", &body)
req.Header.Set("Content-Type", writer.FormDataContentType())
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), `id="import_sensitive_secrets" name="import_sensitive_secrets" type="checkbox" checked`)
assert.Contains(t, w.Body.String(), `name="imported_lfs_jwt_secret" value="lfs-secret"`)
assert.Contains(t, w.Body.String(), `name="imported_internal_token" value="internal-secret"`)
assert.Contains(t, w.Body.String(), `name="imported_o_auth2_jwt_secret" value="oauth-secret"`)
}
// end edit/add - by petru @ codex
func TestApplyInstallSensitiveSecretsToConfigPersistsImportedValues(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "app.ini")
+1
View File
@@ -22,6 +22,7 @@ const (
func Organizations(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("admin.organizations")
ctx.Data["PageIsAdminOrganizations"] = true
ctx.Data["CurrentRequestURI"] = ctx.Req.RequestURI // edit/add - by petru @ codex
if ctx.FormString("sort") == "" {
ctx.SetFormString("sort", UserSearchDefaultAdminSort)
+1 -1
View File
@@ -144,7 +144,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
} else if action == "adopt" {
if _, err := repo_service.AdoptRepository(ctx, ctx.Doer, ctxUser, repo_service.CreateRepoOptions{
Name: dirSplit[1],
IsPrivate: true,
IsPrivate: ctx.FormBool("private"), // edit/add - by petru @ codex
}); err != nil {
ctx.ServerError("repository.AdoptRepository", err)
return
+19 -1
View File
@@ -14,6 +14,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
repo_module "code.gitea.io/gitea/modules/repository"
@@ -39,6 +40,15 @@ const (
tplSettingsLabels templates.TplName = "org/settings/labels"
)
// start edit/add - by petru @ codex
func setOrgSettingsRedirectTo(ctx *context.Context) {
if redirectTo := ctx.FormString("redirect_to"); redirectTo != "" && httplib.IsRelativeURL(redirectTo) {
ctx.Data["RedirectTo"] = redirectTo
}
}
// end edit/add - by petru @ codex
// Settings render the main settings page
func Settings(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("org.settings")
@@ -47,6 +57,7 @@ func Settings(ctx *context.Context) {
ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility
ctx.Data["RepoAdminChangeTeamAccess"] = ctx.Org.Organization.RepoAdminChangeTeamAccess
ctx.Data["ContextUser"] = ctx.ContextUser
setOrgSettingsRedirectTo(ctx) // edit/add - by petru @ codex
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
@@ -63,6 +74,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsOptions"] = true
ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility
setOrgSettingsRedirectTo(ctx) // edit/add - by petru @ codex
if ctx.HasError() {
ctx.HTML(http.StatusOK, tplSettingsOptions)
@@ -143,7 +155,13 @@ func SettingsDeleteOrgPost(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("org.settings.delete_successful", ctx.Org.Organization.Name))
ctx.JSONRedirect(setting.AppSubURL + "/")
// start edit/add - by petru @ codex
redirectTo := setting.AppSubURL + "/"
if formRedirectTo := ctx.FormString("redirect_to"); formRedirectTo != "" && httplib.IsRelativeURL(formRedirectTo) {
redirectTo = formRedirectTo
}
ctx.JSONRedirect(redirectTo)
// end edit/add - by petru @ codex
}
// Webhooks render webhook list page
+196
View File
@@ -0,0 +1,196 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package org
import (
"net/http"
"os"
"path/filepath"
"strings"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
shared_user "code.gitea.io/gitea/routers/web/shared/user"
"code.gitea.io/gitea/services/context"
repo_service "code.gitea.io/gitea/services/repository"
)
const tplSettingsRepos templates.TplName = "org/settings/repos" // edit/add - by petru @ codex
// start edit/add - by petru @ codex
func Repos(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings.repos")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsRepos"] = true
ctx.Data["ContextUser"] = ctx.ContextUser // edit/add - by petru @ codex
ctx.Data["allowAdopt"] = ctx.IsUserSiteAdmin() || setting.Repository.AllowAdoptionOfUnadoptedRepositories
ctx.Data["allowDelete"] = ctx.IsUserSiteAdmin() || setting.Repository.AllowDeleteOfUnadoptedRepositories
opts := db.ListOptions{
PageSize: setting.UI.Admin.UserPagingNum,
Page: ctx.FormInt("page"),
}
if opts.Page <= 0 {
opts.Page = 1
}
start := int64((opts.Page - 1) * opts.PageSize)
end := start + int64(opts.PageSize)
adoptOrDelete := ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories)
orgUser := ctx.Org.Organization.AsUser()
var count int64
if adoptOrDelete {
repoNames := make([]string, 0, setting.UI.Admin.UserPagingNum)
reposMap := map[string]*repo_model.Repository{}
root := user_model.UserPath(orgUser.Name)
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
if !d.IsDir() || path == root {
return nil
}
name := d.Name()
if !strings.HasSuffix(name, ".git") {
return filepath.SkipDir
}
name = name[:len(name)-4]
if repo_model.IsUsableRepoName(name) != nil || strings.ToLower(name) != name {
return filepath.SkipDir
}
if count >= start && count < end {
repoNames = append(repoNames, name)
}
count++
return filepath.SkipDir
}); err != nil {
ctx.ServerError("filepath.WalkDir", err)
return
}
orgRepos, _, err := repo_model.SearchRepository(ctx, repo_model.SearchRepoOptions{
Actor: ctx.Doer,
OwnerID: orgUser.ID,
Private: true,
ListOptions: db.ListOptions{
Page: 1,
PageSize: setting.UI.Admin.UserPagingNum,
},
LowerNames: repoNames,
}) // edit/add - by petru @ codex
if err != nil {
ctx.ServerError("SearchRepository", err)
return
}
for _, repo := range orgRepos {
if repo.IsFork {
if err := repo.GetBaseRepo(ctx); err != nil {
ctx.ServerError("GetBaseRepo", err)
return
}
}
reposMap[repo.LowerName] = repo
}
repos := make(repo_model.RepositoryList, 0, len(orgRepos)) // edit/add - by petru @ codex
unadoptedDirs := make([]string, 0, len(repoNames)) // edit/add - by petru @ codex
for _, repoName := range repoNames { // edit/add - by petru @ codex
if repo, ok := reposMap[repoName]; ok {
repos = append(repos, repo)
} else {
unadoptedDirs = append(unadoptedDirs, repoName)
}
}
ctx.Data["Repos"] = repos
ctx.Data["Dirs"] = unadoptedDirs
} else {
repos, reposCount, err := repo_model.SearchRepository(ctx, repo_model.SearchRepoOptions{
Actor: ctx.Doer,
OwnerID: orgUser.ID,
Private: true,
ListOptions: opts,
}) // edit/add - by petru @ codex
if err != nil {
ctx.ServerError("SearchRepository", err)
return
}
count = reposCount
for i := range repos {
if repos[i].IsFork {
if err := repos[i].GetBaseRepo(ctx); err != nil {
ctx.ServerError("GetBaseRepo", err)
return
}
}
}
ctx.Data["Repos"] = repos
}
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
return
}
pager := context.NewPagination(count, opts.PageSize, opts.Page, 5)
pager.AddParamFromRequest(ctx.Req)
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, tplSettingsRepos)
}
func AdoptOrDeleteRepository(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings.adopt")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsRepos"] = true
allowAdopt := ctx.IsUserSiteAdmin() || setting.Repository.AllowAdoptionOfUnadoptedRepositories
ctx.Data["allowAdopt"] = allowAdopt
allowDelete := ctx.IsUserSiteAdmin() || setting.Repository.AllowDeleteOfUnadoptedRepositories
ctx.Data["allowDelete"] = allowDelete
dir := ctx.FormString("id")
action := ctx.FormString("action")
orgUser := ctx.Org.Organization.AsUser()
has, err := repo_model.IsRepositoryModelExist(ctx, orgUser, dir)
if err != nil {
ctx.ServerError("IsRepositoryExist", err)
return
}
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(orgUser.Name, dir)))
if err != nil {
ctx.ServerError("IsDir", err)
return
}
if has || !exist {
// Fallthrough to failure mode
} else if action == "adopt" && allowAdopt {
if _, err := repo_service.AdoptRepository(ctx, ctx.Doer, orgUser, repo_service.CreateRepoOptions{
Name: dir,
IsPrivate: ctx.FormBool("private"), // edit/add - by petru @ codex
}); err != nil {
ctx.ServerError("repository.AdoptRepository", err)
return
}
ctx.Flash.Success(ctx.Tr("repo.adopt_preexisting_success", dir))
} else if action == "delete" && allowDelete {
if err := repo_service.DeleteUnadoptedRepository(ctx, ctx.Doer, orgUser, dir); err != nil {
ctx.ServerError("repository.AdoptRepository", err)
return
}
ctx.Flash.Success(ctx.Tr("repo.delete_preexisting_success", dir))
}
ctx.Redirect(ctx.Org.OrgLink + "/settings/repos")
}
// end edit/add - by petru @ codex
+18 -5
View File
@@ -281,13 +281,15 @@ func MigrateCancelPost(ctx *context.Context) {
ctx.Redirect(ctx.Repo.Repository.Link())
return
}
if migratingTask.Status == structs.TaskStatusRunning {
taskUpdate := &admin_model.Task{ID: migratingTask.ID, Status: structs.TaskStatusFailed, Message: "canceled"}
// start edit/add - by petru @ codex
if migratingTask.Status == structs.TaskStatusQueued || migratingTask.Status == structs.TaskStatusRunning {
taskUpdate := &admin_model.Task{ID: migratingTask.ID, Status: structs.TaskStatusStopped, Message: "canceling"}
if err = taskUpdate.UpdateCols(ctx, "status", "message"); err != nil {
ctx.ServerError("task.UpdateCols", err)
return
}
}
// end edit/add - by petru @ codex
ctx.Redirect(ctx.Repo.Repository.Link())
}
@@ -310,7 +312,15 @@ func MigrateStatus(ctx *context.Context) {
message := task.Message
if task.Message != "" && task.Message[0] == '{' {
// start edit/add - by petru @ codex
stopping := task.Status == structs.TaskStatusStopped && task.EndTime == 0
stopped := task.Status == structs.TaskStatusStopped && task.EndTime != 0
if stopping {
message = ctx.Locale.TrString("repo.migrate.migrating_canceling")
} else if stopped {
message = ctx.Locale.TrString("repo.migrate.migrating_stopped.error")
} else if task.Message != "" && task.Message[0] == '{' {
// assume message is actually a translatable string
var translatableMessage admin_model.TranslatableMessage
if err := json.Unmarshal([]byte(message), &translatableMessage); err != nil {
@@ -321,9 +331,12 @@ func MigrateStatus(ctx *context.Context) {
}
message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
}
// end edit/add - by petru @ codex
ctx.JSON(http.StatusOK, map[string]any{
"status": task.Status,
"message": message,
"status": task.Status,
"message": message,
"stopping": stopping, // edit/add - by petru @ codex
"stopped": stopped, // edit/add - by petru @ codex
})
}
+2 -1
View File
@@ -198,7 +198,8 @@ func checkHomeCodeViewable(ctx *context.Context) {
ctx.Data["Repo"] = ctx.Repo
ctx.Data["MigrateTask"] = task
ctx.Data["CloneAddr"], _ = util.SanitizeURL(cfg.CloneAddr)
ctx.Data["Failed"] = task.Status == structs.TaskStatusFailed
ctx.Data["Stopping"] = task.Status == structs.TaskStatusStopped && task.EndTime == 0 // edit/add - by petru @ codex
ctx.Data["Failed"] = task.Status == structs.TaskStatusFailed || (task.Status == structs.TaskStatusStopped && task.EndTime != 0) // edit/add - by petru @ codex
ctx.HTML(http.StatusOK, tplMigrating)
return
}
+1 -1
View File
@@ -42,7 +42,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
} else if action == "adopt" && allowAdopt {
if _, err := repo_service.AdoptRepository(ctx, ctxUser, ctxUser, repo_service.CreateRepoOptions{
Name: dir,
IsPrivate: true,
IsPrivate: ctx.FormBool("private"), // edit/add - by petru @ codex
}); err != nil {
ctx.ServerError("repository.AdoptRepository", err)
return
+13 -4
View File
@@ -253,7 +253,7 @@ func Repos(ctx *context.Context) {
if adoptOrDelete {
repoNames := make([]string, 0, setting.UI.Admin.UserPagingNum)
repos := map[string]*repo_model.Repository{}
reposMap := map[string]*repo_model.Repository{}
// We're going to iterate by pagesize.
root := user_model.UserPath(ctxUser.Name)
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
@@ -304,10 +304,19 @@ func Repos(ctx *context.Context) {
return
}
}
repos[repo.LowerName] = repo
reposMap[repo.LowerName] = repo
}
ctx.Data["Dirs"] = repoNames
ctx.Data["ReposMap"] = repos
repos := make(repo_model.RepositoryList, 0, len(userRepos)) // edit/add - by petru @ codex
unadoptedDirs := make([]string, 0, len(repoNames)) // edit/add - by petru @ codex
for _, repoName := range repoNames { // edit/add - by petru @ codex
if repo, ok := reposMap[repoName]; ok {
repos = append(repos, repo)
} else {
unadoptedDirs = append(unadoptedDirs, repoName)
}
}
ctx.Data["Repos"] = repos
ctx.Data["Dirs"] = unadoptedDirs
} else {
repos, reposCount, err := repo_model.GetUserRepositories(ctx, repo_model.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: opts})
if err != nil {
+4
View File
@@ -1070,6 +1070,10 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {
m.Get("", org.BlockedUsers)
m.Post("", web.Bind(forms.BlockUserForm{}), org.BlockedUsersPost)
})
m.Group("/repos", func() {
m.Get("", org.Repos) // edit/add - by petru @ codex
m.Post("/unadopted", org.AdoptOrDeleteRepository) // edit/add - by petru @ codex
})
}, ctxDataSet("EnableOAuth2", setting.OAuth2.Enabled, "EnablePackages", setting.Packages.Enabled, "PageIsOrgSettings", true))
}, context.OrgAssignment(context.OrgAssignmentOptions{RequireOwner: true}))
}, reqSignIn)
+7 -4
View File
@@ -46,6 +46,7 @@ type InstallForm struct {
SMTPUser string `binding:"OmitEmpty;MaxSize(254)" locale:"install.mailer_user"`
SMTPPasswd string
ImportSensitiveSecrets bool `form:"import_sensitive_secrets"`
ImportedAppINI bool `form:"imported_app_ini"`
ImportedLFSJWTSecret string `form:"imported_lfs_jwt_secret"`
ImportedInternalToken string `form:"imported_internal_token"`
ImportedOAuth2JWTSecret string `form:"imported_o_auth2_jwt_secret"`
@@ -69,10 +70,12 @@ type InstallForm struct {
EnableUpdateChecker bool
NoReplyAddress string
PasswordAlgorithm string
AdminManagementPolicy string `binding:"In(,super_admin_only,grantor_only,grantor_inheritance)" locale:"install.admin_management_policy"`
ReleaseMaxFiles int64
ReleaseFileMaxSize int64
PasswordAlgorithm string
AdminManagementPolicy string `binding:"In(,super_admin_only,grantor_only,grantor_inheritance)" locale:"install.admin_management_policy"`
ReleaseMaxFiles int64
ReleaseFileMaxSize int64
AllowAdoptionOfUnadoptedRepositories bool // edit/add - by petru @ codex
AllowDeleteOfUnadoptedRepositories bool // edit/add - by petru @ codex
AdminName string `binding:"OmitEmpty;Username;MaxSize(30)" locale:"install.admin_name"`
AdminPasswd string `binding:"OmitEmpty;MaxSize(255)" locale:"install.admin_password"`
+10 -8
View File
@@ -45,10 +45,11 @@ func cloneWiki(ctx context.Context, repo *repo_model.Repository, opts migration.
}
}
if err := gitrepo.CloneExternalRepo(ctx, wikiRemoteURL, storageRepo, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
KillProcessTreeOnCancel: true, // edit/add - by petru @ codex
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
}); err != nil {
log.Error("Clone wiki failed, err: %v", err)
cleanIncompleteWikiPath()
@@ -91,10 +92,11 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
}
if err := gitrepo.CloneExternalRepo(ctx, opts.CloneAddr, repo, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
KillProcessTreeOnCancel: true, // edit/add - by petru @ codex
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
}); err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return repo, fmt.Errorf("clone timed out, consider increasing [git.timeout] MIGRATE in app.ini, underlying err: %w", err)
+21 -2
View File
@@ -41,6 +41,18 @@ func handleCreateError(owner *user_model.User, err error) error {
}
}
// start edit/add - by petru @ codex
func isMigrationCancelRequested(ctx context.Context, t *admin_model.Task) bool {
if t.Status == structs.TaskStatusStopped && t.Message == "canceling" {
return true
}
currentTask, loadErr := admin_model.GetMigratingTask(ctx, t.RepoID)
return loadErr == nil && currentTask.ID == t.ID && currentTask.Status == structs.TaskStatusStopped && currentTask.Message == "canceling"
}
// end edit/add - by petru @ codex
func runMigrateTask(ctx context.Context, t *admin_model.Task) (err error) {
defer func(ctx context.Context) {
if e := recover(); e != nil {
@@ -59,9 +71,16 @@ func runMigrateTask(ctx context.Context, t *admin_model.Task) (err error) {
log.Error("runMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d] failed: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, err)
// start edit/add - by petru @ codex
t.EndTime = timeutil.TimeStampNow()
t.Status = structs.TaskStatusFailed
t.Message = err.Error()
if isMigrationCancelRequested(ctx, t) {
t.Status = structs.TaskStatusStopped
t.Message = "canceled"
} else {
t.Status = structs.TaskStatusFailed
t.Message = err.Error()
}
// end edit/add - by petru @ codex
if err := t.UpdateCols(ctx, "status", "message", "end_time"); err != nil {
log.Error("Task UpdateCols failed: %v", err)
}
+4 -1
View File
@@ -136,9 +136,12 @@ func RetryMigrateTask(ctx context.Context, repoID int64) error {
log.Error("GetMigratingTask: %v", err)
return err
}
if migratingTask.Status == structs.TaskStatusQueued || migratingTask.Status == structs.TaskStatusRunning {
// start edit/add - by petru @ codex
if migratingTask.Status == structs.TaskStatusQueued || migratingTask.Status == structs.TaskStatusRunning ||
(migratingTask.Status == structs.TaskStatusStopped && migratingTask.EndTime == 0) {
return nil
}
// end edit/add - by petru @ codex
// TODO Need to removing the storage/database garbage brought by the failed task
+21
View File
@@ -51,10 +51,16 @@
</td>
<td class="gt-ellipsis tw-max-w-48">{{.Description}}</td>
<td>
{{/* start edit/add - by petru @ codex */}}
<div class="tw-flex tw-gap-2">
<a href="{{$.Link}}/slug/{{.Slug | PathEscape}}" data-tooltip-content="{{ctx.Locale.Tr "admin.badges.details"}}">{{svg "octicon-star"}}</a>
<a href="{{$.Link}}/slug/{{.Slug | PathEscape}}/edit" data-tooltip-content="{{ctx.Locale.Tr "edit"}}">{{svg "octicon-pencil"}}</a>
<a class="tw-text-red show-modal" href data-modal="#admin-badge-delete-modal"
data-modal-form.action="{{$.Link}}/slug/{{.Slug | PathEscape}}/delete"
data-tooltip-content="{{ctx.Locale.Tr "admin.badges.delete_badge"}}"
>{{svg "octicon-trash"}}</a> <!-- edit/add - by petru @ codex -->
</div>
{{/* end edit/add - by petru @ codex */}}
</td>
</tr>
{{end}}
@@ -64,4 +70,19 @@
{{template "base/paginate" .}}
</div>
{{/* start edit/add - by petru @ codex */}}
<div class="ui g-modal-confirm modal" id="admin-badge-delete-modal">
<div class="header">
{{svg "octicon-trash"}}
{{ctx.Locale.Tr "admin.badges.delete_badge"}}
</div>
<form class="ui form" method="post">
<div class="content">
<p>{{ctx.Locale.Tr "admin.badges.delete_badge_desc"}}</p>
</div>
{{template "base/modal_actions_confirm" .}}
</form>
</div> <!-- edit/add - by petru @ codex -->
{{/* end edit/add - by petru @ codex */}}
{{template "admin/layout_footer" .}}
+48 -1
View File
@@ -77,7 +77,18 @@
<td>{{.NumMembers}}</td>
<td>{{.NumRepos}}</td>
<td>{{DateUtils.AbsoluteShort .CreatedUnix}}</td>
<td><a href="{{.OrganisationLink}}/settings" data-tooltip-content="{{ctx.Locale.Tr "edit"}}">{{svg "octicon-pencil"}}</a></td>
<td>
{{/* start edit/add - by petru @ codex */}}
<div class="tw-flex tw-gap-2">
<a href="{{.OrganisationLink}}/settings?redirect_to={{$.CurrentRequestURI | QueryEscape}}" data-tooltip-content="{{ctx.Locale.Tr "edit"}}">{{svg "octicon-pencil"}}</a> <!-- edit/add - by petru @ codex -->
<a class="tw-text-red show-modal" href data-modal="#admin-org-delete-modal"
data-modal-form.action="{{.OrganisationLink}}/settings/delete"
data-modal-org-name="{{.Name}}" data-modal-org-name-notice-2="{{.Name}}" data-modal-org-name-notice-3="{{.Name}}" data-modal-org-name-notice-4="{{.Name}}" data-modal-confirm-org-name.value=""
data-tooltip-content="{{ctx.Locale.Tr "org.settings.delete_account"}}"
>{{svg "octicon-trash"}}</a> <!-- edit/add - by petru @ codex -->
</div>
{{/* end edit/add - by petru @ codex */}}
</td>
</tr>
{{else}}
<tr><td class="tw-text-center" colspan="7">{{ctx.Locale.Tr "no_results_found"}}</td></tr>
@@ -88,4 +99,40 @@
{{template "base/paginate" .}}
</div>
{{/* start edit/add - by petru @ codex */}}
<div class="ui small modal" id="admin-org-delete-modal">
<div class="header">
{{ctx.Locale.Tr "org.settings.delete_account"}}
</div>
<div class="content">
<div class="ui warning message">
<ul>
<li>{{ctx.Locale.Tr "org.settings.delete_notices_1"}}</li>
<li>{{ctx.Locale.Tr "org.settings.delete_notices_2" `<span id="org-name-notice-2"></span>`}}</li>
<li>{{ctx.Locale.Tr "org.settings.delete_notices_3" `<span id="org-name-notice-3"></span>`}}</li>
<li>{{ctx.Locale.Tr "org.settings.delete_notices_4" `<span id="org-name-notice-4"></span>`}}</li>
</ul>
</div>
<form class="ui form form-fetch-action" method="post">
<input type="hidden" name="redirect_to" value="{{AppSubUrl}}/-/admin/orgs"> <!-- edit/add - by petru @ codex -->
<div class="field">
<label>
{{ctx.Locale.Tr "org.settings.name_confirm"}}
<span class="tw-text-red" id="org-name"></span> <!-- edit/add - by petru @ codex -->
</label>
</div>
<div class="required field">
<label>{{ctx.Locale.Tr "org.org_name_holder"}}</label>
<input name="org_name" id="confirm-org-name" required> <!-- edit/add - by petru @ codex -->
</div>
<div class="actions">
<button class="ui cancel button">{{ctx.Locale.Tr "settings.cancel"}}</button>
<button class="ui red button">{{ctx.Locale.Tr "org.settings.delete_account"}}</button>
</div>
</form>
</div>
</div> <!-- edit/add - by petru @ codex -->
{{/* end edit/add - by petru @ codex */}}
{{template "admin/layout_footer" .}}
+8
View File
@@ -36,6 +36,14 @@
<input type="hidden" name="action" value="adopt">
<input type="hidden" name="q" value="{{$.Keyword}}">
<input type="hidden" name="page" value="{{$.CurrentPage}}">
{{/* start edit/add - by petru @ codex */}}
<div class="field">
<div class="ui checkbox">
<input id="adopt-private-admin-{{$dirI}}" name="private" type="checkbox">
<label for="adopt-private-admin-{{$dirI}}">{{ctx.Locale.Tr "repo.desc.private"}}</label>
</div>
</div>
{{/* end edit/add - by petru @ codex */}}
{{template "base/modal_actions_confirm"}}
</form>
</div>
+3 -1
View File
@@ -81,7 +81,8 @@
{{range .Users}}
<tr>
<td>{{.ID}}</td>
<td>
{{/* start edit/add - by petru @ codex */}}
<td class="tw-whitespace-nowrap">
<a href="{{.HomeLink}}">{{.Name}}</a>
{{if $superAdminBy := index $.UsersSuperAdminByAdmin .ID}}
{{if $superAdminBy.Name}}
@@ -107,6 +108,7 @@
<span class="ui mini label">{{ctx.Locale.Tr "admin.users.remote"}}</span>
{{end}}
</td>
{{/* end edit/add - by petru @ codex */}}
<td class="gt-ellipsis tw-max-w-48">{{.Email}}</td>
<td class="tw-whitespace-nowrap">
<span class="tw-inline-flex tw-items-center tw-gap-1 tw-whitespace-nowrap">
+89 -30
View File
@@ -6,11 +6,11 @@
{{ctx.Locale.Tr "install.title"}}
</h3>
<div class="ui attached segment">
{{template "base/alert" .}}
{{if not .Err_DbInstalledBefore}}{{template "base/alert" .}}{{end}} <!-- edit/add - by petru @ codex -->
<p>{{ctx.Locale.Tr "install.docker_helper" "https://docs.gitea.com/installation/install-with-docker"}}</p>
<form class="ui form js-install-form" action="{{AppSubUrl}}/" method="post" enctype="multipart/form-data">
<form id="install-form" class="ui form js-install-form" action="{{AppSubUrl}}/" method="post" enctype="multipart/form-data"> <!-- edit/add - by petru @ codex -->
<h4 class="ui dividing header">{{ctx.Locale.Tr "install.import_app_ini_title"}}</h4>
<p>{{ctx.Locale.Tr "install.import_app_ini_desc"}}</p>
<div class="inline field">
@@ -25,6 +25,7 @@
</div>
<span class="help">{{ctx.Locale.Tr "install.import_app_ini_sensitive_secrets_helper"}}</span>
</div>
<input type="hidden" name="imported_app_ini" value="{{if .imported_app_ini}}true{{end}}"> <!-- edit/add - by petru @ codex -->
<input type="hidden" name="imported_lfs_jwt_secret" value="{{.imported_lfs_jwt_secret}}">
<input type="hidden" name="imported_internal_token" value="{{.imported_internal_token}}">
<input type="hidden" name="imported_o_auth2_jwt_secret" value="{{.imported_o_auth2_jwt_secret}}">
@@ -96,30 +97,6 @@
</div>
</div>
{{if .Err_DbInstalledBefore}}
<div>
<p class="reinstall-message">{{ctx.Locale.Tr "install.reinstall_confirm_message"}}</p>
<div class="reinstall-confirm">
<div class="ui checkbox">
<label>{{ctx.Locale.Tr "install.reinstall_confirm_check_1"}}</label>
<input name="reinstall_confirm_first" type="checkbox">
</div>
</div>
<div class="reinstall-confirm">
<div class="ui checkbox">
<label>{{ctx.Locale.Tr "install.reinstall_confirm_check_2"}}</label>
<input name="reinstall_confirm_second" type="checkbox">
</div>
</div>
<div class="reinstall-confirm">
<div class="ui checkbox">
<label>{{ctx.Locale.Tr "install.reinstall_confirm_check_3"}}</label>
<input name="reinstall_confirm_third" type="checkbox">
</div>
</div>
</div>
{{end}}
<!-- General Settings -->
<h4 class="ui dividing header">{{ctx.Locale.Tr "install.general_title"}}</h4>
<div class="inline required field {{if .Err_AppName}}error{{end}}">
@@ -426,6 +403,22 @@
<summary class="right-content tw-py-2">
{{ctx.Locale.Tr "install.repository_options_title"}}
</summary>
{{/* start edit/add - by petru @ codex */}}
<div class="inline field">
<div class="ui checkbox">
<label for="allow_adoption_of_unadopted_repositories">{{ctx.Locale.Tr "install.allow_adoption_of_unadopted_repositories"}}</label>
<input id="allow_adoption_of_unadopted_repositories" name="allow_adoption_of_unadopted_repositories" type="checkbox" {{if .allow_adoption_of_unadopted_repositories}}checked{{end}}>
</div>
<span class="help">{{ctx.Locale.Tr "install.allow_adoption_of_unadopted_repositories_helper"}}</span>
</div>
<div class="inline field">
<div class="ui checkbox">
<label for="allow_delete_of_unadopted_repositories">{{ctx.Locale.Tr "install.allow_delete_of_unadopted_repositories"}}</label>
<input id="allow_delete_of_unadopted_repositories" name="allow_delete_of_unadopted_repositories" type="checkbox" {{if .allow_delete_of_unadopted_repositories}}checked{{end}}>
</div>
<span class="help">{{ctx.Locale.Tr "install.allow_delete_of_unadopted_repositories_helper"}}</span>
</div>
{{/* end edit/add - by petru @ codex */}}
<div class="inline field">
<label for="release_max_files">{{ctx.Locale.Tr "install.release_max_files"}}</label>
<input id="release_max_files" name="release_max_files" type="number" min="1" step="1" value="{{.release_max_files}}">
@@ -512,18 +505,58 @@
{{$filePath := HTMLFormat `<span class="ui label">%s</span> <button class="btn interact-fg" data-clipboard-text="%s">%s</button>` .CustomConfFile .CustomConfFile $copyBtn}}
{{ctx.Locale.Tr "install.config_write_file_prompt" $filePath}}
</div>
{{if not .Err_DbInstalledBefore}} <!-- edit/add - by petru @ codex -->
<div class="tw-mt-4 tw-mb-2 tw-text-center">
<button
class="ui primary button js-install-confirm-button"
data-install-label-template="{{ctx.Locale.Tr "install.install_btn_confirm" "__SITE_NAME__"}}"
>{{ctx.Locale.Tr "install.install_btn_confirm" .InstallerSiteName}}</button>
</div>
{{end}} <!-- edit/add - by petru @ codex -->
</div>
</form>
</div>
</div>
</div>
</div>
{{if .Err_DbInstalledBefore}}
<!-- start edit/add - by petru @ codex -->
<div class="ui small modal install-reinstall-confirm-modal js-install-reinstall-modal">
<div class="ui negative message install-reinstall-alert">{{ctx.Locale.Tr "install.reinstall_error"}}</div>
<div class="content">
<p class="reinstall-message">{{ctx.Locale.Tr "install.reinstall_confirm_message"}}</p>
<div class="reinstall-confirm">
<div class="ui checkbox">
<input id="reinstall_confirm_first" name="reinstall_confirm_first" type="checkbox" form="install-form">
<label for="reinstall_confirm_first">{{ctx.Locale.Tr "install.reinstall_confirm_check_1"}}</label>
</div>
</div>
<div class="reinstall-confirm">
<div class="ui checkbox">
<input id="reinstall_confirm_second" name="reinstall_confirm_second" type="checkbox" form="install-form">
<label for="reinstall_confirm_second">{{ctx.Locale.Tr "install.reinstall_confirm_check_2"}}</label>
</div>
</div>
<div class="reinstall-confirm">
<div class="ui checkbox">
<input id="reinstall_confirm_third" name="reinstall_confirm_third" type="checkbox" form="install-form">
<label for="reinstall_confirm_third">{{ctx.Locale.Tr "install.reinstall_confirm_check_3"}}</label>
</div>
</div>
</div>
<div class="actions">
<a class="ui button cancel" href="{{AppSubUrl}}/">{{ctx.Locale.Tr "go_back"}}</a>
<button
type="submit"
form="install-form"
class="ui primary button js-install-confirm-button"
data-install-label-template="{{ctx.Locale.Tr "install.install_btn_confirm" "__SITE_NAME__"}}"
disabled
>{{ctx.Locale.Tr "install.install_btn_confirm" .InstallerSiteName}}</button>
</div>
</div>
<!-- end edit/add - by petru @ codex -->
{{end}}
<div class="install-language-balloon" id="install-language-balloon" role="status" aria-live="polite">
{{ctx.Locale.Tr "install.language_balloon"}}
</div>
@@ -653,7 +686,7 @@
const installForm = document.querySelector('.js-install-form');
const appNameInput = installForm?.querySelector('#app_name');
const smtpFromNameInput = installForm?.querySelector('#smtp_from_name');
const installConfirmButton = installForm?.querySelector('.js-install-confirm-button');
const installConfirmButtons = installForm ? installForm.querySelectorAll('.js-install-confirm-button') : [];
if (appNameInput instanceof HTMLInputElement && smtpFromNameInput instanceof HTMLInputElement) {
let lastAutoMailerName = smtpFromNameInput.value.trim() || deriveInstallMailerName(appNameInput.value);
const syncInstallBranding = () => {
@@ -663,7 +696,8 @@
smtpFromNameInput.value = siteName;
}
lastAutoMailerName = siteName;
if (installConfirmButton instanceof HTMLButtonElement) {
for (const installConfirmButton of installConfirmButtons) {
if (!(installConfirmButton instanceof HTMLButtonElement)) continue;
installConfirmButton.textContent = installConfirmButton.dataset.installLabelTemplate.replace('__SITE_NAME__', siteName);
}
};
@@ -671,10 +705,13 @@
syncInstallBranding();
appNameInput.addEventListener('input', syncInstallBranding);
appNameInput.addEventListener('change', syncInstallBranding);
} else if (appNameInput instanceof HTMLInputElement && installConfirmButton instanceof HTMLButtonElement) {
} else if (appNameInput instanceof HTMLInputElement && installConfirmButtons.length > 0) {
const syncInstallButton = () => {
const siteName = deriveInstallMailerName(appNameInput.value);
installConfirmButton.textContent = installConfirmButton.dataset.installLabelTemplate.replace('__SITE_NAME__', siteName);
for (const installConfirmButton of installConfirmButtons) {
if (!(installConfirmButton instanceof HTMLButtonElement)) continue;
installConfirmButton.textContent = installConfirmButton.dataset.installLabelTemplate.replace('__SITE_NAME__', siteName);
}
};
syncInstallButton();
appNameInput.addEventListener('input', syncInstallButton);
@@ -725,6 +762,28 @@
document.addEventListener('DOMContentLoaded', () => {
dismissInstallSuccessFlash();
{{if .Err_DbInstalledBefore}}
// start edit/add - by petru @ codex
const reinstallModal = document.querySelector('.js-install-reinstall-modal');
if (reinstallModal) {
const reinstallConfirmInputs = reinstallModal.querySelectorAll('input[name^="reinstall_confirm_"]');
const reinstallConfirmButton = reinstallModal.querySelector('.js-install-confirm-button');
const syncReinstallConfirmButton = () => {
if (!(reinstallConfirmButton instanceof HTMLButtonElement)) return;
reinstallConfirmButton.disabled = [...reinstallConfirmInputs].some((input) => !(input instanceof HTMLInputElement) || !input.checked);
};
for (const input of reinstallConfirmInputs) {
input.addEventListener('change', syncReinstallConfirmButton);
}
syncReinstallConfirmButton();
window.$(reinstallModal).modal({
autofocus: false,
closable: false,
}).modal('show');
}
// end edit/add - by petru @ codex
{{end}}
const installLanguageBalloon = document.querySelector('#install-language-balloon');
const footerLanguageSelector = document.querySelector('#footer-language-selector');
if (!installLanguageBalloon || !footerLanguageSelector) return;
+1
View File
@@ -20,6 +20,7 @@
<a class="{{if .PageIsSettingsBlockedUsers}}active {{end}}item" href="{{.OrgLink}}/settings/blocked_users">
{{ctx.Locale.Tr "user.block.list"}}
</a>
<a class="{{if .PageIsSettingsRepos}}active {{end}}item" href="{{.OrgLink}}/settings/repos">{{ctx.Locale.Tr "settings.repos"}}</a> <!-- edit/add - by petru @ codex -->
{{if .EnablePackages}}
<a class="{{if .PageIsSettingsPackages}}active {{end}}item" href="{{.OrgLink}}/settings/packages">
{{ctx.Locale.Tr "packages.title"}}
@@ -122,6 +122,11 @@
</ul>
</div>
<form class="ui form form-fetch-action" action="{{.Link}}/delete" method="post">
{{/* start edit/add - by petru @ codex */}}
{{if .RedirectTo}}
<input type="hidden" name="redirect_to" value="{{.RedirectTo}}">
{{end}}
{{/* end edit/add - by petru @ codex */}}
<div class="field">
<label>
{{ctx.Locale.Tr "org.settings.name_confirm"}}
+112
View File
@@ -0,0 +1,112 @@
{{template "org/settings/layout_head" (dict "ctxData" . "pageClass" "organization settings repos")}}
<div class="ui segments org-setting-content">
<h4 class="ui top attached header">
{{ctx.Locale.Tr "settings.repos"}}
</h4>
<div class="ui attached segment">
{{if .Repos}}
<div class="ui list">
{{range .Repos}}
<div class="item">
<div class="content flex-text-block">
{{if .IsPrivate}}
{{svg "octicon-lock" 16 "tw-text-gold"}}
{{else if .IsFork}}
{{svg "octicon-repo-forked"}}
{{else if .IsMirror}}
{{svg "octicon-mirror"}}
{{else if .IsTemplate}}
{{svg "octicon-repo-template"}}
{{else}}
{{svg "octicon-repo"}}
{{end}}
<a class="name" href="{{.Link}}">{{.OwnerName}}/{{.Name}}</a>
{{$settingsLink := printf "%s/settings" .Link}}
{{if .IsPrivate}}
<a class="ui basic red label" href="{{$settingsLink}}">{{ctx.Locale.Tr "repo.desc.private"}}</a>
{{else if and .Owner .Owner.Visibility.IsPrivate}}
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.internal"}}</span>
{{else}}
<a class="ui basic green label" href="{{$settingsLink}}">{{ctx.Locale.Tr "settings.visibility.public"}}</a>
{{end}}
<span>{{FileSize .Size}}</span>
{{if .IsFork}}
{{ctx.Locale.Tr "repo.forked_from"}}
<span><a href="{{.BaseRepo.Link}}">{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}</a></span>
{{end}}
</div>
</div>
{{end}}
</div>
{{end}}
{{if or .allowAdopt .allowDelete}}
{{if .Dirs}}
{{if .Repos}}<div class="ui divider"></div>{{end}}
<h5 class="ui header">{{ctx.Locale.Tr "admin.repos.unadopted"}}</h5>
<div class="ui list">
{{range $dirI, $dir := .Dirs}}
<div class="item tw-py-1">
<div class="content">
<span class="icon tw-inline-block tw-pt-2">{{svg "octicon-file-directory-fill"}}</span>
<span class="name tw-inline-block tw-pt-2">{{$.ContextUser.Name}}/{{$dir}}</span>
<div class="tw-float-right">
{{if $.allowAdopt}}
<button class="ui button primary show-modal tw-p-2" data-modal="#adopt-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-plus"}}</span><span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting_label"}}</span></button>
<div class="ui g-modal-confirm modal" id="adopt-unadopted-modal-{{$dirI}}">
<div class="header">
<span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting"}}</span>
</div>
<div class="content">
<p>{{ctx.Locale.Tr "repo.adopt_preexisting_content" $dir}}</p>
</div>
<form class="ui form" method="post" action="{{$.OrgLink}}/settings/repos/unadopted">
<input type="hidden" name="id" value="{{$dir}}">
<input type="hidden" name="action" value="adopt">
{{/* start edit/add - by petru @ codex */}}
<div class="field">
<div class="ui checkbox">
<input id="adopt-private-org-{{$dirI}}" name="private" type="checkbox">
<label for="adopt-private-org-{{$dirI}}">{{ctx.Locale.Tr "repo.desc.private"}}</label>
</div>
</div>
{{/* end edit/add - by petru @ codex */}}
{{template "base/modal_actions_confirm" $}}
</form>
</div>
{{end}}
{{if $.allowDelete}}
<button class="ui button red show-modal tw-p-2" data-modal="#delete-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-x"}}</span><span class="label">{{ctx.Locale.Tr "repo.delete_preexisting_label"}}</span></button>
<div class="ui g-modal-confirm modal" id="delete-unadopted-modal-{{$dirI}}">
<div class="header">
<span class="label">{{ctx.Locale.Tr "repo.delete_preexisting"}}</span>
</div>
<div class="content">
<p>{{ctx.Locale.Tr "repo.delete_preexisting_content" $dir}}</p>
</div>
<form class="ui form" method="post" action="{{$.OrgLink}}/settings/repos/unadopted">
<input type="hidden" name="id" value="{{$dir}}">
<input type="hidden" name="action" value="delete">
{{template "base/modal_actions_confirm" $}}
</form>
</div>
{{end}}
</div>
</div>
</div>
{{end}}
</div>
{{else if not .Repos}}
<div class="item">
{{ctx.Locale.Tr "settings.repos_none"}}
</div>
{{end}}
{{else if not .Repos}}
<div class="item">
{{ctx.Locale.Tr "settings.repos_none"}}
</div>
{{end}}
{{template "base/paginate" .}}
</div>
</div>
{{template "org/settings/layout_footer" .}}
+5 -8
View File
@@ -26,21 +26,18 @@
</div>
<div id="repo_migrating_failed" class="tw-hidden">
{{if .CloneAddr}}
<p>{{ctx.Locale.Tr "repo.migrate.migrating_failed" .CloneAddr}}</p>
<p id="repo_migrating_failed_title" data-failed-html="{{ctx.Locale.Tr "repo.migrate.migrating_failed" .CloneAddr}}" data-stopped-html="{{ctx.Locale.Tr "repo.migrate.migrating_stopped" .CloneAddr}}">{{ctx.Locale.Tr "repo.migrate.migrating_failed" .CloneAddr}}</p> <!-- edit/add - by petru @ codex -->
{{else}}
<p>{{ctx.Locale.Tr "repo.migrate.migrating_failed_no_addr"}}</p>
<p id="repo_migrating_failed_title" data-failed-html="{{ctx.Locale.Tr "repo.migrate.migrating_failed_no_addr"}}" data-stopped-html="{{ctx.Locale.Tr "repo.migrate.migrating_stopped_no_addr"}}">{{ctx.Locale.Tr "repo.migrate.migrating_failed_no_addr"}}</p> <!-- edit/add - by petru @ codex -->
{{end}}
<p id="repo_migrating_failed_error"></p>
</div>
{{if .Permission.IsAdmin}}
<div class="divider"></div>
<div class="item">
{{if .Failed}}
<button class="ui basic red show-modal button" data-modal="#delete-repo-modal">{{ctx.Locale.Tr "repo.settings.delete"}}</button>
{{else}}
<button class="ui basic show-modal button" data-modal="#cancel-repo-modal">{{ctx.Locale.Tr "cancel"}}</button>
{{end}}
<button id="repo_migrating_retry" data-migrating-task-retry-url="{{.Link}}/settings/migrate/retry" class="ui basic button tw-hidden">{{ctx.Locale.Tr "retry"}}</button>
<button id="repo_migrating_delete" class="ui basic red show-modal button{{if not .Failed}} tw-hidden{{end}}" data-modal="#delete-repo-modal">{{ctx.Locale.Tr "repo.settings.delete"}}</button> <!-- edit/add - by petru @ codex -->
<button id="repo_migrating_cancel" class="ui basic show-modal button{{if or .Failed .Stopping}} tw-hidden{{end}}" data-modal="#cancel-repo-modal">{{ctx.Locale.Tr "cancel"}}</button> <!-- edit/add - by petru @ codex -->
<button id="repo_migrating_retry" data-migrating-task-retry-url="{{.Link}}/settings/migrate/retry" class="ui basic button{{if not .Failed}} tw-hidden{{end}}">{{ctx.Locale.Tr "retry"}}</button> <!-- edit/add - by petru @ codex -->
</div>
{{end}}
</div>
+87 -109
View File
@@ -4,131 +4,109 @@
{{ctx.Locale.Tr "settings.repos"}}
</h4>
<div class="ui attached segment">
{{if .Repos}}
<div class="ui list">
{{range .Repos}}
<div class="item">
<div class="content flex-text-block">
{{if .IsPrivate}}
{{svg "octicon-lock" 16 "tw-text-gold"}}
{{else if .IsFork}}
{{svg "octicon-repo-forked"}}
{{else if .IsMirror}}
{{svg "octicon-mirror"}}
{{else if .IsTemplate}}
{{svg "octicon-repo-template"}}
{{else}}
{{svg "octicon-repo"}}
{{end}}
<a class="name" href="{{.Link}}">{{.OwnerName}}/{{.Name}}</a>
{{$settingsLink := printf "%s/settings" .Link}}
{{$canAccessSettings := and $.IsSigned (eq $.SignedUser.ID .OwnerID)}}
{{if .IsPrivate}}
{{if $canAccessSettings}}<a class="ui basic red label" href="{{$settingsLink}}">{{ctx.Locale.Tr "repo.desc.private"}}</a>{{else}}<span class="ui basic red label">{{ctx.Locale.Tr "repo.desc.private"}}</span>{{end}}
{{else if and .Owner .Owner.Visibility.IsPrivate}}
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.internal"}}</span>
{{else}}
{{if $canAccessSettings}}<a class="ui basic green label" href="{{$settingsLink}}">{{ctx.Locale.Tr "settings.visibility.public"}}</a>{{else}}<span class="ui basic green label">{{ctx.Locale.Tr "settings.visibility.public"}}</span>{{end}}
{{end}}
<span>{{FileSize .Size}}</span>
{{if .IsFork}}
{{ctx.Locale.Tr "repo.forked_from"}}
<span><a href="{{.BaseRepo.Link}}">{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}</a></span>
{{end}}
</div>
</div>
{{end}}
</div>
{{end}}
{{if or .allowAdopt .allowDelete}}
{{if .Dirs}}
{{if .Repos}}<div class="ui divider"></div>{{end}}
<h5 class="ui header">{{ctx.Locale.Tr "admin.repos.unadopted"}}</h5>
<div class="ui list">
{{range $dirI, $dir := .Dirs}}
{{$repo := index $.ReposMap $dir}}
<div class="item {{if not $repo}}tw-py-1{{end}}">{{/* if not repo, then there are "adapt" buttons, so the padding shouldn't be that default large*/}}
<div class="item tw-py-1">
<div class="content">
{{if $repo}}
{{if $repo.IsPrivate}}
<span class="tw-text-gold icon">{{svg "octicon-lock"}}</span>
{{else if $repo.IsFork}}
<span class="icon">{{svg "octicon-repo-forked"}}</span>
{{else if $repo.IsMirror}}
<span class="icon">{{svg "octicon-mirror"}}</span>
{{else if $repo.IsTemplate}}
<span class="icon">{{svg "octicon-repo-template"}}</span>
{{else}}
<span class="icon">{{svg "octicon-repo"}}</span>
{{end}}
<a class="muted name" href="{{$repo.Link}}">{{$repo.OwnerName}}/{{$repo.Name}}</a>
{{$settingsLink := printf "%s/settings" $repo.Link}}
{{$canAccessSettings := and $.IsSigned (eq $.SignedUser.ID $repo.OwnerID)}}
{{if $repo.IsPrivate}}
{{if $canAccessSettings}}<a class="ui basic red label" href="{{$settingsLink}}">{{ctx.Locale.Tr "repo.desc.private"}}</a>{{else}}<span class="ui basic red label">{{ctx.Locale.Tr "repo.desc.private"}}</span>{{end}}
{{else if and $repo.Owner $repo.Owner.Visibility.IsPrivate}}
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.internal"}}</span>
{{else}}
{{if $canAccessSettings}}<a class="ui basic green label" href="{{$settingsLink}}">{{ctx.Locale.Tr "settings.visibility.public"}}</a>{{else}}<span class="ui basic green label">{{ctx.Locale.Tr "settings.visibility.public"}}</span>{{end}}
{{end}}
<span class="tw-text-text-light-3" {{if not (eq $repo.Size 0)}} data-tooltip-content="{{$repo.SizeDetailsString}}"{{end}}>{{FileSize $repo.Size}}</span>
{{if $repo.IsFork}}
{{ctx.Locale.Tr "repo.forked_from"}}
<span><a href="{{$repo.BaseRepo.Link}}">{{$repo.BaseRepo.OwnerName}}/{{$repo.BaseRepo.Name}}</a></span>
{{end}}
{{else}}
<span class="icon tw-inline-block tw-pt-2">{{svg "octicon-file-directory-fill"}}</span>
<span class="name tw-inline-block tw-pt-2">{{$.ContextUser.Name}}/{{$dir}}</span>
<div class="tw-float-right">
{{if $.allowAdopt}}
<button class="ui button primary show-modal tw-p-2" data-modal="#adopt-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-plus"}}</span><span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting_label"}}</span></button>
<div class="ui g-modal-confirm modal" id="adopt-unadopted-modal-{{$dirI}}">
<div class="header">
<span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting"}}</span>
</div>
<div class="content">
<p>{{ctx.Locale.Tr "repo.adopt_preexisting_content" $dir}}</p>
</div>
<form class="ui form" method="post" action="{{AppSubUrl}}/user/settings/repos/unadopted">
<input type="hidden" name="id" value="{{$dir}}">
<input type="hidden" name="action" value="adopt">
{{template "base/modal_actions_confirm" $}}
</form>
<span class="icon tw-inline-block tw-pt-2">{{svg "octicon-file-directory-fill"}}</span>
<span class="name tw-inline-block tw-pt-2">{{$.ContextUser.Name}}/{{$dir}}</span>
<div class="tw-float-right">
{{if $.allowAdopt}}
<button class="ui button primary show-modal tw-p-2" data-modal="#adopt-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-plus"}}</span><span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting_label"}}</span></button>
<div class="ui g-modal-confirm modal" id="adopt-unadopted-modal-{{$dirI}}">
<div class="header">
<span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting"}}</span>
</div>
{{end}}
{{if $.allowDelete}}
<button class="ui button red show-modal tw-p-2" data-modal="#delete-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-x"}}</span><span class="label">{{ctx.Locale.Tr "repo.delete_preexisting_label"}}</span></button>
<div class="ui g-modal-confirm modal" id="delete-unadopted-modal-{{$dirI}}">
<div class="header">
<span class="label">{{ctx.Locale.Tr "repo.delete_preexisting"}}</span>
</div>
<div class="content">
<p>{{ctx.Locale.Tr "repo.delete_preexisting_content" $dir}}</p>
</div>
<form class="ui form" method="post" action="{{AppSubUrl}}/user/settings/repos/unadopted">
<input type="hidden" name="id" value="{{$dir}}">
<input type="hidden" name="action" value="delete">
{{template "base/modal_actions_confirm" $}}
</form>
<div class="content">
<p>{{ctx.Locale.Tr "repo.adopt_preexisting_content" $dir}}</p>
</div>
{{end}}
</div>
{{end}}
<form class="ui form" method="post" action="{{AppSubUrl}}/user/settings/repos/unadopted">
<input type="hidden" name="id" value="{{$dir}}">
<input type="hidden" name="action" value="adopt">
{{/* start edit/add - by petru @ codex */}}
<div class="field">
<div class="ui checkbox">
<input id="adopt-private-user-{{$dirI}}" name="private" type="checkbox">
<label for="adopt-private-user-{{$dirI}}">{{ctx.Locale.Tr "repo.desc.private"}}</label>
</div>
</div>
{{/* end edit/add - by petru @ codex */}}
{{template "base/modal_actions_confirm" $}}
</form>
</div>
{{end}}
{{if $.allowDelete}}
<button class="ui button red show-modal tw-p-2" data-modal="#delete-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-x"}}</span><span class="label">{{ctx.Locale.Tr "repo.delete_preexisting_label"}}</span></button>
<div class="ui g-modal-confirm modal" id="delete-unadopted-modal-{{$dirI}}">
<div class="header">
<span class="label">{{ctx.Locale.Tr "repo.delete_preexisting"}}</span>
</div>
<div class="content">
<p>{{ctx.Locale.Tr "repo.delete_preexisting_content" $dir}}</p>
</div>
<form class="ui form" method="post" action="{{AppSubUrl}}/user/settings/repos/unadopted">
<input type="hidden" name="id" value="{{$dir}}">
<input type="hidden" name="action" value="delete">
{{template "base/modal_actions_confirm" $}}
</form>
</div>
{{end}}
</div>
</div>
</div>
{{end}}
</div>
{{template "base/paginate" .}}
{{else}}
<div class="item">
{{ctx.Locale.Tr "settings.repos_none"}}
</div>
{{end}}
{{else}}
{{if .Repos}}
<div class="ui list">
{{range .Repos}}
<div class="item">
<div class="content flex-text-block">
{{if .IsPrivate}}
{{svg "octicon-lock" 16 "tw-text-gold"}}
{{else if .IsFork}}
{{svg "octicon-repo-forked"}}
{{else if .IsMirror}}
{{svg "octicon-mirror"}}
{{else if .IsTemplate}}
{{svg "octicon-repo-template"}}
{{else}}
{{svg "octicon-repo"}}
{{end}}
<a class="name" href="{{.Link}}">{{.OwnerName}}/{{.Name}}</a>
{{$settingsLink := printf "%s/settings" .Link}}
{{$canAccessSettings := and $.IsSigned (eq $.SignedUser.ID .OwnerID)}}
{{if .IsPrivate}}
{{if $canAccessSettings}}<a class="ui basic red label" href="{{$settingsLink}}">{{ctx.Locale.Tr "repo.desc.private"}}</a>{{else}}<span class="ui basic red label">{{ctx.Locale.Tr "repo.desc.private"}}</span>{{end}}
{{else if and .Owner .Owner.Visibility.IsPrivate}}
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.internal"}}</span>
{{else}}
{{if $canAccessSettings}}<a class="ui basic green label" href="{{$settingsLink}}">{{ctx.Locale.Tr "settings.visibility.public"}}</a>{{else}}<span class="ui basic green label">{{ctx.Locale.Tr "settings.visibility.public"}}</span>{{end}}
{{end}}
<span>{{FileSize .Size}}</span>
{{if .IsFork}}
{{ctx.Locale.Tr "repo.forked_from"}}
<span><a href="{{.BaseRepo.Link}}">{{.BaseRepo.OwnerName}}/{{.BaseRepo.Name}}</a></span>
{{end}}
</div>
</div>
{{end}}
</div>
{{template "base/paginate" .}}
{{else}}
{{else if not .Repos}}
<div class="item">
{{ctx.Locale.Tr "settings.repos_none"}}
</div>
{{end}}
{{else if not .Repos}}
<div class="item">
{{ctx.Locale.Tr "settings.repos_none"}}
</div>
{{end}}
{{template "base/paginate" .}}
</div>
</div>
+51
View File
@@ -70,6 +70,57 @@
margin: 10px auto;
}
/* start edit/add - by petru @ codex */
.page-content.install .install-reinstall-confirm-modal .content {
padding-top: 1.25rem;
}
.ui.negative.message.install-reinstall-alert {
font-size: 19px;
}
.page-content.install .install-reinstall-confirm-modal .install-reinstall-alert {
margin-bottom: 1rem;
text-align: center;
font-weight: var(--font-weight-semibold);
}
.page-content.install .install-reinstall-confirm-modal .reinstall-message,
.page-content.install .install-reinstall-confirm-modal .reinstall-confirm {
width: 100%;
margin-left: 0;
margin-right: 0;
}
.page-content.install .install-reinstall-confirm-modal .reinstall-message {
margin-top: 0;
margin-bottom: 1rem;
color: var(--color-error-text);
font-weight: var(--font-weight-semibold);
}
.page-content.install .install-reinstall-confirm-modal .reinstall-confirm {
padding: 0;
}
.page-content.install .install-reinstall-confirm-modal .reinstall-confirm + .reinstall-confirm {
margin-top: 0.6rem;
}
.page-content.install .install-reinstall-confirm-modal .reinstall-confirm .ui.checkbox label {
display: block;
padding-left: 1.5rem;
line-height: 1.5;
font-weight: var(--font-weight-normal);
}
.page-content.install .install-reinstall-confirm-modal .actions {
display: flex;
justify-content: flex-end;
gap: 0.75rem;
}
/* end edit/add - by petru @ codex */
.install-language-balloon {
position: fixed;
right: 10.5rem;
+4
View File
@@ -101,6 +101,10 @@ input[type="checkbox"]:indeterminate::before {
margin-left: 20px;
}
.reinstall-confirm > .ui.checkbox label {
margin-bottom: 8px;
}
.ui.checkbox + label {
vertical-align: middle;
}
+5
View File
@@ -12,6 +12,11 @@
margin: 0 0 1em;
}
.g-modal-confirm.modal .form .field {
clear: both;
margin: 0 35px 1.6em;
}
.ui.form .fields .fields,
.ui.form .field:last-child,
.ui.form .fields:last-child .field {
+16 -3
View File
@@ -5,7 +5,8 @@ export function initRepoMigrationStatusChecker() {
const repoMigrating = document.querySelector('#repo_migrating');
if (!repoMigrating) return;
document.querySelector<HTMLButtonElement>('#repo_migrating_retry')?.addEventListener('click', doMigrationRetry);
const repoMigratingRetry = document.querySelector<HTMLButtonElement>('#repo_migrating_retry');
if (repoMigratingRetry) repoMigratingRetry.addEventListener('click', doMigrationRetry); // edit/add - by petru @ codex
const repoLink = repoMigrating.getAttribute('data-migrating-repo-link');
@@ -21,19 +22,31 @@ export function initRepoMigrationStatusChecker() {
document.querySelector('#repo_migrating_progress_message')!.textContent = data.message;
}
// migration cancel requested, keep polling until the clone process tree is actually gone
if (data.stopping) {
hideElem('#repo_migrating_cancel'); // edit/add - by petru @ codex
hideElem('#repo_migrating_retry'); // edit/add - by petru @ codex
hideElem('#repo_migrating_delete'); // edit/add - by petru @ codex
return true;
}
// TaskStatusFinished
if (data.status === 4) {
window.location.reload();
return false;
}
// TaskStatusFailed
if (data.status === 3) {
// TaskStatusFailed / TaskStatusStopped
if (data.status === 3 || data.stopped) {
hideElem('#repo_migrating_progress');
hideElem('#repo_migrating');
hideElem('#repo_migrating_cancel'); // edit/add - by petru @ codex
showElem('#repo_migrating_retry');
showElem('#repo_migrating_delete'); // edit/add - by petru @ codex
showElem('#repo_migrating_failed');
showElem('#repo_migrating_failed_image');
const failedTitle = document.querySelector<HTMLElement>('#repo_migrating_failed_title'); // edit/add - by petru @ codex
if (failedTitle) failedTitle.innerHTML = failedTitle.getAttribute(data.stopped ? 'data-stopped-html' : 'data-failed-html') || failedTitle.innerHTML; // edit/add - by petru @ codex
document.querySelector('#repo_migrating_failed_error')!.textContent = data.message;
return false;
}