Compare commits
9 Commits
0e5e7b03ab
...
406e6d0697
| Author | SHA1 | Date | |
|---|---|---|---|
| 406e6d0697 | |||
| 6ea9c8660f | |||
| 70659dc6c3 | |||
| f293572182 | |||
| 66093c1564 | |||
| 26e30f5ac2 | |||
| efbd83def5 | |||
| b7661af8d7 | |||
| 03f90d9234 |
@@ -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 `/`.
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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" .}}
|
||||
|
||||
@@ -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" .}}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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"}}
|
||||
|
||||
@@ -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" .}}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user