mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-16 21:53:06 +02:00
Merge branch 'main' into work/pr-on-pr-view
This commit is contained in:
commit
0cb63edf9a
@ -326,6 +326,7 @@ module.exports = {
|
||||
'@typescript-eslint/no-unnecessary-type-arguments': [0],
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': [2],
|
||||
'@typescript-eslint/no-unnecessary-type-constraint': [2],
|
||||
'@typescript-eslint/no-unnecessary-type-conversion': [2],
|
||||
'@typescript-eslint/no-unsafe-argument': [0],
|
||||
'@typescript-eslint/no-unsafe-assignment': [0],
|
||||
'@typescript-eslint/no-unsafe-call': [0],
|
||||
@ -645,7 +646,7 @@ module.exports = {
|
||||
'no-multi-str': [2],
|
||||
'no-negated-condition': [0],
|
||||
'no-nested-ternary': [0],
|
||||
'no-new-func': [2],
|
||||
'no-new-func': [0], // handled by @typescript-eslint/no-implied-eval
|
||||
'no-new-native-nonconstructor': [2],
|
||||
'no-new-object': [2],
|
||||
'no-new-symbol': [2],
|
||||
|
10
.github/labeler.yml
vendored
10
.github/labeler.yml
vendored
@ -81,3 +81,13 @@ docs-update-needed:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "custom/conf/app.example.ini"
|
||||
|
||||
topic/code-linting:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- ".eslintrc.cjs"
|
||||
- ".golangci.yml"
|
||||
- ".markdownlint.yaml"
|
||||
- ".spectral.yaml"
|
||||
- ".yamllint.yaml"
|
||||
- "stylelint.config.js"
|
||||
|
@ -591,7 +591,7 @@ be reviewed by two maintainers and must pass the automatic tests.
|
||||
## Releasing Gitea
|
||||
|
||||
- Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future.
|
||||
- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody against in about serval hours.
|
||||
- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
|
||||
- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
|
||||
- Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
|
||||
- When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
|
||||
|
@ -32,6 +32,7 @@ var (
|
||||
CmdHook = &cli.Command{
|
||||
Name: "hook",
|
||||
Usage: "(internal) Should only be called by Git",
|
||||
Hidden: true, // internal commands shouldn't be visible
|
||||
Description: "Delegate commands to corresponding Git hooks",
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Commands: []*cli.Command{
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
var CmdKeys = &cli.Command{
|
||||
Name: "keys",
|
||||
Usage: "(internal) Should only be called by SSH server",
|
||||
Hidden: true, // internal commands shouldn't not be visible
|
||||
Description: "Queries the Gitea database to get the authorized command for a given ssh key fingerprint",
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Action: runKeys,
|
||||
|
158
cmd/main.go
158
cmd/main.go
@ -6,6 +6,7 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@ -15,26 +16,28 @@ import (
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// cmdHelp is our own help subcommand with more information
|
||||
// Keep in mind that the "./gitea help"(subcommand) is different from "./gitea --help"(flag), the flag doesn't parse the config or output "DEFAULT CONFIGURATION:" information
|
||||
func cmdHelp() *cli.Command {
|
||||
c := &cli.Command{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
ArgsUsage: "[command]",
|
||||
Action: func(ctx context.Context, c *cli.Command) (err error) {
|
||||
lineage := c.Lineage() // The order is from child to parent: help, doctor, Gitea
|
||||
targetCmdIdx := 0
|
||||
if c.Name == "help" {
|
||||
targetCmdIdx = 1
|
||||
}
|
||||
if lineage[targetCmdIdx] != lineage[targetCmdIdx].Root() {
|
||||
err = cli.ShowCommandHelp(ctx, lineage[targetCmdIdx+1] /* parent cmd */, lineage[targetCmdIdx].Name /* sub cmd */)
|
||||
} else {
|
||||
err = cli.ShowAppHelp(c)
|
||||
}
|
||||
_, _ = fmt.Fprintf(c.Root().Writer, `
|
||||
var cliHelpPrinterOld = cli.HelpPrinter
|
||||
|
||||
func init() {
|
||||
cli.HelpPrinter = cliHelpPrinterNew
|
||||
}
|
||||
|
||||
// cliHelpPrinterNew helps to print "DEFAULT CONFIGURATION" for the following cases ( "-c" can apper in any position):
|
||||
// * ./gitea -c /dev/null -h
|
||||
// * ./gitea -c help /dev/null help
|
||||
// * ./gitea help -c /dev/null
|
||||
// * ./gitea help -c /dev/null web
|
||||
// * ./gitea help web -c /dev/null
|
||||
// * ./gitea web help -c /dev/null
|
||||
// * ./gitea web -h -c /dev/null
|
||||
func cliHelpPrinterNew(out io.Writer, templ string, data any) {
|
||||
cmd, _ := data.(*cli.Command)
|
||||
if cmd != nil {
|
||||
prepareWorkPathAndCustomConf(cmd)
|
||||
}
|
||||
cliHelpPrinterOld(out, templ, data)
|
||||
if setting.CustomConf != "" {
|
||||
_, _ = fmt.Fprintf(out, `
|
||||
DEFAULT CONFIGURATION:
|
||||
AppPath: %s
|
||||
WorkPath: %s
|
||||
@ -42,77 +45,36 @@ DEFAULT CONFIGURATION:
|
||||
ConfigFile: %s
|
||||
|
||||
`, setting.AppPath, setting.AppWorkPath, setting.CustomPath, setting.CustomConf)
|
||||
return err
|
||||
},
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func appGlobalFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
// make the builtin flags at the top
|
||||
cli.HelpFlag,
|
||||
|
||||
// shared configuration flags, they are for global and for each sub-command at the same time
|
||||
// eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
|
||||
// keep in mind that the short flags like "-C", "-c" and "-w" are globally polluted, they can't be used for sub-commands anymore.
|
||||
&cli.StringFlag{
|
||||
Name: "custom-path",
|
||||
Aliases: []string{"C"},
|
||||
Usage: "Set custom path (defaults to '{WorkPath}/custom')",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
Value: setting.CustomConf,
|
||||
Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "work-path",
|
||||
Aliases: []string{"w"},
|
||||
Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func prepareSubcommandWithGlobalFlags(command *cli.Command) {
|
||||
command.Flags = append(append([]cli.Flag{}, appGlobalFlags()...), command.Flags...)
|
||||
command.Action = prepareWorkPathAndCustomConf(command.Action)
|
||||
command.HideHelp = true
|
||||
if command.Name != "help" {
|
||||
command.Commands = append(command.Commands, cmdHelp())
|
||||
}
|
||||
for i := range command.Commands {
|
||||
prepareSubcommandWithGlobalFlags(command.Commands[i])
|
||||
}
|
||||
}
|
||||
|
||||
// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
|
||||
// It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times
|
||||
func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(context.Context, *cli.Command) error {
|
||||
return func(ctx context.Context, cmd *cli.Command) error {
|
||||
var args setting.ArgWorkPathAndCustomConf
|
||||
// from children to parent, check the global flags
|
||||
for _, curCtx := range cmd.Lineage() {
|
||||
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
||||
args.WorkPath = curCtx.String("work-path")
|
||||
}
|
||||
if curCtx.IsSet("custom-path") && args.CustomPath == "" {
|
||||
args.CustomPath = curCtx.String("custom-path")
|
||||
}
|
||||
if curCtx.IsSet("config") && args.CustomConf == "" {
|
||||
args.CustomConf = curCtx.String("config")
|
||||
}
|
||||
func prepareSubcommandWithGlobalFlags(originCmd *cli.Command) {
|
||||
originBefore := originCmd.Before
|
||||
originCmd.Before = func(ctx context.Context, cmd *cli.Command) (context.Context, error) {
|
||||
prepareWorkPathAndCustomConf(cmd)
|
||||
if originBefore != nil {
|
||||
return originBefore(ctx, cmd)
|
||||
}
|
||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||
if cmd.Bool("help") || action == nil {
|
||||
// the default behavior of "urfave/cli": "nil action" means "show help"
|
||||
return cmdHelp().Action(ctx, cmd)
|
||||
}
|
||||
return action(ctx, cmd)
|
||||
return ctx, nil
|
||||
}
|
||||
}
|
||||
|
||||
// prepareWorkPathAndCustomConf tries to prepare the work path, custom path and custom config from various inputs:
|
||||
// command line flags, environment variables, config file
|
||||
func prepareWorkPathAndCustomConf(cmd *cli.Command) {
|
||||
var args setting.ArgWorkPathAndCustomConf
|
||||
if cmd.IsSet("work-path") {
|
||||
args.WorkPath = cmd.String("work-path")
|
||||
}
|
||||
if cmd.IsSet("custom-path") {
|
||||
args.CustomPath = cmd.String("custom-path")
|
||||
}
|
||||
if cmd.IsSet("config") {
|
||||
args.CustomConf = cmd.String("config")
|
||||
}
|
||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||
}
|
||||
|
||||
type AppVersion struct {
|
||||
Version string
|
||||
Extra string
|
||||
@ -125,10 +87,29 @@ func NewMainApp(appVer AppVersion) *cli.Command {
|
||||
app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
|
||||
app.Version = appVer.Version + appVer.Extra
|
||||
app.EnableShellCompletion = true
|
||||
|
||||
// these sub-commands need to use config file
|
||||
app.Flags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "work-path",
|
||||
Aliases: []string{"w"},
|
||||
TakesFile: true,
|
||||
Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
TakesFile: true,
|
||||
Value: setting.CustomConf,
|
||||
Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "custom-path",
|
||||
Aliases: []string{"C"},
|
||||
TakesFile: true,
|
||||
Usage: "Set custom path (defaults to '{WorkPath}/custom')",
|
||||
},
|
||||
}
|
||||
// these sub-commands need to use a config file
|
||||
subCmdWithConfig := []*cli.Command{
|
||||
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
|
||||
CmdWeb,
|
||||
CmdServ,
|
||||
CmdHook,
|
||||
@ -156,9 +137,6 @@ func NewMainApp(appVer AppVersion) *cli.Command {
|
||||
// but not sure whether it would break Windows users who used to double-click the EXE to run.
|
||||
app.DefaultCommand = CmdWeb.Name
|
||||
|
||||
app.Flags = append(app.Flags, cli.VersionFlag)
|
||||
app.Flags = append(app.Flags, appGlobalFlags()...)
|
||||
app.HideHelp = true // use our own help action to show helps (with more information like default config)
|
||||
app.Before = PrepareConsoleLoggerLevel(log.INFO)
|
||||
for i := range subCmdWithConfig {
|
||||
prepareSubcommandWithGlobalFlags(subCmdWithConfig[i])
|
||||
|
@ -74,12 +74,56 @@ func TestCliCmd(t *testing.T) {
|
||||
cmd string
|
||||
exp string
|
||||
}{
|
||||
// main command help
|
||||
// help commands
|
||||
{
|
||||
cmd: "./gitea -h",
|
||||
exp: "DEFAULT CONFIGURATION:",
|
||||
},
|
||||
{
|
||||
cmd: "./gitea help",
|
||||
exp: "DEFAULT CONFIGURATION:",
|
||||
},
|
||||
|
||||
{
|
||||
cmd: "./gitea -c /dev/null -h",
|
||||
exp: "ConfigFile: /dev/null",
|
||||
},
|
||||
|
||||
{
|
||||
cmd: "./gitea -c /dev/null help",
|
||||
exp: "ConfigFile: /dev/null",
|
||||
},
|
||||
{
|
||||
cmd: "./gitea help -c /dev/null",
|
||||
exp: "ConfigFile: /dev/null",
|
||||
},
|
||||
|
||||
{
|
||||
cmd: "./gitea -c /dev/null test-cmd -h",
|
||||
exp: "ConfigFile: /dev/null",
|
||||
},
|
||||
{
|
||||
cmd: "./gitea test-cmd -c /dev/null -h",
|
||||
exp: "ConfigFile: /dev/null",
|
||||
},
|
||||
{
|
||||
cmd: "./gitea test-cmd -h -c /dev/null",
|
||||
exp: "ConfigFile: /dev/null",
|
||||
},
|
||||
|
||||
{
|
||||
cmd: "./gitea -c /dev/null test-cmd help",
|
||||
exp: "ConfigFile: /dev/null",
|
||||
},
|
||||
{
|
||||
cmd: "./gitea test-cmd -c /dev/null help",
|
||||
exp: "ConfigFile: /dev/null",
|
||||
},
|
||||
{
|
||||
cmd: "./gitea test-cmd help -c /dev/null",
|
||||
exp: "ConfigFile: /dev/null",
|
||||
},
|
||||
|
||||
// parse paths
|
||||
{
|
||||
cmd: "./gitea test-cmd",
|
||||
|
@ -41,6 +41,7 @@ var CmdServ = &cli.Command{
|
||||
Name: "serv",
|
||||
Usage: "(internal) Should only be called by SSH shell",
|
||||
Description: "Serv provides access auth for repositories",
|
||||
Hidden: true, // Internal commands shouldn't be visible in help
|
||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||
Action: runServ,
|
||||
Flags: []cli.Flag{
|
||||
|
@ -1,17 +0,0 @@
|
||||
Bash and Zsh completion
|
||||
=======================
|
||||
|
||||
From within the gitea root run:
|
||||
|
||||
```bash
|
||||
source contrib/autocompletion/bash_autocomplete
|
||||
```
|
||||
|
||||
or for zsh run:
|
||||
|
||||
```bash
|
||||
source contrib/autocompletion/zsh_autocomplete
|
||||
```
|
||||
|
||||
These scripts will check if gitea is on the path and if so add autocompletion for `gitea`. Or if not autocompletion will work for `./gitea`.
|
||||
If gitea has been installed as a different program pass in the `PROG` environment variable to set the correct program name.
|
@ -1,30 +0,0 @@
|
||||
#! /bin/bash
|
||||
# Heavily inspired by https://github.com/urfave/cli
|
||||
|
||||
_cli_bash_autocomplete() {
|
||||
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
|
||||
local cur opts base
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [[ "$cur" == "-"* ]]; then
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
|
||||
else
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
|
||||
fi
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -z "$PROG" ] && [ ! "$(command -v gitea &> /dev/null)" ] ; then
|
||||
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete gitea
|
||||
elif [ -z "$PROG" ]; then
|
||||
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete ./gitea
|
||||
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete "$PWD/gitea"
|
||||
else
|
||||
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete "$PROG"
|
||||
unset PROG
|
||||
fi
|
||||
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
#compdef ${PROG:=gitea}
|
||||
|
||||
|
||||
# Heavily inspired by https://github.com/urfave/cli
|
||||
|
||||
_cli_zsh_autocomplete() {
|
||||
|
||||
local -a opts
|
||||
local cur
|
||||
cur=${words[-1]}
|
||||
if [[ "$cur" == "-"* ]]; then
|
||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
|
||||
else
|
||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
|
||||
fi
|
||||
|
||||
if [[ "${opts[1]}" != "" ]]; then
|
||||
_describe 'values' opts
|
||||
else
|
||||
_files
|
||||
fi
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if [ -z $PROG ] ; then
|
||||
compdef _cli_zsh_autocomplete gitea
|
||||
else
|
||||
compdef _cli_zsh_autocomplete $(basename $PROG)
|
||||
fi
|
2
go.mod
2
go.mod
@ -1,6 +1,6 @@
|
||||
module code.gitea.io/gitea
|
||||
|
||||
go 1.24.4
|
||||
go 1.24.5
|
||||
|
||||
// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
|
||||
// But some CAs use negative serial number, just relax the check. related:
|
||||
|
@ -275,7 +275,7 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
||||
HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr)
|
||||
}
|
||||
default:
|
||||
log.Fatal("Invalid PROTOCOL %q", Protocol)
|
||||
log.Fatal("Invalid PROTOCOL %q", protocolCfg)
|
||||
}
|
||||
UseProxyProtocol = sec.Key("USE_PROXY_PROTOCOL").MustBool(false)
|
||||
ProxyProtocolTLSBridging = sec.Key("PROXY_PROTOCOL_TLS_BRIDGING").MustBool(false)
|
||||
|
@ -57,7 +57,7 @@ type Repository struct {
|
||||
Private bool `json:"private"`
|
||||
Fork bool `json:"fork"`
|
||||
Template bool `json:"template"`
|
||||
Parent *Repository `json:"parent"`
|
||||
Parent *Repository `json:"parent,omitempty"`
|
||||
Mirror bool `json:"mirror"`
|
||||
Size int `json:"size"`
|
||||
Language string `json:"language"`
|
||||
@ -114,7 +114,7 @@ type Repository struct {
|
||||
ObjectFormatName string `json:"object_format_name"`
|
||||
// swagger:strfmt date-time
|
||||
MirrorUpdated time.Time `json:"mirror_updated"`
|
||||
RepoTransfer *RepoTransfer `json:"repo_transfer"`
|
||||
RepoTransfer *RepoTransfer `json:"repo_transfer,omitempty"`
|
||||
Topics []string `json:"topics"`
|
||||
Licenses []string `json:"licenses"`
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"html/template"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
texttmpl "text/template"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
@ -16,6 +17,12 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
type MailTemplates struct {
|
||||
TemplateNames []string
|
||||
BodyTemplates *template.Template
|
||||
SubjectTemplates *texttmpl.Template
|
||||
}
|
||||
|
||||
var mailSubjectSplit = regexp.MustCompile(`(?m)^-{3,}\s*$`)
|
||||
|
||||
// mailSubjectTextFuncMap returns functions for injecting to text templates, it's only used for mail subject
|
||||
@ -52,16 +59,17 @@ func buildSubjectBodyTemplate(stpl *texttmpl.Template, btpl *template.Template,
|
||||
return nil
|
||||
}
|
||||
|
||||
// Mailer provides the templates required for sending notification mails.
|
||||
func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) {
|
||||
subjectTemplates := texttmpl.New("")
|
||||
bodyTemplates := template.New("")
|
||||
|
||||
subjectTemplates.Funcs(mailSubjectTextFuncMap())
|
||||
bodyTemplates.Funcs(NewFuncMap())
|
||||
|
||||
// LoadMailTemplates provides the templates required for sending notification mails.
|
||||
func LoadMailTemplates(ctx context.Context, loadedTemplates *atomic.Pointer[MailTemplates]) {
|
||||
assetFS := AssetFS()
|
||||
refreshTemplates := func(firstRun bool) {
|
||||
var templateNames []string
|
||||
subjectTemplates := texttmpl.New("")
|
||||
bodyTemplates := template.New("")
|
||||
|
||||
subjectTemplates.Funcs(mailSubjectTextFuncMap())
|
||||
bodyTemplates.Funcs(NewFuncMap())
|
||||
|
||||
if !firstRun {
|
||||
log.Trace("Reloading mail templates")
|
||||
}
|
||||
@ -81,6 +89,7 @@ func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) {
|
||||
if firstRun {
|
||||
log.Trace("Adding mail template %s: %s by %s", tmplName, assetPath, layerName)
|
||||
}
|
||||
templateNames = append(templateNames, tmplName)
|
||||
if err = buildSubjectBodyTemplate(subjectTemplates, bodyTemplates, tmplName, content); err != nil {
|
||||
if firstRun {
|
||||
log.Fatal("Failed to parse mail template, err: %v", err)
|
||||
@ -88,6 +97,12 @@ func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) {
|
||||
log.Error("Failed to parse mail template, err: %v", err)
|
||||
}
|
||||
}
|
||||
loaded := &MailTemplates{
|
||||
TemplateNames: templateNames,
|
||||
BodyTemplates: bodyTemplates,
|
||||
SubjectTemplates: subjectTemplates,
|
||||
}
|
||||
loadedTemplates.Store(loaded)
|
||||
}
|
||||
|
||||
refreshTemplates(true)
|
||||
@ -99,6 +114,4 @@ func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) {
|
||||
refreshTemplates(false)
|
||||
})
|
||||
}
|
||||
|
||||
return subjectTemplates, bodyTemplates
|
||||
}
|
||||
|
@ -128,7 +128,6 @@ pin=Připnout
|
||||
unpin=Odepnout
|
||||
|
||||
artifacts=Artefakty
|
||||
confirm_delete_artifact=Jste si jisti, že chcete odstranit artefakt „%s“?
|
||||
|
||||
archived=Archivováno
|
||||
|
||||
@ -168,7 +167,6 @@ internal_error_skipped=Došlo k vnitřní chybě, ale je přeskočena: %s
|
||||
search=Hledat...
|
||||
type_tooltip=Druh vyhledávání
|
||||
fuzzy=Fuzzy
|
||||
fuzzy_tooltip=Zahrnout výsledky, které také úzce odpovídají hledanému výrazu
|
||||
exact=Přesně
|
||||
exact_tooltip=Zahrnout pouze výsledky, které přesně odpovídají hledanému výrazu
|
||||
repo_kind=Hledat repozitáře...
|
||||
@ -490,7 +488,6 @@ activate_email.text=Pro aktivaci vašeho účtu do <b>%s</b> klikněte na násle
|
||||
|
||||
register_notify=Vítejte v %s
|
||||
register_notify.title=%[1]s vítejte v %[2]s
|
||||
register_notify.text_1=toto je váš potvrzovací e-mail pro %s!
|
||||
register_notify.text_2=Nyní se můžete přihlásit přes uživatelské jméno: %s.
|
||||
register_notify.text_3=Pokud pro vás byl vytvořen tento účet, nejprve <a href="%s">nastavte své heslo</a>.
|
||||
|
||||
@ -977,7 +974,6 @@ webauthn_alternative_tip=Možná budete chtít nakonfigurovat další metodu ov
|
||||
|
||||
manage_account_links=Správa propojených účtů
|
||||
manage_account_links_desc=Tyto externí účty jsou propojeny s vaším Gitea účtem.
|
||||
account_links_not_available=K vašemu Gitea účtu nejsou aktuálně připojené žádné externí účty.
|
||||
link_account=Propojit účet
|
||||
remove_account_link=Odstranit propojený účet
|
||||
remove_account_link_desc=Odstraněním propojeného účtu zrušíte jeho přístup k vašemu Gitea účtu. Pokračovat?
|
||||
@ -1014,8 +1010,6 @@ new_repo_helper=Repozitář obsahuje všechny projektové soubory, včetně hist
|
||||
owner=Vlastník
|
||||
owner_helper=Některé organizace se nemusejí v seznamu zobrazit kvůli maximálnímu dosaženému počtu repozitářů.
|
||||
repo_name=Název repozitáře
|
||||
repo_name_profile_public_hint=.profile je speciální repozitář, který můžete použít k přidání souboru README.md do svého veřejného profilu organizace, který je viditelný pro každého. Ujistěte se, že je veřejný, a pro začátek jej inicializujte pomocí README v adresáři profilu.
|
||||
repo_name_profile_private_hint=.profile-private je speciální repozitář, který můžete použít k přidání souboru README.md do profilu člena organizace, který je viditelný pouze pro členy organizace. Ujistěte se, že je soukromý, a pro začátek jej inicializujte pomocí README v adresáři profilu.
|
||||
repo_name_helper=Dobrá jména repozitářů používají krátká, zapamatovatelná a unikátní klíčová slova. Repozitář s názvem „.profile“ nebo „.profile-private“ lze použít k přidání README.md pro uživatelský/organizační profil.
|
||||
repo_size=Velikost repozitáře
|
||||
template=Šablona
|
||||
@ -1037,7 +1031,6 @@ fork_branch=Větev, která má být klonována pro fork
|
||||
all_branches=Všechny větve
|
||||
view_all_branches=Zobrazit všechny větve
|
||||
view_all_tags=Zobrazit všechny značky
|
||||
fork_no_valid_owners=Tento repozitář nemůže být rozštěpen, protože neexistují žádní platní vlastníci.
|
||||
fork.blocked_user=Nelze rozštěpit repozitář, protože jste blokováni majitelem repozitáře.
|
||||
use_template=Použít tuto šablonu
|
||||
open_with_editor=Otevřít pomocí %s
|
||||
@ -1705,7 +1698,6 @@ issues.due_date_form=rrrr-mm-dd
|
||||
issues.due_date_form_add=Přidat termín dokončení
|
||||
issues.due_date_form_edit=Upravit
|
||||
issues.due_date_form_remove=Odstranit
|
||||
issues.due_date_not_writer=Potřebujete přístup k zápisu do tohoto repozitáře, abyste mohli aktualizovat datum dokončení úkolu.
|
||||
issues.due_date_not_set=Žádný termín dokončení.
|
||||
issues.due_date_added=přidal/a termín dokončení %s %s
|
||||
issues.due_date_modified=upravil/a termín termínu z %[2]s na %[1]s %[3]s
|
||||
@ -2070,7 +2062,6 @@ activity.title.releases_1=%d Vydání
|
||||
activity.title.releases_n=%d Vydání
|
||||
activity.title.releases_published_by=%s publikoval %s
|
||||
activity.published_release_label=Publikováno
|
||||
activity.no_git_activity=V tomto období nebyla žádná aktivita při odevzdání.
|
||||
activity.git_stats_exclude_merges=Při vyloučení slučování,
|
||||
activity.git_stats_author_1=%d autor
|
||||
activity.git_stats_author_n=%d autoři
|
||||
|
@ -117,7 +117,6 @@ files=Dateien
|
||||
|
||||
error=Fehler
|
||||
error404=Die Seite, die Du versuchst aufzurufen, <strong>existiert nicht</strong> oder <strong>Du bist nicht berechtigt</strong>, diese anzusehen.
|
||||
error503=Der Server konnte deine Anfrage nicht abschließen. Bitte versuche es später erneut.
|
||||
go_back=Zurück
|
||||
invalid_data=Ungültige Daten: %v
|
||||
|
||||
@ -131,7 +130,6 @@ unpin=Loslösen
|
||||
|
||||
artifacts=Artefakte
|
||||
expired=Abgelaufen
|
||||
confirm_delete_artifact=Bist du sicher, dass du das Artefakt '%s' löschen möchtest?
|
||||
|
||||
archived=Archiviert
|
||||
|
||||
@ -171,7 +169,6 @@ internal_error_skipped=Ein interner Fehler ist aufgetreten, wurde aber überspru
|
||||
search=Suche ...
|
||||
type_tooltip=Suchmodus
|
||||
fuzzy=Ähnlich
|
||||
fuzzy_tooltip=Ergebnisse einbeziehen, die dem Suchbegriff ähnlich sind
|
||||
words=Wörter
|
||||
words_tooltip=Nur Suchbegriffe einbeziehen, die den Suchbegriffen exakt entsprechen
|
||||
regexp=Regexp
|
||||
@ -505,7 +502,6 @@ activate_email.text=Bitte klicke innerhalb von <b>%s</b> auf folgenden Link, um
|
||||
|
||||
register_notify=Willkommen bei %s
|
||||
register_notify.title=%[1]s, willkommen bei %[2]s
|
||||
register_notify.text_1=dies ist deine Bestätigungs-E-Mail für %s!
|
||||
register_notify.text_2=Du kannst dich jetzt mit dem Benutzernamen "%s" anmelden.
|
||||
register_notify.text_3=Wenn dieser Account von dir erstellt wurde, musst du zuerst <a href="%s">dein Passwort setzen</a>.
|
||||
|
||||
@ -997,7 +993,6 @@ webauthn_alternative_tip=Möglicherweise möchtest du eine zusätzliche Authenti
|
||||
|
||||
manage_account_links=Verknüpfte Accounts verwalten
|
||||
manage_account_links_desc=Diese externen Accounts sind mit deinem Gitea-Account verknüpft.
|
||||
account_links_not_available=Es sind keine externen Accounts mit diesem Gitea-Account verknüpft.
|
||||
link_account=Account verbinden
|
||||
remove_account_link=Verknüpften Account entfernen
|
||||
remove_account_link_desc=Wenn du den verknüpften Account entfernst, wirst du darüber nicht mehr auf deinen Gitea-Account zugreifen können. Fortfahren?
|
||||
@ -1034,8 +1029,6 @@ new_repo_helper=Ein Repository enthält alle Projektdateien, einschließlich des
|
||||
owner=Besitzer
|
||||
owner_helper=Einige Organisationen könnten in der Dropdown-Liste nicht angezeigt werden, da die Anzahl an Repositories begrenzt ist.
|
||||
repo_name=Repository-Name
|
||||
repo_name_profile_public_hint=.profile ist ein spezielles Repository, mit dem du die README.md zu deinem öffentlichen Organisationsprofil hinzufügen kannst, das für jeden sichtbar ist. Stelle sicher, dass es öffentlich ist und initialisiere es mit einer README im Profilverzeichnis, um loszulegen.
|
||||
repo_name_profile_private_hint=.profile ist ein spezielles Repository, mit dem du die README.md zu deinem privaten Organisationsprofil hinzufügen kannst, das nur für Organisationsmitglieder sichtbar ist. Stelle sicher, dass es privat ist und initialisiere es mit einer README im Profilverzeichnis, um loszulegen.
|
||||
repo_name_helper=Ein guter Repository-Name besteht normalerweise aus kurzen, unvergesslichen und einzigartigen Schlagwörtern. Ein Repository namens ".profile" or ".profile-private" kann verwendet werden, um die README.md auf dem Benutzer- oder Organisationsprofil anzuzeigen.
|
||||
repo_size=Repository-Größe
|
||||
template=Template
|
||||
@ -1057,7 +1050,6 @@ fork_branch=Branch, der zum Fork geklont werden soll
|
||||
all_branches=Alle Branches
|
||||
view_all_branches=Alle Branches anzeigen
|
||||
view_all_tags=Alle Tags anzeigen
|
||||
fork_no_valid_owners=Dieses Repository kann nicht geforkt werden, da keine gültigen Besitzer vorhanden sind.
|
||||
fork.blocked_user=Das Repository kann nicht geforkt werden, da du vom Repository-Eigentümer blockiert wurdest.
|
||||
use_template=Dieses Template verwenden
|
||||
open_with_editor=Mit %s öffnen
|
||||
@ -1739,7 +1731,6 @@ issues.due_date_form=JJJJ-MM-TT
|
||||
issues.due_date_form_add=Fälligkeitsdatum hinzufügen
|
||||
issues.due_date_form_edit=Bearbeiten
|
||||
issues.due_date_form_remove=Entfernen
|
||||
issues.due_date_not_writer=Du musst Schreibrechte für dieses Repository haben, um das Fälligkeitsdatum zu ändern.
|
||||
issues.due_date_not_set=Kein Fälligkeitsdatum gesetzt.
|
||||
issues.due_date_added=hat %[2]s das Fälligkeitsdatum %[1]s hinzugefügt
|
||||
issues.due_date_modified=ändert das Abgabedatum von %[2]s auf %[1]s %[3]s s
|
||||
@ -2106,7 +2097,6 @@ activity.title.releases_1=%d Release
|
||||
activity.title.releases_n=%d Releases
|
||||
activity.title.releases_published_by=%s von %s veröffentlicht
|
||||
activity.published_release_label=Veröffentlicht
|
||||
activity.no_git_activity=In diesem Zeitraum sind keine Commit-Aktivität vorhanden.
|
||||
activity.git_stats_exclude_merges=Merges ausgenommen,
|
||||
activity.git_stats_author_1=%d Autor
|
||||
activity.git_stats_author_n=%d Autoren
|
||||
|
@ -427,7 +427,6 @@ activate_email.title=%s, παρακαλώ επαληθεύστε τη διεύθ
|
||||
activate_email.text=Παρακαλώ κάντε κλικ στον παρακάτω σύνδεσμο για να επαληθεύσετε τη διεύθυνση email σας στο <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, καλώς ήρθατε στο %[2]s
|
||||
register_notify.text_1=αυτό είναι το email επιβεβαίωσης εγγραφής για το %s!
|
||||
register_notify.text_2=Τώρα μπορείτε να συνδεθείτε μέσω του ονόματος χρήστη: %s.
|
||||
register_notify.text_3=Εάν αυτός ο λογαριασμός έχει δημιουργηθεί για εσάς, παρακαλώ <a href="%s">ορίστε πρώτα τον κωδικό πρόσβασής σας</a>.
|
||||
|
||||
@ -871,7 +870,6 @@ webauthn_alternative_tip=Μπορεί να θέλετε να ρυθμίσετε
|
||||
|
||||
manage_account_links=Διαχείριση Συνδεδεμένων Λογαριασμών
|
||||
manage_account_links_desc=Αυτοί οι εξωτερικοί λογαριασμοί είναι συνδεδεμένοι στον Gitea λογαριασμό σας.
|
||||
account_links_not_available=Προς το παρόν δεν υπάρχουν εξωτερικοί λογαριασμοί συνδεδεμένοι με τον λογαριασμό σας στο Gitea.
|
||||
link_account=Σύνδεση Λογαριασμού
|
||||
remove_account_link=Αφαίρεση Συνδεδεμένου Λογαριασμού
|
||||
remove_account_link_desc=Η κατάργηση ενός συνδεδεμένου λογαριασμού θα ανακαλέσει την πρόσβασή του στο λογαριασμό σας στο Gitea. Συνέχεια;
|
||||
@ -926,7 +924,6 @@ fork_to_different_account=Fork σε διαφορετικό λογαριασμό
|
||||
fork_visibility_helper=Η ορατότητα ενός fork αποθετηρίου δεν μπορεί να αλλάξει.
|
||||
fork_branch=Κλάδος που θα κλωνοποιηθεί στο fork
|
||||
all_branches=Όλοι οι κλάδοι
|
||||
fork_no_valid_owners=Αυτό το αποθετήριο δεν μπορεί να γίνει fork επειδή δεν υπάρχουν έγκυροι ιδιοκτήτες.
|
||||
use_template=Χρήση αυτού του πρότυπου
|
||||
download_zip=Λήψη ZIP
|
||||
download_tar=Λήψη TAR.GZ
|
||||
@ -1537,7 +1534,6 @@ issues.due_date_form=εεεε-μμ-ηη
|
||||
issues.due_date_form_add=Προσθήκη ημερομηνίας παράδοσης
|
||||
issues.due_date_form_edit=Επεξεργασία
|
||||
issues.due_date_form_remove=Διαγραφή
|
||||
issues.due_date_not_writer=Χρειάζεστε πρόσβαση εγγραφής στο αποθετήριο για να ενημερώσετε την ημερομηνία λήξης ενός προβλήματος.
|
||||
issues.due_date_not_set=Δεν ορίστηκε ημερομηνία παράδοσης.
|
||||
issues.due_date_added=πρόσθεσε την ημερομηνία παράδοσης %s %s
|
||||
issues.due_date_modified=τροποποίησε την ημερομηνία παράδοσης από %[2]s σε %[1]s %[3]s
|
||||
@ -1875,7 +1871,6 @@ activity.title.releases_1=%d Κυκλοφορία
|
||||
activity.title.releases_n=%d Εκδόσεις
|
||||
activity.title.releases_published_by=%s δημοσιεύτηκε από %s
|
||||
activity.published_release_label=Δημοσιεύθηκε
|
||||
activity.no_git_activity=Δεν έχει υπάρξει καμία δραστηριότητα υποβολών σε αυτήν την περίοδο.
|
||||
activity.git_stats_exclude_merges=Εκτός τις συγχωνεύσεις,
|
||||
activity.git_stats_author_1=%d συγγραφέας
|
||||
activity.git_stats_author_n=%d συγγραφείς
|
||||
|
@ -117,7 +117,7 @@ files = Files
|
||||
|
||||
error = Error
|
||||
error404 = The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it.
|
||||
error503 = The server was unable to complete your request. Please try again later.
|
||||
error503 = The server could not complete your request. Please try again later.
|
||||
go_back = Go Back
|
||||
invalid_data = Invalid data: %v
|
||||
|
||||
@ -131,7 +131,7 @@ unpin = Unpin
|
||||
|
||||
artifacts = Artifacts
|
||||
expired = Expired
|
||||
confirm_delete_artifact = Are you sure you want to delete the artifact '%s' ?
|
||||
confirm_delete_artifact = Are you sure you want to delete the artifact '%s'?
|
||||
|
||||
archived = Archived
|
||||
|
||||
@ -171,7 +171,7 @@ internal_error_skipped = Internal error occurred but is skipped: %s
|
||||
search = Search...
|
||||
type_tooltip = Search type
|
||||
fuzzy = Fuzzy
|
||||
fuzzy_tooltip = Include results that also match the search term closely
|
||||
fuzzy_tooltip = Include results that closely match the search term
|
||||
words = Words
|
||||
words_tooltip = Include only results that match the search term words
|
||||
regexp = Regexp
|
||||
@ -506,7 +506,7 @@ activate_email.text = Please click the following link to verify your email addre
|
||||
|
||||
register_notify = Welcome to %s
|
||||
register_notify.title = %[1]s, welcome to %[2]s
|
||||
register_notify.text_1 = this is your registration confirmation email for %s!
|
||||
register_notify.text_1 = This is your registration confirmation email for %s!
|
||||
register_notify.text_2 = You can now login via username: %s.
|
||||
register_notify.text_3 = If this account has been created for you, please <a href="%s">set your password</a> first.
|
||||
|
||||
@ -998,7 +998,7 @@ webauthn_alternative_tip = You may want to configure an additional authenticatio
|
||||
|
||||
manage_account_links = Manage Linked Accounts
|
||||
manage_account_links_desc = These external accounts are linked to your Gitea account.
|
||||
account_links_not_available = There are currently no external accounts linked to your Gitea account.
|
||||
account_links_not_available = No external accounts are currently linked to your Gitea account.
|
||||
link_account = Link Account
|
||||
remove_account_link = Remove Linked Account
|
||||
remove_account_link_desc = Removing a linked account will revoke its access to your Gitea account. Continue?
|
||||
@ -1035,8 +1035,8 @@ new_repo_helper = A repository contains all project files, including revision hi
|
||||
owner = Owner
|
||||
owner_helper = Some organizations may not show up in the dropdown due to a maximum repository count limit.
|
||||
repo_name = Repository Name
|
||||
repo_name_profile_public_hint= .profile is a special repository that you can use to add README.md to your public organization profile, visible to anyone. Make sure it’s public and initialize it with a README in the profile directory to get started.
|
||||
repo_name_profile_private_hint = .profile-private is a special repository that you can use to add a README.md to your organization member profile, visible only to organization members. Make sure it’s private and initialize it with a README in the profile directory to get started.
|
||||
repo_name_profile_public_hint= .profile is a special repository that you can use to add README.md to your public organization profile, visible to anyone. Make sure it's public and initialize it with a README in the profile directory to get started.
|
||||
repo_name_profile_private_hint = .profile-private is a special repository that you can use to add a README.md to your organization member profile, visible only to organization members. Make sure it's private and initialize it with a README in the profile directory to get started.
|
||||
repo_name_helper = Good repository names use short, memorable and unique keywords. A repository named ".profile" or ".profile-private" could be used to add a README.md for the user/organization profile.
|
||||
repo_size = Repository Size
|
||||
template = Template
|
||||
@ -1058,7 +1058,7 @@ fork_branch = Branch to be cloned to the fork
|
||||
all_branches = All branches
|
||||
view_all_branches = View all branches
|
||||
view_all_tags = View all tags
|
||||
fork_no_valid_owners = This repository can not be forked because there are no valid owners.
|
||||
fork_no_valid_owners = This repository cannot be forked because there are no valid owners.
|
||||
fork.blocked_user = Cannot fork the repository because you are blocked by the repository owner.
|
||||
use_template = Use this template
|
||||
open_with_editor = Open with %s
|
||||
@ -1755,7 +1755,7 @@ issues.due_date_form = "yyyy-mm-dd"
|
||||
issues.due_date_form_add = "Add due date"
|
||||
issues.due_date_form_edit = "Edit"
|
||||
issues.due_date_form_remove = "Remove"
|
||||
issues.due_date_not_writer = "You need write access to this repository in order to update the due date of an issue."
|
||||
issues.due_date_not_writer = "You need write access to this repository to update the due date of an issue."
|
||||
issues.due_date_not_set = "No due date set."
|
||||
issues.due_date_added = "added the due date %s %s"
|
||||
issues.due_date_modified = "modified the due date from %[2]s to %[1]s %[3]s"
|
||||
@ -2123,7 +2123,7 @@ activity.title.releases_1 = %d Release
|
||||
activity.title.releases_n = %d Releases
|
||||
activity.title.releases_published_by = %s published by %s
|
||||
activity.published_release_label = Published
|
||||
activity.no_git_activity = There has not been any commit activity in this period.
|
||||
activity.no_git_activity = There has been no commit activity in this period.
|
||||
activity.git_stats_exclude_merges = Excluding merges,
|
||||
activity.git_stats_author_1 = %d author
|
||||
activity.git_stats_author_n = %d authors
|
||||
|
@ -424,7 +424,6 @@ activate_email.title=%s, por favor verifique su dirección de correo electrónic
|
||||
activate_email.text=Por favor, haga clic en el siguiente enlace para verificar su dirección de correo electrónico dentro de <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, bienvenido a %[2]s
|
||||
register_notify.text_1=este es tu correo de confirmación de registro para %s!
|
||||
register_notify.text_2=Ahora puede iniciar sesión vía nombre de usuario: %s.
|
||||
register_notify.text_3=Si esta cuenta ha sido creada para usted, por favor <a href="%s">establezca su contraseña</a> primero.
|
||||
|
||||
@ -862,7 +861,6 @@ webauthn_delete_key_desc=Si elimina una llave de seguridad ya no podrá utilizar
|
||||
|
||||
manage_account_links=Administrar cuentas vinculadas
|
||||
manage_account_links_desc=Estas cuentas externas están vinculadas a su cuenta de Gitea.
|
||||
account_links_not_available=Actualmente no hay cuentas externas vinculadas a su cuenta de Gitea.
|
||||
link_account=Enlazar cuenta
|
||||
remove_account_link=Eliminar cuenta vinculada
|
||||
remove_account_link_desc=Eliminar una cuenta vinculada revocará su acceso a su cuenta de Gitea. ¿Continuar?
|
||||
@ -916,7 +914,6 @@ fork_to_different_account=Forkear a una cuenta diferente
|
||||
fork_visibility_helper=La visibilidad de un repositorio del cual se ha hecho fork no puede ser cambiada.
|
||||
fork_branch=Rama a clonar en la bifurcación
|
||||
all_branches=Todas las ramas
|
||||
fork_no_valid_owners=Este repositorio no puede ser bifurcado porque no hay propietarios válidos.
|
||||
use_template=Utilizar esta plantilla
|
||||
download_zip=Descargar ZIP
|
||||
download_tar=Descargar TAR.GZ
|
||||
@ -1527,7 +1524,6 @@ issues.due_date_form=aaaa-mm-dd
|
||||
issues.due_date_form_add=Añadir fecha de vencimiento
|
||||
issues.due_date_form_edit=Editar
|
||||
issues.due_date_form_remove=Eliminar
|
||||
issues.due_date_not_writer=Necesita acceso de escritura a este repositorio para actualizar la fecha límite de de una incidencia.
|
||||
issues.due_date_not_set=Sin fecha de vencimiento.
|
||||
issues.due_date_added=añadió la fecha de vencimiento %s %s
|
||||
issues.due_date_modified=modificó la fecha de vencimiento de %[2]s a %[1]s %[3]s
|
||||
@ -1859,7 +1855,6 @@ activity.title.releases_1=%d Lanzamiento
|
||||
activity.title.releases_n=%d Lanzamientos
|
||||
activity.title.releases_published_by=%s publicado por %s
|
||||
activity.published_release_label=Publicado
|
||||
activity.no_git_activity=No ha habido ningún commit en este período.
|
||||
activity.git_stats_exclude_merges=Excluyendo fusiones,
|
||||
activity.git_stats_author_1=%d autor
|
||||
activity.git_stats_author_n=%d autores
|
||||
|
@ -332,7 +332,6 @@ activate_email=نشانی ایمیل خود را تایید کنید
|
||||
activate_email.text=لطفاً روی پیوند زیر کلیک کنید تا رایانامهی خود را در <b>%s</b> تأیید کنید:
|
||||
|
||||
register_notify.title=%[1]s، به %[2]s خوشآمدید
|
||||
register_notify.text_1=این رایانامهی تأیید عضویت شما در %s است!
|
||||
register_notify.text_2=حالا شما میتوانید با نام کاربری وارد شوید: %s.
|
||||
register_notify.text_3=اگر این حساب برای شما ایجاد شده، لطفاً ابتدا <a href="%s">گذرواژهی خود را تنظیم کنید</a>.
|
||||
|
||||
@ -675,7 +674,6 @@ twofa_failed_get_secret=خطا در دریافت رمز.
|
||||
|
||||
manage_account_links=مدیریت حساب های مرتبط شده
|
||||
manage_account_links_desc=این حساب های خارجی به حساب Gitea ارتباط دارد.
|
||||
account_links_not_available=اکنون دیگر هیچ پیوند حسابهای کاربری خارجی به حساب کاربری شما وجود ندارد.
|
||||
link_account=پیوند به حساب
|
||||
remove_account_link=حذف حساب پیوند خرده
|
||||
remove_account_link_desc=با حذف پیوند خارجی حساب کاربری دسترسی شما به حساب کابریتان توسط آن از بین میرود. آیا ادامه میدهید؟
|
||||
@ -1437,7 +1435,6 @@ activity.title.releases_1=%d انتشار
|
||||
activity.title.releases_n=%d انتشار
|
||||
activity.title.releases_published_by=%s منشتر شده توسط %s
|
||||
activity.published_release_label=منتشر شده
|
||||
activity.no_git_activity=در این دوره فعالیت کامیتی ارسال نشده است.
|
||||
activity.git_stats_exclude_merges=به استثنای ادغامها ،
|
||||
activity.git_stats_author_1=%d بانی
|
||||
activity.git_stats_author_n=%d بانی
|
||||
|
@ -117,7 +117,6 @@ files=Fichiers
|
||||
|
||||
error=Erreur
|
||||
error404=La page que vous essayez d'atteindre <strong>n'existe pas</strong> ou <strong>vous n'êtes pas autorisé</strong> à la voir.
|
||||
error503=Le serveur n’a pas pu répondre à votre requête. Veuillez réessayer plus tard.
|
||||
go_back=Retour
|
||||
invalid_data=Données invalides : %v
|
||||
|
||||
@ -131,7 +130,6 @@ unpin=Désépingler
|
||||
|
||||
artifacts=Artefacts
|
||||
expired=Expiré
|
||||
confirm_delete_artifact=Êtes-vous sûr de vouloir supprimer l‘artefact « %s » ?
|
||||
|
||||
archived=Archivé
|
||||
|
||||
@ -171,7 +169,6 @@ internal_error_skipped=Une erreur interne est survenue, mais ignorée : %s
|
||||
search=Rechercher…
|
||||
type_tooltip=Type de recherche
|
||||
fuzzy=Approximative
|
||||
fuzzy_tooltip=Inclure également les résultats proches de la recherche
|
||||
words=Mots
|
||||
words_tooltip=Inclure uniquement les résultats qui correspondent exactement aux mots recherchés
|
||||
regexp=Regexp
|
||||
@ -506,7 +503,6 @@ activate_email.text=Veuillez cliquer sur le lien suivant pour vérifier votre ad
|
||||
|
||||
register_notify=Bienvenue sur %s
|
||||
register_notify.title=%[1]s, bienvenue à %[2]s
|
||||
register_notify.text_1=ceci est votre courriel de confirmation d'inscription pour %s!
|
||||
register_notify.text_2=Vous pouvez maintenant vous connecter avec le nom d'utilisateur : %s.
|
||||
register_notify.text_3=Si ce compte a été créé pour vous, veuillez <a href="%s">définir votre mot de passe</a> d'abord.
|
||||
|
||||
@ -998,7 +994,6 @@ webauthn_alternative_tip=Vous devriez configurer une méthode d’authentificati
|
||||
|
||||
manage_account_links=Gérer les comptes liés
|
||||
manage_account_links_desc=Ces comptes externes sont liés à votre compte Gitea.
|
||||
account_links_not_available=Il n'y a pour l'instant pas de compte externe connecté à votre compte Gitea.
|
||||
link_account=Lier un Compte
|
||||
remove_account_link=Supprimer un compte lié
|
||||
remove_account_link_desc=La suppression d'un compte lié révoquera son accès à votre compte Gitea. Continuer ?
|
||||
@ -1035,8 +1030,6 @@ new_repo_helper=Un dépôt contient tous les fichiers d’un projet, ainsi que l
|
||||
owner=Propriétaire
|
||||
owner_helper=Certaines organisations peuvent ne pas apparaître dans la liste déroulante en raison d'une limite maximale du nombre de dépôts.
|
||||
repo_name=Nom du dépôt
|
||||
repo_name_profile_public_hint=.profile est un dépôt spécial que vous pouvez utiliser pour ajouter un README.md à votre profil public d’organisation, visible à tout le monde. Assurez-vous qu’il soit public et initialisez-le avec un README dans le répertoire de profil pour commencer.
|
||||
repo_name_profile_private_hint=.profile-private est un dépôt spécial que vous pouvez utiliser pour ajouter un README.md à votre profil d’organisation, visible uniquement aux membres de l’organisation. Assurez-vous qu’il soit privé et initialisez-le avec un README dans le répertoire de profil pour commencer.
|
||||
repo_name_helper=Idéalement, le nom d’un dépôt devrait être court, mémorisable et unique. Vous pouvez personnaliser votre profil ou celui de votre organisation en créant un dépôt nommé « .profile » ou « .profile-private » et contenant un README.md.
|
||||
repo_size=Taille du dépôt
|
||||
template=Modèle
|
||||
@ -1058,7 +1051,6 @@ fork_branch=Branche à cloner sur la bifurcation
|
||||
all_branches=Toutes les branches
|
||||
view_all_branches=Voir toutes les branches
|
||||
view_all_tags=Voir toutes les étiquettes
|
||||
fork_no_valid_owners=Ce dépôt ne peut pas être bifurqué car il n’a pas de propriétaire valide.
|
||||
fork.blocked_user=Impossible de bifurquer le dépôt car vous êtes bloqué par son propriétaire.
|
||||
use_template=Utiliser ce modèle
|
||||
open_with_editor=Ouvrir avec %s
|
||||
@ -1755,7 +1747,6 @@ issues.due_date_form=aaaa-mm-jj
|
||||
issues.due_date_form_add=Ajouter une échéance
|
||||
issues.due_date_form_edit=Éditer
|
||||
issues.due_date_form_remove=Supprimer
|
||||
issues.due_date_not_writer=Vous avez besoin d’un accès en écriture à ce dépôt pour modifier l’échéance de ses tickets.
|
||||
issues.due_date_not_set=Aucune échéance n'a été définie.
|
||||
issues.due_date_added=a ajouté l'échéance %s %s
|
||||
issues.due_date_modified=a modifié l'échéance de %[2]s à %[1]s %[3]s
|
||||
@ -2123,7 +2114,6 @@ activity.title.releases_1=%d publication
|
||||
activity.title.releases_n=%d publications
|
||||
activity.title.releases_published_by=%s publiée par %s
|
||||
activity.published_release_label=Publiée
|
||||
activity.no_git_activity=Il n'y a pas eu de nouvelle révision dans cette période.
|
||||
activity.git_stats_exclude_merges=En excluant les fusions,
|
||||
activity.git_stats_author_1=%d auteur
|
||||
activity.git_stats_author_n=%d auteurs
|
||||
|
@ -117,7 +117,6 @@ files=Comhaid
|
||||
|
||||
error=Earráid
|
||||
error404=Níl an leathanach atá tú ag iarraidh a bhaint amach <strong>ann</strong> nó <strong>níl tú údaraithe</strong> chun é a fheiceáil.
|
||||
error503=Níorbh fhéidir leis an bhfreastalaí d'iarratas a chur i gcrích. Bain triail eile as ar ball.
|
||||
go_back=Ar ais
|
||||
invalid_data=Sonraí neamhbhailí: %v
|
||||
|
||||
@ -131,7 +130,6 @@ unpin=Díphoráil
|
||||
|
||||
artifacts=Déantáin
|
||||
expired=Imithe in éag
|
||||
confirm_delete_artifact=An bhfuil tú cinnte gur mhaith leat an déantán '%s' a scriosadh?
|
||||
|
||||
archived=Cartlann
|
||||
|
||||
@ -171,7 +169,6 @@ internal_error_skipped=Tharla earráid inmheánach ach éirithe as: %s
|
||||
search=Cuardaigh...
|
||||
type_tooltip=Cineál cuardaigh
|
||||
fuzzy=Doiléir
|
||||
fuzzy_tooltip=Cuir san áireamh torthaí a mheaitseálann an téarma cuardaigh go dlúth freisin
|
||||
words=Focail
|
||||
words_tooltip=Ná cuir san áireamh ach torthaí a mheaitseálann na focail téarma cuardaigh
|
||||
regexp=Nathanna Rialta
|
||||
@ -506,7 +503,6 @@ activate_email.text=Cliceáil ar an nasc seo a leanas le do sheoladh ríomhphois
|
||||
|
||||
register_notify=Fáilte go dtí %s
|
||||
register_notify.title=%[1]s, fáilte go %[2]s
|
||||
register_notify.text_1=is é seo do ríomhphost deimhnithe clárúcháin do %s!
|
||||
register_notify.text_2=Is féidir leat logáil isteach anois trí ainm úsáideora: %s.
|
||||
register_notify.text_3=Má cruthaíodh an cuntas seo duit, <a href="%s">socraigh do phasfhocal</a> ar dtús.
|
||||
|
||||
@ -998,7 +994,6 @@ webauthn_alternative_tip=B'fhéidir gur mhaith leat modh fíordheimhnithe breise
|
||||
|
||||
manage_account_links=Bainistigh Cuntais Nasctha
|
||||
manage_account_links_desc=Tá na cuntais sheachtracha seo nasctha le do chuntas Gitea.
|
||||
account_links_not_available=Níl aon chuntais sheachtracha nasctha le do chuntas Gitea faoi láthair.
|
||||
link_account=Cuntas Nasc
|
||||
remove_account_link=Bain Cuntas Nasctha
|
||||
remove_account_link_desc=Ag baint cuntas nasctha, cuirfear a rochtain ar do chuntas Gitea a chúlghairm. Lean ar aghaidh?
|
||||
@ -1035,8 +1030,6 @@ new_repo_helper=Tá gach comhad tionscadail i stór, lena n-áirítear stair ath
|
||||
owner=Úinéir
|
||||
owner_helper=B'fhéidir nach dtaispeánfar roinnt eagraíochtaí sa anuas mar gheall ar theorainn uasta comhaireamh stórais.
|
||||
repo_name=Ainm Stórais
|
||||
repo_name_profile_public_hint=Is stóras speisialta é .profile is féidir leat a úsáid chun README.md a chur le do phróifíl eagraíochta poiblí, le feiceáil ag aon duine. Cinntigh go bhfuil sé poiblí agus tosaigh é le README san eolaire próifíle le tosú.
|
||||
repo_name_profile_private_hint=Is stóras speisialta é .profile-private is féidir leat a úsáid chun README.md a chur le do phróifíl bhall eagraíochta, nach féidir a fheiceáil ach ag baill eagraíochta. Cinntigh go bhfuil sé príobháideach agus tosaigh le README sa eolaire próifíle chun tús a chur leis.
|
||||
repo_name_helper=Úsáideann ainmneacha maith stóras focail eochair gairide, áithnid agus uathúla. D'fhéadfaí stóras darbh ainm '.profile' nó '.profile-private' a úsáid chun README.md a chur leis an bpróifíl úsáideora/eagraíochta.
|
||||
repo_size=Méid an Stóras
|
||||
template=Teimpléad
|
||||
@ -1058,7 +1051,6 @@ fork_branch=Brainse le clónú chuig an bhforc
|
||||
all_branches=Gach brainse
|
||||
view_all_branches=Féach ar gach brainse
|
||||
view_all_tags=Féach ar gach clib
|
||||
fork_no_valid_owners=Ní féidir an stór seo a fhorcáil toisc nach bhfuil úinéirí bailí ann.
|
||||
fork.blocked_user=Ní féidir an stór a fhorcáil toisc go bhfuil úinéir an stórais bac ort.
|
||||
use_template=Úsáid an teimpléad seo
|
||||
open_with_editor=Oscail le %s
|
||||
@ -1755,7 +1747,6 @@ issues.due_date_form=bbbb-mm-ll
|
||||
issues.due_date_form_add=Cuir dáta dlite leis
|
||||
issues.due_date_form_edit=Cuir in eagar
|
||||
issues.due_date_form_remove=Bain
|
||||
issues.due_date_not_writer=Ní mór duit rochtain scríofa ar an stór seo d'fhonn dáta dlite eisiúna a nuashonrú.
|
||||
issues.due_date_not_set=Níl aon dáta dlite socraithe.
|
||||
issues.due_date_added=cuireadh an dáta dlite %s %s
|
||||
issues.due_date_modified=d'athraigh an dáta dlite ó %[2]s go %[1]s %[3]s
|
||||
@ -2123,7 +2114,6 @@ activity.title.releases_1=Scaoileadh %d
|
||||
activity.title.releases_n=Eisiúintí %d
|
||||
activity.title.releases_published_by=%s foilsithe ag %s
|
||||
activity.published_release_label=Foilsithe
|
||||
activity.no_git_activity=Níor rinneadh aon ghníomhaíocht tiomanta sa tréimhse seo.
|
||||
activity.git_stats_exclude_merges=Gan cumaisc a áireamh,
|
||||
activity.git_stats_author_1=%d údar
|
||||
activity.git_stats_author_n=%d údair
|
||||
|
@ -1017,7 +1017,6 @@ activity.title.releases_1=%d Kiadás
|
||||
activity.title.releases_n=%d Kiadások
|
||||
activity.title.releases_published_by=%s publikálta %s
|
||||
activity.published_release_label=Publikálva
|
||||
activity.no_git_activity=Nem voltak commit-ok ebben az időszakban.
|
||||
activity.git_stats_commit_1=%d commit
|
||||
activity.git_stats_commit_n=%d commit
|
||||
activity.git_stats_file_n=%d fájl
|
||||
|
@ -117,7 +117,6 @@ pin=Sematkan
|
||||
unpin=Lepas sematan
|
||||
|
||||
artifacts=Artefak
|
||||
confirm_delete_artifact=Apakah Anda yakin ingin menghapus artefak '%s' ?
|
||||
|
||||
archived=Diarsipkan
|
||||
|
||||
@ -147,7 +146,6 @@ no_results_found=Hasil tidak ditemukan.
|
||||
[search]
|
||||
search=Cari...
|
||||
type_tooltip=Tipe pencarian
|
||||
fuzzy_tooltip=Termasuk juga hasil yang mendekati kata pencarian
|
||||
exact_tooltip=Hanya menampilkan hasil yang cocok dengan istilah pencarian
|
||||
repo_kind=Cari repo...
|
||||
user_kind=Telusuri pengguna...
|
||||
@ -561,7 +559,6 @@ passcode_invalid=Kode sandi salah. Coba lagi.
|
||||
|
||||
manage_account_links=Kelola akun tertaut
|
||||
manage_account_links_desc=Semua akun eksternal ini sementara tertaut dengan akun Gitea Anda.
|
||||
account_links_not_available=Saat ini tidak ada akun eksternal yang tertaut ke akun Gitea ini.
|
||||
link_account=Tautan Akun
|
||||
remove_account_link=Hapus Akun Tertaut
|
||||
remove_account_link_desc=Menghapus akun tertaut akan membuat akun itu tidak bisa mengakses akun Gitea Anda. Lanjutkan?
|
||||
|
@ -298,7 +298,6 @@ activate_email=Staðfestu netfangið þitt
|
||||
activate_email.text=Vinsamlegast smelltu á eftirfarandi tengil til að staðfesta netfangið þitt innan <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, velkomin(n) í %[2]s
|
||||
register_notify.text_1=þetta er staðfestingarpóstur þinn fyrir skráningu á %s!
|
||||
register_notify.text_2=Þú getur nú skráð þig inn með notandanafni: %s.
|
||||
register_notify.text_3=Ef þessi reikningur hefur verið búinn til fyrir þig, vinsamlegast <a href="%s">stilltu lykilorðið þitt</a> fyrst.
|
||||
|
||||
|
@ -356,7 +356,6 @@ activate_email=Verifica il tuo indirizzo e-mail
|
||||
activate_email.text=Clicca sul seguente link per verificare il tuo indirizzo email entro <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, benvenuto in %[2]s
|
||||
register_notify.text_1=questa è la tua email di conferma di registrazione per %s!
|
||||
register_notify.text_2=Ora è possibile accedere tramite nome utente: %s.
|
||||
register_notify.text_3=Se questo account è stato creato per te, per favore <a href="%s">imposta prima la tua password</a>.
|
||||
|
||||
@ -725,7 +724,6 @@ webauthn_delete_key_desc=Se si rimuove una chiave di sicurezza non è più possi
|
||||
|
||||
manage_account_links=Gestisci gli account collegati
|
||||
manage_account_links_desc=Questi account esterni sono collegati al tuo account Gitea.
|
||||
account_links_not_available=Attualmente non è collegato alcun account esterno al tuo account Gitea.
|
||||
link_account=Collega Account
|
||||
remove_account_link=Rimuovi account collegato
|
||||
remove_account_link_desc=Rimuovere un account collegato ne revoca l'accesso al tuo account Gitea. Continuare?
|
||||
@ -1555,7 +1553,6 @@ activity.title.releases_1=%d Release
|
||||
activity.title.releases_n=%d Release
|
||||
activity.title.releases_published_by=%s pubblicata da %s
|
||||
activity.published_release_label=Pubblicata
|
||||
activity.no_git_activity=In questo periodo non c'è stata alcuna attività di commit.
|
||||
activity.git_stats_exclude_merges=Escludendo i merge,
|
||||
activity.git_stats_author_1=%d autore
|
||||
activity.git_stats_author_n=%d autori
|
||||
|
@ -117,7 +117,6 @@ files=ファイル
|
||||
|
||||
error=エラー
|
||||
error404=アクセスしようとしたページは<strong>存在しない</strong>か、閲覧が<strong>許可されていません</strong>。
|
||||
error503=サーバーはリクエストを完了できませんでした。 後でもう一度お試しください。
|
||||
go_back=戻る
|
||||
invalid_data=無効なデータ: %v
|
||||
|
||||
@ -131,7 +130,6 @@ unpin=ピン留め解除
|
||||
|
||||
artifacts=成果物
|
||||
expired=期限切れ
|
||||
confirm_delete_artifact=アーティファクト %s を削除してよろしいですか?
|
||||
|
||||
archived=アーカイブ
|
||||
|
||||
@ -171,7 +169,6 @@ internal_error_skipped=内部エラーが発生しましたがスキップされ
|
||||
search=検索…
|
||||
type_tooltip=検索タイプ
|
||||
fuzzy=あいまい
|
||||
fuzzy_tooltip=検索語におおよそ一致する結果も含めます
|
||||
words=単語
|
||||
words_tooltip=検索語と一致する結果だけを含めます
|
||||
regexp=正規表現
|
||||
@ -506,7 +503,6 @@ activate_email.text=あなたのメールアドレスを確認するため、<b>
|
||||
|
||||
register_notify=%s へようこそ
|
||||
register_notify.title=%[1]s さん、%[2]s にようこそ
|
||||
register_notify.text_1=これは %s への登録確認メールです!
|
||||
register_notify.text_2=あなたはユーザー名 %s でログインできるようになりました。
|
||||
register_notify.text_3=このアカウントがあなたに作成されたものであれば、最初に<a href="%s">パスワードを設定</a>してください。
|
||||
|
||||
@ -998,7 +994,6 @@ webauthn_alternative_tip=もうひとつ別の認証方法も設定しておく
|
||||
|
||||
manage_account_links=連携アカウントの管理
|
||||
manage_account_links_desc=これらの外部アカウントがGiteaアカウントと連携されています。
|
||||
account_links_not_available=現在このGiteaアカウントが連携している外部アカウントはありません。
|
||||
link_account=アカウントをリンク
|
||||
remove_account_link=連携アカウントの削除
|
||||
remove_account_link_desc=連携アカウントを削除し、Giteaアカウントへのアクセス権を取り消します。 続行しますか?
|
||||
@ -1035,8 +1030,6 @@ new_repo_helper=リポジトリには、プロジェクトのすべてのファ
|
||||
owner=オーナー
|
||||
owner_helper=リポジトリ数の上限により、一部の組織はドロップダウンに表示されない場合があります。
|
||||
repo_name=リポジトリ名
|
||||
repo_name_profile_public_hint=.profile は特別なリポジトリで、これを使用して、あなたの組織の公開プロフィール(誰でも閲覧可能)に README.md を追加することができます。 利用を開始するには、必ず公開リポジトリとし、プロフィールディレクトリにREADMEを追加して初期化してください。
|
||||
repo_name_profile_private_hint=.profile-private は特別なリポジトリで、これを使用して、あなたの組織のメンバー向けプロフィール(組織メンバーのみ閲覧可能)に README.md を追加することができます。 利用を開始するには、必ずプライベートリポジトリとし、プロフィールディレクトリにREADMEを追加して初期化してください。
|
||||
repo_name_helper=リポジトリ名は、短く、覚えやすく、他と重複しないキーワードを使用しましょう。 リポジトリ名を ".profile" または ".profile-private" にして README.md を追加すると、ユーザーや組織のプロフィールとなります。
|
||||
repo_size=リポジトリサイズ
|
||||
template=テンプレート
|
||||
@ -1058,7 +1051,6 @@ fork_branch=フォークにクローンされるブランチ
|
||||
all_branches=すべてのブランチ
|
||||
view_all_branches=すべてのブランチを表示
|
||||
view_all_tags=すべてのタグを表示
|
||||
fork_no_valid_owners=このリポジトリには有効なオーナーがいないため、フォークできません。
|
||||
fork.blocked_user=リポジトリのオーナーがあなたをブロックしているため、リポジトリをフォークできません。
|
||||
use_template=このテンプレートを使用
|
||||
open_with_editor=%s で開く
|
||||
@ -1746,7 +1738,6 @@ issues.due_date_form=yyyy-mm-dd
|
||||
issues.due_date_form_add=期日の追加
|
||||
issues.due_date_form_edit=変更
|
||||
issues.due_date_form_remove=削除
|
||||
issues.due_date_not_writer=イシューの期日を変更するには、リポジトリへの書き込み権限が必要です。
|
||||
issues.due_date_not_set=期日は設定されていません。
|
||||
issues.due_date_added=が期日 %s を追加 %s
|
||||
issues.due_date_modified=が期日を %[2]s から %[1]s に変更 %[3]s
|
||||
@ -2113,7 +2104,6 @@ activity.title.releases_1=%d件のリリース
|
||||
activity.title.releases_n=%d件のリリース
|
||||
activity.title.releases_published_by=%sが%sによって発行されました
|
||||
activity.published_release_label=発行
|
||||
activity.no_git_activity=この期間にはコミットのアクティビティがありません。
|
||||
activity.git_stats_exclude_merges=マージを除くと、
|
||||
activity.git_stats_author_1=%d人の作成者
|
||||
activity.git_stats_author_n=%d人の作成者
|
||||
|
@ -510,7 +510,6 @@ twofa_enrolled=당신의 계정에 2단계 인증이 설정되었습니다. 스
|
||||
|
||||
manage_account_links=연결된 계정 관리
|
||||
manage_account_links_desc=Gitea 계정에 연결된 외부 계정입니다.
|
||||
account_links_not_available=현재 Gitea 계정에 연결된 외부 계정이 없습니다.
|
||||
link_account=계정 연결
|
||||
remove_account_link=연결된 계정 제거
|
||||
remove_account_link_desc=해당 계정을 연결해제 하는 경우 Gitea 계정에 대한 접근 권한이 사라지게 됩니다. 계속하시겠습니까?
|
||||
|
@ -430,7 +430,6 @@ activate_email.title=%s, apstipriniet savu e-pasta adresi
|
||||
activate_email.text=Nospiediet uz saites, lai apstiprinātu savu e-pasta adresi lapā <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, esat reģistrējies %[2]s
|
||||
register_notify.text_1=šis ir reģistrācijas apstiprinājuma e-pasts lapai %s!
|
||||
register_notify.text_2=Tagad varat autorizēties ar lietotāja vārdu: %s.
|
||||
register_notify.text_3=Ja šis konts Jums tika izveidots, tad obligāti <a href="%s">nomainiet citu paroli</a>.
|
||||
|
||||
@ -876,7 +875,6 @@ webauthn_alternative_tip=Ir vēlams uzstādīt papildu autentifikācijas veidu.
|
||||
|
||||
manage_account_links=Pārvaldīt saistītos kontus
|
||||
manage_account_links_desc=Šādi ārējie konti ir piesaistīti Jūsu Gitea kontam.
|
||||
account_links_not_available=Pašlaik nav neviena ārējā konta piesaistīta šim kontam.
|
||||
link_account=Sasaistīt kontu
|
||||
remove_account_link=Noņemt saistīto kontu
|
||||
remove_account_link_desc=Noņemot saistīto kontu, tam tiks liegta piekļuve Jūsu Gitea kontam. Vai turpināt?
|
||||
@ -931,7 +929,6 @@ fork_to_different_account=Atdalīt uz citu kontu
|
||||
fork_visibility_helper=Atdalītam repozitorijam nav iespējams mainīt tā redzamību.
|
||||
fork_branch=Atzars, ko klonēt atdalītajā repozitorijā
|
||||
all_branches=Visi atzari
|
||||
fork_no_valid_owners=Šim repozitorijam nevar izveidot atdalītu repozitoriju, jo tam nav spēkā esošu īpašnieku.
|
||||
use_template=Izmantot šo sagatavi
|
||||
download_zip=Lejupielādēt ZIP
|
||||
download_tar=Lejupielādēt TAR.GZ
|
||||
@ -1543,7 +1540,6 @@ issues.due_date_form=dd.mm.yyyy
|
||||
issues.due_date_form_add=Pievienot izpildes termiņu
|
||||
issues.due_date_form_edit=Labot
|
||||
issues.due_date_form_remove=Noņemt
|
||||
issues.due_date_not_writer=Ir nepieciešama rakstīšanas piekļuve šim repozitorijam, lai varētu mainīt problēmas plānoto izpildes datumu.
|
||||
issues.due_date_not_set=Izpildes termiņš nav uzstādīts.
|
||||
issues.due_date_added=pievienoja izpildes termiņu %s %s
|
||||
issues.due_date_modified=mainīja termiņa datumu no %[2]s uz %[1]s %[3]s
|
||||
@ -1881,7 +1877,6 @@ activity.title.releases_1=%d versiju
|
||||
activity.title.releases_n=%d versijas
|
||||
activity.title.releases_published_by=%s publicēja %s
|
||||
activity.published_release_label=Publicēts
|
||||
activity.no_git_activity=Šajā laika periodā nav notikušas nekādas izmaiņas.
|
||||
activity.git_stats_exclude_merges=Neskaitot sapludināšanas revīzijas,
|
||||
activity.git_stats_author_1=%d autors
|
||||
activity.git_stats_author_n=%d autori
|
||||
|
@ -355,7 +355,6 @@ activate_email=Verifieer uw e-mailadres
|
||||
activate_email.text=Klik op de volgende link om je e-mailadres te bevestigen in <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, welkom bij %[2]s
|
||||
register_notify.text_1=dit is uw registratie bevestigingsemail voor %s!
|
||||
register_notify.text_2=U kunt nu inloggen via de gebruikersnaam: %s.
|
||||
register_notify.text_3=Als dit account voor u is aangemaakt, kunt u eerst <a href="%s">uw wachtwoord instellen</a>.
|
||||
|
||||
@ -723,7 +722,6 @@ webauthn_delete_key_desc=Als u een beveiligingssleutel verwijdert, kunt u er nie
|
||||
|
||||
manage_account_links=Gekoppelde accounts beheren
|
||||
manage_account_links_desc=Deze externe accounts zijn gekoppeld aan je Gitea-account.
|
||||
account_links_not_available=Er zijn momenteel geen externe accounts aan je Gitea-account gelinkt.
|
||||
link_account=Account koppelen
|
||||
remove_account_link=Gekoppeld account verwijderen
|
||||
remove_account_link_desc=Als je een gekoppeld account verwijdert, verliest dit account toegang tot je Gitea-account. Doorgaan?
|
||||
@ -1550,7 +1548,6 @@ activity.title.releases_1=%d Release
|
||||
activity.title.releases_n=%d Releases
|
||||
activity.title.releases_published_by=%s gepubliceerd door %s
|
||||
activity.published_release_label=Gepubliceerd
|
||||
activity.no_git_activity=Er is in deze periode geen sprake geweest van een commit activiteit.
|
||||
activity.git_stats_exclude_merges=Exclusief merges,
|
||||
activity.git_stats_author_1=%d auteur
|
||||
activity.git_stats_author_n=%d auteurs
|
||||
|
@ -348,7 +348,6 @@ activate_email=Potwierdź swój adres e-mail
|
||||
activate_email.text=Aby zweryfikować swój adres e-mail, w ciągu następnych <b>%s</b> kliknij poniższy link:
|
||||
|
||||
register_notify.title=%[1]s, witaj w %[2]s
|
||||
register_notify.text_1=to jest Twój e-mail z potwierdzeniem rejestracji dla %s!
|
||||
register_notify.text_2=Możesz teraz zalogować się za pomocą nazwy użytkownika: %s.
|
||||
register_notify.text_3=Jeśli to konto zostało utworzone dla Ciebie, <a href="%s">ustaw swoje hasło</a>.
|
||||
|
||||
@ -682,7 +681,6 @@ webauthn_delete_key_desc=Jeżeli usuniesz klucz bezpieczeństwa, utracisz możli
|
||||
|
||||
manage_account_links=Zarządzaj powiązanymi kontami
|
||||
manage_account_links_desc=Te konta zewnętrzne są powiązane z Twoim kontem Gitea.
|
||||
account_links_not_available=Obecnie nie ma żadnych zewnętrznych kont powiązanych z tym kontem Gitea.
|
||||
link_account=Powiąż konto
|
||||
remove_account_link=Usuń powiązane konto
|
||||
remove_account_link_desc=Usunięcie powiązanego konta unieważni jego dostęp do Twojego konta Gitea. Kontynuować?
|
||||
@ -1405,7 +1403,6 @@ activity.title.releases_1=%d Wydanie
|
||||
activity.title.releases_n=%d Wydań
|
||||
activity.title.releases_published_by=%s opublikowane przez %s
|
||||
activity.published_release_label=Opublikowane
|
||||
activity.no_git_activity=Nie było żadnej aktywności w tym okresie czasu.
|
||||
activity.git_stats_exclude_merges=Wykluczając scalenia,
|
||||
activity.git_stats_author_1=%d autor
|
||||
activity.git_stats_author_n=%d autorzy
|
||||
|
@ -123,7 +123,6 @@ pin=Fixar
|
||||
unpin=Desfixar
|
||||
|
||||
artifacts=Artefatos
|
||||
confirm_delete_artifact=Tem certeza que deseja excluir o artefato '%s' ?
|
||||
|
||||
archived=Arquivado
|
||||
|
||||
@ -428,7 +427,6 @@ activate_email.title=%s, por favor verifique o seu endereço de e-mail
|
||||
activate_email.text=Por favor clique no link a seguir para verificar o seu endereço de e-mail em <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, bem-vindo(a) a %[2]s
|
||||
register_notify.text_1=este é o seu e-mail de confirmação de registro para %s!
|
||||
register_notify.text_2=Agora você pode entrar com o nome de usuário: %s.
|
||||
register_notify.text_3=Se esta conta foi criada para você, <a href="%s">defina sua senha</a> primeiro.
|
||||
|
||||
@ -871,7 +869,6 @@ webauthn_alternative_tip=Você pode querer configurar um método de autenticaç
|
||||
|
||||
manage_account_links=Gerenciar contas vinculadas
|
||||
manage_account_links_desc=Estas contas externas estão vinculadas a sua conta de Gitea.
|
||||
account_links_not_available=Não existem contas externas atualmente vinculadas a esta conta.
|
||||
link_account=Vincular Conta
|
||||
remove_account_link=Remover conta vinculada
|
||||
remove_account_link_desc=A exclusão da chave SSH revogará o acesso à sua conta. Continuar?
|
||||
@ -926,7 +923,6 @@ fork_to_different_account=Faça um fork para uma conta diferente
|
||||
fork_visibility_helper=A visibilidade do fork de um repositório não pode ser alterada.
|
||||
fork_branch=Branch a ser clonado para o fork
|
||||
all_branches=Todos os branches
|
||||
fork_no_valid_owners=Não é possível fazer um fork desse repositório porque não há proprietários validos.
|
||||
use_template=Usar este modelo
|
||||
download_zip=Baixar ZIP
|
||||
download_tar=Baixar TAR.GZ
|
||||
@ -1536,7 +1532,6 @@ issues.due_date_form=dd/mm/aaaa
|
||||
issues.due_date_form_add=Adicionar data limite
|
||||
issues.due_date_form_edit=Editar
|
||||
issues.due_date_form_remove=Remover
|
||||
issues.due_date_not_writer=Você precisa de acesso de gravação a esse repositório para atualizar a data limite de uma issue.
|
||||
issues.due_date_not_set=Data limite não informada.
|
||||
issues.due_date_added=adicionou a data limite %s %s
|
||||
issues.due_date_modified=modificou a data limite de %[2]s para %[1]s %[3]s
|
||||
@ -1874,7 +1869,6 @@ activity.title.releases_1=%d Versão
|
||||
activity.title.releases_n=%d Versões
|
||||
activity.title.releases_published_by=%s publicada(s) por %s
|
||||
activity.published_release_label=Publicado
|
||||
activity.no_git_activity=Não houve nenhuma atividade de commit neste período.
|
||||
activity.git_stats_exclude_merges=Excluindo merges,
|
||||
activity.git_stats_author_1=%d autor
|
||||
activity.git_stats_author_n=%d autores
|
||||
|
@ -117,7 +117,6 @@ files=Ficheiros
|
||||
|
||||
error=Erro
|
||||
error404=A página que pretende aceder <strong>não existe</strong> ou <strong>não tem autorização</strong> para a ver.
|
||||
error503=O servidor não conseguiu concluir o seu pedido. Tente novamente mais tarde.
|
||||
go_back=Voltar
|
||||
invalid_data=Dados inválidos: %v
|
||||
|
||||
@ -131,7 +130,6 @@ unpin=Desafixar
|
||||
|
||||
artifacts=Artefactos
|
||||
expired=Expirado
|
||||
confirm_delete_artifact=Tem a certeza que quer eliminar este artefacto "%s"?
|
||||
|
||||
archived=Arquivado
|
||||
|
||||
@ -171,7 +169,6 @@ internal_error_skipped=Ocorreu um erro interno mas foi ignorado: %s
|
||||
search=Pesquisar...
|
||||
type_tooltip=Tipo de pesquisa
|
||||
fuzzy=Aproximada
|
||||
fuzzy_tooltip=Incluir também os resultados que estejam próximos do termo de pesquisa
|
||||
words=Palavras
|
||||
words_tooltip=Incluir apenas os resultados que correspondam às palavras do termo de pesquisa
|
||||
regexp=Regexp
|
||||
@ -506,7 +503,6 @@ activate_email.text=Por favor clique na seguinte ligação para validar o seu en
|
||||
|
||||
register_notify=Bem-vindo(a) a %s
|
||||
register_notify.title=%[1]s, bem-vindo(a) a %[2]s
|
||||
register_notify.text_1=este é o seu email de confirmação de registo para %s!
|
||||
register_notify.text_2=Agora pode iniciar a sessão com o nome de utilizador: %s.
|
||||
register_notify.text_3=Se esta conta foi criada para si, <a href="%s">defina a sua senha</a> primeiro.
|
||||
|
||||
@ -998,7 +994,6 @@ webauthn_alternative_tip=Poderá querer configurar um método de autenticação
|
||||
|
||||
manage_account_links=Gerir contas vinculadas
|
||||
manage_account_links_desc=Estas contas externas estão vinculadas à sua conta do Gitea.
|
||||
account_links_not_available=Neste momento não existem contas externas vinculadas à sua conta do Gitea.
|
||||
link_account=Vincular conta
|
||||
remove_account_link=Remover conta vinculada
|
||||
remove_account_link_desc=A remoção de uma conta vinculada revogará o acesso dessa conta à sua conta do Gitea. Quer continuar?
|
||||
@ -1035,8 +1030,6 @@ new_repo_helper=Um repositório contém todos os ficheiros do trabalho, incluind
|
||||
owner=Proprietário(a)
|
||||
owner_helper=Algumas organizações podem não aparecer na lista suspensa devido a um limite máximo de contagem de repositórios.
|
||||
repo_name=Nome do repositório
|
||||
repo_name_profile_public_hint=.profile é um repositório especial que pode usar para adicionar README.md ao seu perfil público da organização, visível para qualquer pessoa. Certifique-se que é público e inicialize-o com um README na pasta do perfil para começar.
|
||||
repo_name_profile_private_hint=.profile-private é um repositório especial que pode usar para adicionar um README.md ao seu perfil de membro da organização, visível apenas para membros da organização. Certifique-se que é privado e inicialize-o com um README na pasta de perfil para começar.
|
||||
repo_name_helper=Bons nomes de repositórios usam palavras-chave curtas, memorizáveis e únicas. Um repositório chamado ".profile" ou ".profile-private" pode ser usado para adicionar um README.md ao perfil do utilizador ou da organização.
|
||||
repo_size=Tamanho do repositório
|
||||
template=Modelo
|
||||
@ -1058,7 +1051,6 @@ fork_branch=Ramo a ser clonado para a derivação
|
||||
all_branches=Todos os ramos
|
||||
view_all_branches=Ver todos os ramos
|
||||
view_all_tags=Ver todas as etiquetas
|
||||
fork_no_valid_owners=Não pode fazer uma derivação deste repositório porque não existem proprietários válidos.
|
||||
fork.blocked_user=Não pode derivar o repositório porque foi bloqueado/a pelo/a proprietário/a do repositório.
|
||||
use_template=Usar este modelo
|
||||
open_with_editor=Abrir com %s
|
||||
@ -1755,7 +1747,6 @@ issues.due_date_form=yyyy-mm-dd
|
||||
issues.due_date_form_add=Adicionar data de vencimento
|
||||
issues.due_date_form_edit=Editar
|
||||
issues.due_date_form_remove=Remover
|
||||
issues.due_date_not_writer=Tem que ter acesso de escrita neste repositório para poder modificar a data de vencimento de uma questão.
|
||||
issues.due_date_not_set=Sem data de vencimento definida.
|
||||
issues.due_date_added=adicionou a data de vencimento %s %s
|
||||
issues.due_date_modified=modificou a data de vencimento de %[2]s para %[1]s %[3]s
|
||||
@ -2123,7 +2114,6 @@ activity.title.releases_1=%d lançamento
|
||||
activity.title.releases_n=%d Lançamentos
|
||||
activity.title.releases_published_by=%s publicado por %s
|
||||
activity.published_release_label=Publicado
|
||||
activity.no_git_activity=Não houve quaisquer cometimentos feitos durante este período.
|
||||
activity.git_stats_exclude_merges=Excluindo integrações,
|
||||
activity.git_stats_author_1=%d autor
|
||||
activity.git_stats_author_n=%d autores
|
||||
|
@ -425,7 +425,6 @@ activate_email.title=%s, пожалуйста, подтвердите ваш а
|
||||
activate_email.text=Пожалуйста, перейдите по ссылке, чтобы подтвердить ваш адрес электронной почты в течение <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, добро пожаловать в %[2]s
|
||||
register_notify.text_1=это письмо с вашим подтверждением регистрации в %s!
|
||||
register_notify.text_2=Теперь вы можете войти через логин: %s.
|
||||
register_notify.text_3=Если эта учётная запись была создана для вас, пожалуйста, сначала <a href="%s">установите пароль</a>.
|
||||
|
||||
@ -864,7 +863,6 @@ webauthn_key_loss_warning=В случае утраты ключей безопа
|
||||
|
||||
manage_account_links=Управление привязанными аккаунтами
|
||||
manage_account_links_desc=Эти внешние аккаунты привязаны к вашему аккаунту Gitea.
|
||||
account_links_not_available=В настоящее время нет внешних аккаунтов, привязанных к вашему аккаунту Gitea.
|
||||
link_account=Привязать аккаунт
|
||||
remove_account_link=Удалить привязанный аккаунт
|
||||
remove_account_link_desc=Удаление привязанной учётной записи отменит её доступ к вашей учётной записи Gitea. Продолжить?
|
||||
@ -1836,7 +1834,6 @@ activity.title.releases_1=%d релиз
|
||||
activity.title.releases_n=%d релизов
|
||||
activity.title.releases_published_by=%s опубликованы %s
|
||||
activity.published_release_label=Опубликовано
|
||||
activity.no_git_activity=В этот период не было новых коммитов.
|
||||
activity.git_stats_exclude_merges=За исключением слияний,
|
||||
activity.git_stats_author_1=%d автор
|
||||
activity.git_stats_author_n=%d автора(ов)
|
||||
|
@ -322,7 +322,6 @@ activate_email=ඔබගේ විද්යුත් තැපැල් ලි
|
||||
activate_email.text=තුළ ඔබගේ විද්යුත් තැපැල් ලිපිනය සත්යාපනය කිරීමට පහත සබැඳිය ක්ලික් කරන්න <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, %[2]s වෙත සාදරයෙන් පිළිගනිමු
|
||||
register_notify.text_1=මෙය %sසඳහා ඔබගේ ලියාපදිංචි තහවුරු කිරීමේ විද්යුත් තැපෑලයි!
|
||||
register_notify.text_2=ඔබට දැන් පරිශීලක නාමය හරහා පිවිසිය හැකිය: %s.
|
||||
register_notify.text_3=මෙම ගිණුම ඔබ වෙනුවෙන් නිර්මාණය කර තිබේ නම්, කරුණාකර <a href="%s">ඔබගේ මුරපදය</a> පළමු සකසන්න.
|
||||
|
||||
@ -664,7 +663,6 @@ twofa_failed_get_secret=රහස්ය වීමට අසමත් විය.
|
||||
|
||||
manage_account_links=සම්බන්ධිත ගිණුම් කළමනාකරණය කරන්න
|
||||
manage_account_links_desc=මෙම බාහිර ගිණුම් ඔබගේ Gitea ගිණුමට සම්බන්ධ කර ඇත.
|
||||
account_links_not_available=දැනට ඔබගේ Gitea ගිණුමට සම්බන්ධ බාහිර ගිණුම් නොමැත.
|
||||
link_account=ගිණුම සබැඳින්න
|
||||
remove_account_link=සම්බන්ධිත ගිණුම ඉවත් කරන්න
|
||||
remove_account_link_desc=සම්බන්ධිත ගිණුමක් ඉවත් කිරීම ඔබගේ Gitea ගිණුමට එහි ප්රවේශය අවලංගු කරනු ඇත. දිගටම?
|
||||
@ -1401,7 +1399,6 @@ activity.title.releases_1=නිකුතු %d
|
||||
activity.title.releases_n=නිකුතු %d
|
||||
activity.title.releases_published_by=%s විසින් ප්රකාශයට පත් කර %s
|
||||
activity.published_release_label=ප්රකාශයට පත්
|
||||
activity.no_git_activity=මෙම කාලය තුළ කිසිදු කැපවීමක් සිදු වී නොමැත.
|
||||
activity.git_stats_exclude_merges=ඒකාබද්ධ කිරීම හැර,
|
||||
activity.git_stats_author_1=%d කර්තෘ
|
||||
activity.git_stats_author_n=%d කතුවරුන්
|
||||
|
@ -411,7 +411,6 @@ activate_email=Overte svoju e-mailovú adresu
|
||||
activate_email.text=Pre overenie vašej e-mailovej adresy kliknite, prosím, na nasledovný odkaz do <b>%s</b>:
|
||||
|
||||
register_notify.title=%[1]s, vitajte v %[2]s
|
||||
register_notify.text_1=toto je e-mail potvrdzujúci vašu registráciu pre %s!
|
||||
register_notify.text_2=Teraz sa môžete prihlásiť s používateľským menom: %s.
|
||||
register_notify.text_3=Ak bol tento účet vytvorený pre vás, nastavte prosím najskôr <a href="%s">svoje heslo</a>.
|
||||
|
||||
@ -788,7 +787,6 @@ webauthn_delete_key_desc=Ak odstránite bezpečnostný kľúč, už sa s ním ne
|
||||
|
||||
manage_account_links=Spravovať prepojené kontá
|
||||
manage_account_links_desc=Tieto externé účty sú prepojené s vaším účtom Gitea.
|
||||
account_links_not_available=V súčasnosti nie sú s vaším účtom Gitea prepojené žiadne externé účty.
|
||||
link_account=Pripojiť účet
|
||||
remove_account_link=Odstrániť prepojený účet
|
||||
remove_account_link_desc=Odstránenie prepojeného účtu zruší jeho prístup k vášmu účtu Gitea. Pokračovať?
|
||||
|
@ -573,7 +573,6 @@ passcode_invalid=Koden är ogiltig. Försök igen.
|
||||
|
||||
manage_account_links=Hantera Länkade Konton
|
||||
manage_account_links_desc=Dessa externa konton är länkade till ditt Gitea-konto.
|
||||
account_links_not_available=Det finns för närvarande inga externa konton länkade till ditt Gitea-konto.
|
||||
link_account=Länka konto
|
||||
remove_account_link=Ta Bort Länkat Konto
|
||||
remove_account_link_desc=Borttagning av länkade konton kommer häva dess åtkomst till ditt Gitea-konto. Vill du fortsätta?
|
||||
@ -1182,7 +1181,6 @@ activity.title.releases_1=%d release
|
||||
activity.title.releases_n=%d releaser
|
||||
activity.title.releases_published_by=%s publicerad av %s
|
||||
activity.published_release_label=Publicerad
|
||||
activity.no_git_activity=Det har inte gjorts några commit under den här perioden.
|
||||
activity.git_stats_exclude_merges=Exkludera merger,
|
||||
activity.git_stats_author_1=%d författare
|
||||
activity.git_stats_author_n=%d författare
|
||||
|
@ -117,7 +117,6 @@ files=Dosyalar
|
||||
|
||||
error=Hata
|
||||
error404=Ulaşmaya çalıştığınız sayfa <strong>mevcut değil</strong> veya <strong>görüntüleme yetkiniz yok</strong>.
|
||||
error503=Sunucu isteğinizi gerçekleştiremedi. Lütfen daha sonra tekrar deneyin.
|
||||
go_back=Geri Git
|
||||
invalid_data=Geçersiz veri: %v
|
||||
|
||||
@ -131,7 +130,6 @@ unpin=Sabitlemeyi kaldır
|
||||
|
||||
artifacts=Yapılar
|
||||
expired=Süresi doldu
|
||||
confirm_delete_artifact=%s yapısını silmek istediğinizden emin misiniz?
|
||||
|
||||
archived=Arşivlenmiş
|
||||
|
||||
@ -171,7 +169,6 @@ internal_error_skipped=Dahili bir hata oluştu ama atlandı: %s
|
||||
search=Ara...
|
||||
type_tooltip=Arama türü
|
||||
fuzzy=Bulanık
|
||||
fuzzy_tooltip=Arama terimine benzeyen sonuçları da içer
|
||||
words=Kelimeler
|
||||
words_tooltip=Sadece arama terimi kelimeleriyle eşleşen sonuçları içer
|
||||
regexp=Regexp
|
||||
@ -506,7 +503,6 @@ activate_email.text=E posta adresinizi doğrulamak için lütfen <b>%s</b> için
|
||||
|
||||
register_notify=%s'ya Hoş Geldiniz
|
||||
register_notify.title=%[1]s, %[2]s e hoşgeldiniz
|
||||
register_notify.text_1=bu %s için kayıt onay e postanızdır!
|
||||
register_notify.text_2=Artık %s kullanıcı adı ile oturum açabilirsiniz.
|
||||
register_notify.text_3=Eğer bu hesap sizin için oluşturulduysa, lütfen önce <a href="%s">şifrenizi</a> ayarlayın.
|
||||
|
||||
@ -998,7 +994,6 @@ webauthn_alternative_tip=Ek bir kimlik doğrulama yöntemi ayarlamak isteyebilir
|
||||
|
||||
manage_account_links=Bağlı Hesapları Yönet
|
||||
manage_account_links_desc=Bu harici hesaplar Gitea hesabınızla bağlantılı.
|
||||
account_links_not_available=Şu anda Gitea hesabınıza bağlı harici bir hesap yok.
|
||||
link_account=Hesap Bağla
|
||||
remove_account_link=Bağlantılı Hesabı Kaldır
|
||||
remove_account_link_desc=Bağlantılı bir hesabı kaldırmak, onunla Gitea hesabınıza erişimi iptal edecektir. Devam edilsin mi?
|
||||
@ -1035,8 +1030,6 @@ new_repo_helper=Bir depo, sürüm geçmişi dahil tüm proje dosyalarını içer
|
||||
owner=Sahibi
|
||||
owner_helper=Bazı organizasyonlar, en çok depo sayısı sınırı nedeniyle açılır menüde görünmeyebilir.
|
||||
repo_name=Depo İsmi
|
||||
repo_name_profile_public_hint=.profile herkese açık organizasyonunuzun profiline herkesin görüntüleyebileceği bir README.md dosyası eklemek için kullanabileceğiniz özel bir depodur. Başlamak için herkese açık olduğundan ve profile dizininde README ile başladığınızdan emin olun.
|
||||
repo_name_profile_private_hint=.profile-private organizasyonunuzun üye profiline sadece organizasyon üyelerinin görüntüleyebileceği bir README.md eklemek için kullanabileceğiniz özel bir depodur. Başlamak için özel olduğundan ve profil dizininde README ile başladığınızdan emin olun.
|
||||
repo_name_helper=İyi depo isimleri kısa, akılda kalıcı ve benzersiz anahtar kelimeler kullanır. “.profile” veya ‘.profile-private’ adlı bir depo, kullanıcı/kuruluş profili için bir README.md eklemek için kullanılabilir.
|
||||
repo_size=Depo Boyutu
|
||||
template=Şablon
|
||||
@ -1058,7 +1051,6 @@ fork_branch=Çatala klonlanacak dal
|
||||
all_branches=Tüm dallar
|
||||
view_all_branches=Tüm dalları görüntüle
|
||||
view_all_tags=Tüm etiketleri görüntüle
|
||||
fork_no_valid_owners=Geçerli bir sahibi olmadığı için bu depo çatallanamaz.
|
||||
fork.blocked_user=Depo çatallanamıyor, depo sahibi tarafından engellenmişsiniz.
|
||||
use_template=Bu şablonu kullan
|
||||
open_with_editor=%s ile aç
|
||||
@ -1748,7 +1740,6 @@ issues.due_date_form=yyyy-aa-gg
|
||||
issues.due_date_form_add=Bitiş tarihi ekle
|
||||
issues.due_date_form_edit=Düzenle
|
||||
issues.due_date_form_remove=Kaldır
|
||||
issues.due_date_not_writer=Bir konunun bitiş tarihini güncellemek için bu depoda yazma iznine ihtiyacınız var.
|
||||
issues.due_date_not_set=Bitiş tarihi atanmadı.
|
||||
issues.due_date_added=bitiş tarihini %s olarak %s ekledi
|
||||
issues.due_date_modified=bitiş tarihini %[2]s iken %[1]s olarak %[3]s değiştirdi
|
||||
@ -2107,7 +2098,6 @@ activity.title.releases_1=%d Sürüm
|
||||
activity.title.releases_n=%d Sürüm
|
||||
activity.title.releases_published_by=%s %s tarafından yayınlandı
|
||||
activity.published_release_label=Yayınlandı
|
||||
activity.no_git_activity=Bu dönemde herhangi bir işleme yapılmamıştır.
|
||||
activity.git_stats_exclude_merges=Birleştirmeler hariç,
|
||||
activity.git_stats_author_1=%d yazar
|
||||
activity.git_stats_author_n=%d yazar
|
||||
|
@ -116,7 +116,6 @@ files=Файли
|
||||
|
||||
error=Помилка
|
||||
error404=Сторінка, яку ви намагаєтеся відкрити, <strong>не існує</strong> або <strong>ви не маєте права</strong> на її перегляд.
|
||||
error503=Сервер не зміг виконати ваш запит. Будь ласка, спробуйте пізніше.
|
||||
go_back=Назад
|
||||
invalid_data=Недійсні дані: %v
|
||||
|
||||
@ -130,7 +129,6 @@ unpin=Відкріпити
|
||||
|
||||
artifacts=Артефакти
|
||||
expired=Прострочено
|
||||
confirm_delete_artifact=Справді видалити артефакт '%s' ?
|
||||
|
||||
archived=Архівовано
|
||||
|
||||
@ -168,7 +166,6 @@ internal_error_skipped=Трапилась внутрішня помилка, а
|
||||
search=Пошук...
|
||||
type_tooltip=Тип пошуку
|
||||
fuzzy=Неточний
|
||||
fuzzy_tooltip=Включити результати, які також близько відповідають пошуковому запиту
|
||||
words=Слова
|
||||
words_tooltip=Включати тільки результати, які відповідають пошуковим словам
|
||||
regexp=Регулярний вираз
|
||||
@ -497,7 +494,6 @@ activate_email.text=Будь ласка, перейдіть за наступн
|
||||
|
||||
register_notify=Ласкаво просимо до %s
|
||||
register_notify.title=%[1]s, ласкаво просимо до %[2]s
|
||||
register_notify.text_1=це лист з підтвердженням реєстрації на %s!
|
||||
register_notify.text_2=Тепер ви можете увійти як: %s.
|
||||
register_notify.text_3=Якщо цей обліковий запис створено для вас, будь ласка, спершу <a href="%s">встановіть пароль</a>.
|
||||
|
||||
@ -980,7 +976,6 @@ webauthn_alternative_tip=Ви можете налаштувати додатко
|
||||
|
||||
manage_account_links=Керування прив'язаними обліковими записами
|
||||
manage_account_links_desc=Ці зовнішні облікові записи прив'язані до вашого облікового запису Gitea.
|
||||
account_links_not_available=Наразі немає зовнішніх облікових записів, пов'язаних із вашим обліковим записом Gitea.
|
||||
link_account=Прив'язати обліковий запис
|
||||
remove_account_link=Видалити обліковий запис
|
||||
remove_account_link_desc=Видалення пов'язаного облікового запису відкликає його доступ до вашого облікового запису Gitea. Продовжити?
|
||||
@ -1016,7 +1011,6 @@ new_repo_helper=Сховище містить усі файли проєкту,
|
||||
owner=Власник
|
||||
owner_helper=Деякі організації можуть не відображатися у списку через обмеження на максимальну кількість сховищ.
|
||||
repo_name=Назва сховища
|
||||
repo_name_profile_public_hint=.profile - це спеціальне сховище, за допомогою якого ви можете додати README.md до профілю вашої публічної організації, який буде видимим для всіх. Переконайтеся, що він є публічним, та ініціалізуйте його за допомогою README у каталозі профілю.
|
||||
repo_name_helper=У хороших назвах сховищ використовуються короткі ключові слова, які легко запам'ятовуються та є унікальними. Сховище з назвою «.profile» або «.profile-private» можна використовувати для додавання README.md для профілю користувача/організації.
|
||||
repo_size=Розмір сховища
|
||||
template=Шаблон
|
||||
@ -1690,7 +1684,6 @@ issues.due_date_form=рррр-мм-дд
|
||||
issues.due_date_form_add=Додати дату завершення
|
||||
issues.due_date_form_edit=Редагувати
|
||||
issues.due_date_form_remove=Видалити
|
||||
issues.due_date_not_writer=Вам потрібен доступ на запис до цього сховища, щоб оновити дату виконання задачі.
|
||||
issues.due_date_not_set=Термін виконання не встановлений.
|
||||
issues.due_date_added=додав(ла) дату завершення %s %s
|
||||
issues.due_date_modified=змінив(-ла) термін виконання з %[2]s на %[1]s %[3]s
|
||||
@ -2024,7 +2017,6 @@ activity.title.releases_1=%d Реліз
|
||||
activity.title.releases_n=%d Релізів
|
||||
activity.title.releases_published_by=%s опубліковано %s
|
||||
activity.published_release_label=Опубліковано
|
||||
activity.no_git_activity=За цей період не було жодної активності комітів.
|
||||
activity.git_stats_exclude_merges=Не враховуючи об'єднання,
|
||||
activity.git_stats_author_1=%d автор
|
||||
activity.git_stats_author_n=%d автори
|
||||
|
@ -117,7 +117,6 @@ files=文件
|
||||
|
||||
error=错误
|
||||
error404=您正尝试访问的页面 <strong>不存在</strong> 或 <strong>您尚未被授权</strong> 查看该页面。
|
||||
error503=服务器无法完成您的请求,请稍后重试。
|
||||
go_back=返回
|
||||
invalid_data=无效数据: %v
|
||||
|
||||
@ -131,7 +130,6 @@ unpin=取消置顶
|
||||
|
||||
artifacts=产物
|
||||
expired=已过期
|
||||
confirm_delete_artifact=您确定要删除产物「%s」吗?
|
||||
|
||||
archived=已归档
|
||||
|
||||
@ -171,7 +169,6 @@ internal_error_skipped=发生内部错误,但已跳过: %s
|
||||
search=搜索...
|
||||
type_tooltip=搜索类型
|
||||
fuzzy=模糊
|
||||
fuzzy_tooltip=包含近似匹配搜索词的结果
|
||||
words=词
|
||||
words_tooltip=仅包含匹配搜索词的结果
|
||||
regexp=正则表达式
|
||||
@ -506,7 +503,6 @@ activate_email.text=请在 <b>%s</b> 时间内,点击以下链接,以验证
|
||||
|
||||
register_notify=欢迎来到 %s
|
||||
register_notify.title=%[1]s,欢迎来到 %[2]s
|
||||
register_notify.text_1=这是您的 %s 注册确认邮件 !
|
||||
register_notify.text_2=您现在可以以用户名 %s 登录。
|
||||
register_notify.text_3=如果此账户已为您创建,请先 <a href="%s">设置您的密码</a>。
|
||||
|
||||
@ -998,7 +994,6 @@ webauthn_alternative_tip=您可能想要配置额外的身份验证方法。
|
||||
|
||||
manage_account_links=管理绑定过的账号
|
||||
manage_account_links_desc=这些外部帐户已经绑定到您的 Gitea 帐户。
|
||||
account_links_not_available=当前没有与您的 Gitea 帐户绑定的外部帐户。
|
||||
link_account=链接账户
|
||||
remove_account_link=删除已绑定的账号
|
||||
remove_account_link_desc=删除已绑定帐户将吊销其对您的 Gitea 帐户的访问权限。继续?
|
||||
@ -1035,8 +1030,6 @@ new_repo_helper=代码仓库包含了所有的项目文件,包括版本历史
|
||||
owner=拥有者
|
||||
owner_helper=由于最大仓库数量限制,一些组织可能不会显示在下拉列表中。
|
||||
repo_name=仓库名称
|
||||
repo_name_profile_public_hint=.profile 是一个特殊的仓库,您可以使用它将 README.md 添加到您的公共组织资料中,任何人都可以看到。请确保它是公开的,并使用个人资料目录中的 README 对其进行初始化以开始使用。
|
||||
repo_name_profile_private_hint=.profile-private 是一个特殊的仓库,您可以使用它向您的组织成员个人资料添加 README.md,仅对组织成员可见。请确保它是私有的,并使用个人资料目录中的 README 对其进行初始化以开始使用。
|
||||
repo_name_helper=理想的仓库名称应由简短、有意义和独特的关键词组成。「.profile」和「.profile-private」可用于为用户/组织添加 README.md。
|
||||
repo_size=仓库大小
|
||||
template=模板
|
||||
@ -1058,7 +1051,6 @@ fork_branch=要克隆为派生的分支
|
||||
all_branches=所有分支
|
||||
view_all_branches=查看所有分支
|
||||
view_all_tags=查看所有标签
|
||||
fork_no_valid_owners=这个代码仓库无法被派生,因为没有有效的所有者。
|
||||
fork.blocked_user=无法克隆仓库,因为您被仓库所有者屏蔽。
|
||||
use_template=使用此模板
|
||||
open_with_editor=用 %s 打开
|
||||
@ -1400,12 +1392,12 @@ editor.revert=将 %s 还原到:
|
||||
editor.failed_to_commit=提交更改失败。
|
||||
editor.failed_to_commit_summary=错误信息:
|
||||
|
||||
editor.fork_create=派生仓库发起请求变更
|
||||
editor.fork_create_description=您不能直接编辑此仓库。您可以从此仓库派生,进行编辑并创建一个拉取请求。
|
||||
editor.fork_edit_description=您不能直接编辑此仓库。 更改将写入您的派生仓库 <b>%s</b>,以便您可以创建一个拉取请求。
|
||||
editor.fork_not_editable=你已经派生了这个仓库,但是你的分叉是不可编辑的。
|
||||
editor.fork_create=派生仓库以请求变更
|
||||
editor.fork_create_description=您不能直接编辑此仓库。您可以派生此仓库,进行编辑并创建一个合并请求。
|
||||
editor.fork_edit_description=您不能直接编辑此仓库。 更改将写入您的派生仓库 <b>%s</b>,以便您可以创建一个合并请求。
|
||||
editor.fork_not_editable=您已经派生了此仓库,但您的派生是不可编辑的。
|
||||
editor.fork_failed_to_push_branch=推送分支 %s 到仓库失败。
|
||||
editor.fork_branch_exists=分支 "%s" 已存在于您的派生仓库中,请选择一个新的分支名称。
|
||||
editor.fork_branch_exists=分支「%s」已存在于您的派生仓库中,请选择一个新的分支名称。
|
||||
|
||||
commits.desc=浏览代码修改历史
|
||||
commits.commits=次代码提交
|
||||
@ -1756,7 +1748,6 @@ issues.due_date_form=yyyy年mm月dd日
|
||||
issues.due_date_form_add=设置到期时间
|
||||
issues.due_date_form_edit=编辑
|
||||
issues.due_date_form_remove=删除
|
||||
issues.due_date_not_writer=您需要该仓库的写权限才能更新工单的到期日期。
|
||||
issues.due_date_not_set=未设置到期时间。
|
||||
issues.due_date_added=于 %[2]s 设置到期时间为 %[1]s
|
||||
issues.due_date_modified=将到期日从 %[2]s 修改为 %[1]s %[3]s
|
||||
@ -2124,7 +2115,6 @@ activity.title.releases_1=%d 个发布
|
||||
activity.title.releases_n=%d 个发布
|
||||
activity.title.releases_published_by=%[2]s 发布了 %[1]s
|
||||
activity.published_release_label=已发布
|
||||
activity.no_git_activity=在此期间没有任何提交活动。
|
||||
activity.git_stats_exclude_merges=排除合并后,
|
||||
activity.git_stats_author_1=%d 位作者
|
||||
activity.git_stats_author_n=%d 位作者
|
||||
@ -2171,8 +2161,8 @@ settings.hooks=Web 钩子
|
||||
settings.githooks=管理 Git 钩子
|
||||
settings.basic_settings=基本设置
|
||||
settings.mirror_settings=镜像设置
|
||||
settings.mirror_settings.docs=设置您的仓库以自动同步另一个仓库的提交、标签和分支。
|
||||
settings.mirror_settings.docs.disabled_pull_mirror.instructions=设置您的项目以自动将提交、标签和分支推送到另一个仓库。您的站点管理员已禁用了拉取镜像。
|
||||
settings.mirror_settings.docs=将您的仓库设置为自动同步另一个仓库的提交、标签和分支。
|
||||
settings.mirror_settings.docs.disabled_pull_mirror.instructions=将您的项目设置为自动将提交、标签和分支推送到另一个仓库。您的站点管理员已禁用了拉取镜像。
|
||||
settings.mirror_settings.docs.disabled_push_mirror.instructions=将您的项目设置为自动从一个仓库拉取提交、标签和分支。
|
||||
settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning=现在,这只能在「迁移外部仓库」菜单中完成。欲了解更多信息,请参考:
|
||||
settings.mirror_settings.docs.disabled_push_mirror.info=您的站点管理员已禁用推送镜像。
|
||||
@ -2335,6 +2325,8 @@ settings.hooks_desc=当 Gitea 事件发生时,Web 钩子自动发出 HTTP POST
|
||||
settings.webhook_deletion=删除 Web 钩子
|
||||
settings.webhook_deletion_desc=删除 Web 钩子将删除其设置和历史记录。继续?
|
||||
settings.webhook_deletion_success=Web 钩子删除成功!
|
||||
settings.webhook.test_delivery=测试推送事件
|
||||
settings.webhook.test_delivery_desc=用假推送事件测试这个 Web 钩子。
|
||||
settings.webhook.test_delivery_desc_disabled=要用假事件测试这个 Web钩子,请激活它。
|
||||
settings.webhook.request=请求内容
|
||||
settings.webhook.response=响应内容
|
||||
@ -2354,6 +2346,7 @@ settings.payload_url=目标 URL
|
||||
settings.http_method=HTTP 方法
|
||||
settings.content_type=POST 内容类型
|
||||
settings.secret=密钥
|
||||
settings.webhook_secret_desc=如果 Webhook 服务器支持使用密钥,您可以按照 Webhook 的手册在此处填写一个密钥。
|
||||
settings.slack_username=服务名称
|
||||
settings.slack_icon_url=图标 URL
|
||||
settings.slack_color=颜色
|
||||
@ -2768,6 +2761,8 @@ branch.new_branch_from=基于「%s」创建新分支
|
||||
branch.renamed=分支 %s 已重命名为 %s。
|
||||
branch.rename_default_or_protected_branch_error=只有管理员能重命名默认分支和受保护的分支。
|
||||
branch.rename_protected_branch_failed=此分支受到 glob 语法规则的保护。
|
||||
branch.commits_divergence_from=提交分歧:落后 %[3]s %[1]d 个提交,领先 %[2]d 个提交
|
||||
branch.commits_no_divergence=与分支 %[1]s 相同
|
||||
|
||||
tag.create_tag=创建标签 %s
|
||||
tag.create_tag_operation=创建标签
|
||||
@ -2781,6 +2776,7 @@ topic.done=保存
|
||||
topic.count_prompt=您最多选择25个主题
|
||||
topic.format_prompt=主题必须以字母或数字开头,可以包含连字符 ('-') 和句点 ('.'),长度不得超过35个字符。字符必须为小写。
|
||||
|
||||
find_file.follow_symlink=跟随此符号链接的指向位置
|
||||
find_file.go_to_file=转到文件
|
||||
find_file.no_matching=没有找到匹配的文件
|
||||
|
||||
|
@ -128,7 +128,6 @@ pin=固定
|
||||
unpin=取消固定
|
||||
|
||||
artifacts=檔案或工件
|
||||
confirm_delete_artifact=你確定要刪除這個檔案 '%s' 嗎?
|
||||
|
||||
archived=已封存
|
||||
|
||||
@ -167,7 +166,6 @@ internal_error_skipped=已略過內部錯誤:%s
|
||||
search=搜尋…
|
||||
type_tooltip=搜尋類型
|
||||
fuzzy=模糊
|
||||
fuzzy_tooltip=包含與搜尋詞接近的結果
|
||||
exact=精確
|
||||
exact_tooltip=只包含完全符合關鍵字的結果
|
||||
repo_kind=搜尋儲存庫…
|
||||
@ -487,7 +485,6 @@ activate_email.text=請在 <b>%s</b>內點擊下列連結以驗證您的電子
|
||||
|
||||
register_notify=歡迎來到 Gitea
|
||||
register_notify.title=%[1]s,歡迎來到 %[2]s
|
||||
register_notify.text_1=這是您在 %s 的註冊確認信!
|
||||
register_notify.text_2=您現在可以用帳號 %s 登入。
|
||||
register_notify.text_3=如果這是由管理員為您建立的帳戶,請先<a href="%s">設定您的密碼</a>。
|
||||
|
||||
@ -973,7 +970,6 @@ webauthn_alternative_tip=您可能需要設定其他的驗證方法。
|
||||
|
||||
manage_account_links=管理已連結的帳戶
|
||||
manage_account_links_desc=這些外部帳戶已連結到您的 Gitea 帳戶。
|
||||
account_links_not_available=目前沒有連結到您的 Gitea 帳戶的外部帳戶
|
||||
link_account=連結帳戶
|
||||
remove_account_link=刪除已連結的帳戶
|
||||
remove_account_link_desc=刪除連結帳戶將撤銷其對 Gitea 帳戶的存取權限。是否繼續?
|
||||
@ -1030,7 +1026,6 @@ fork_branch=要克隆到 fork 的分支
|
||||
all_branches=所有分支
|
||||
view_all_branches=查看所有分支
|
||||
view_all_tags=查看所有標籤
|
||||
fork_no_valid_owners=此儲存庫無法 fork,因為沒有有效的擁有者。
|
||||
fork.blocked_user=無法 fork 儲存庫,因為您被儲存庫擁有者封鎖。
|
||||
use_template=使用此範本
|
||||
open_with_editor=以 %s 開啟
|
||||
@ -1690,7 +1685,6 @@ issues.due_date_form=yyyy年mm月dd日
|
||||
issues.due_date_form_add=新增截止日期
|
||||
issues.due_date_form_edit=編輯
|
||||
issues.due_date_form_remove=移除
|
||||
issues.due_date_not_writer=您需要對此儲存庫的寫入權限才能更新問題的截止日期。
|
||||
issues.due_date_not_set=未設定截止日期。
|
||||
issues.due_date_added=新增了截止日期 %s %s
|
||||
issues.due_date_modified=將截止日期從 %[2]s 修改為 %[1]s %[3]s
|
||||
@ -2051,7 +2045,6 @@ activity.title.releases_1=%d 個版本
|
||||
activity.title.releases_n=%d 個版本
|
||||
activity.title.releases_published_by=%[2]s發布了 %[1]s
|
||||
activity.published_release_label=已發布
|
||||
activity.no_git_activity=期間內沒有任何提交動態
|
||||
activity.git_stats_exclude_merges=不計合併,
|
||||
activity.git_stats_author_1=%d 位作者
|
||||
activity.git_stats_author_n=%d 位作者
|
||||
|
@ -747,7 +747,7 @@ func (Action) ListWorkflowRuns(ctx *context.APIContext) {
|
||||
// type: integer
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/ArtifactsList"
|
||||
// "$ref": "#/responses/WorkflowRunsList"
|
||||
// "400":
|
||||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
|
@ -44,5 +44,5 @@ type swaggerResponseActionWorkflow struct {
|
||||
// swagger:response ActionWorkflowList
|
||||
type swaggerResponseActionWorkflowList struct {
|
||||
// in:body
|
||||
Body []api.ActionWorkflow `json:"body"`
|
||||
Body api.ActionWorkflowResponse `json:"body"`
|
||||
}
|
||||
|
58
routers/web/devtest/mail_preview.go
Normal file
58
routers/web/devtest/mail_preview.go
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package devtest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func MailPreviewRender(ctx *context.Context) {
|
||||
tmplName := ctx.PathParam("*")
|
||||
mockDataContent, err := templates.AssetFS().ReadFile("mail/" + tmplName + ".mock.yml")
|
||||
mockData := map[string]any{}
|
||||
if err == nil {
|
||||
err = yaml.Unmarshal(mockDataContent, &mockData)
|
||||
if err != nil {
|
||||
http.Error(ctx.Resp, "Failed to parse mock data: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
mockData["locale"] = ctx.Locale
|
||||
err = mailer.LoadedTemplates().BodyTemplates.ExecuteTemplate(ctx.Resp, tmplName, mockData)
|
||||
if err != nil {
|
||||
_, _ = ctx.Resp.Write([]byte(err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
func prepareMailPreviewRender(ctx *context.Context, tmplName string) {
|
||||
tmplSubject := mailer.LoadedTemplates().SubjectTemplates.Lookup(tmplName)
|
||||
if tmplSubject == nil {
|
||||
ctx.Data["RenderMailSubject"] = "default subject"
|
||||
} else {
|
||||
var buf strings.Builder
|
||||
err := tmplSubject.Execute(&buf, nil)
|
||||
if err != nil {
|
||||
ctx.Data["RenderMailSubject"] = err.Error()
|
||||
} else {
|
||||
ctx.Data["RenderMailSubject"] = buf.String()
|
||||
}
|
||||
}
|
||||
ctx.Data["RenderMailTemplateName"] = tmplName
|
||||
}
|
||||
|
||||
func MailPreview(ctx *context.Context) {
|
||||
ctx.Data["MailTemplateNames"] = mailer.LoadedTemplates().TemplateNames
|
||||
tmplName := ctx.FormString("tmpl")
|
||||
if tmplName != "" {
|
||||
prepareMailPreviewRender(ctx, tmplName)
|
||||
}
|
||||
ctx.HTML(http.StatusOK, "devtest/mail-preview")
|
||||
}
|
@ -4,10 +4,8 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
@ -34,58 +32,42 @@ const (
|
||||
tplNotificationSubscriptions templates.TplName = "user/notification/notification_subscriptions"
|
||||
)
|
||||
|
||||
// Notifications is the notifications page
|
||||
// Notifications is the notification list page
|
||||
func Notifications(ctx *context.Context) {
|
||||
getNotifications(ctx)
|
||||
prepareUserNotificationsData(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
if ctx.FormBool("div-only") {
|
||||
ctx.Data["SequenceNumber"] = ctx.FormString("sequence-number")
|
||||
ctx.HTML(http.StatusOK, tplNotificationDiv)
|
||||
return
|
||||
}
|
||||
ctx.HTML(http.StatusOK, tplNotification)
|
||||
}
|
||||
|
||||
func getNotifications(ctx *context.Context) {
|
||||
var (
|
||||
keyword = ctx.FormTrim("q")
|
||||
status activities_model.NotificationStatus
|
||||
page = ctx.FormInt("page")
|
||||
perPage = ctx.FormInt("perPage")
|
||||
)
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 20
|
||||
}
|
||||
|
||||
switch keyword {
|
||||
case "read":
|
||||
status = activities_model.NotificationStatusRead
|
||||
default:
|
||||
status = activities_model.NotificationStatusUnread
|
||||
}
|
||||
func prepareUserNotificationsData(ctx *context.Context) {
|
||||
pageType := ctx.FormString("type", ctx.FormString("q")) // "q" is the legacy query parameter for "page type"
|
||||
page := max(1, ctx.FormInt("page"))
|
||||
perPage := util.IfZero(ctx.FormInt("perPage"), 20) // this value is never used or exposed ....
|
||||
queryStatus := util.Iif(pageType == "read", activities_model.NotificationStatusRead, activities_model.NotificationStatusUnread)
|
||||
|
||||
total, err := db.Count[activities_model.Notification](ctx, activities_model.FindNotificationOptions{
|
||||
UserID: ctx.Doer.ID,
|
||||
Status: []activities_model.NotificationStatus{status},
|
||||
Status: []activities_model.NotificationStatus{queryStatus},
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("ErrGetNotificationCount", err)
|
||||
return
|
||||
}
|
||||
|
||||
// redirect to last page if request page is more than total pages
|
||||
pager := context.NewPagination(int(total), perPage, page, 5)
|
||||
if pager.Paginater.Current() < page {
|
||||
ctx.Redirect(fmt.Sprintf("%s/notifications?q=%s&page=%d", setting.AppSubURL, url.QueryEscape(ctx.FormString("q")), pager.Paginater.Current()))
|
||||
return
|
||||
// use the last page if the requested page is more than total pages
|
||||
page = pager.Paginater.Current()
|
||||
pager = context.NewPagination(int(total), perPage, page, 5)
|
||||
}
|
||||
|
||||
statuses := []activities_model.NotificationStatus{status, activities_model.NotificationStatusPinned}
|
||||
statuses := []activities_model.NotificationStatus{queryStatus, activities_model.NotificationStatusPinned}
|
||||
nls, err := db.Find[activities_model.Notification](ctx, activities_model.FindNotificationOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
PageSize: perPage,
|
||||
@ -142,51 +124,37 @@ func getNotifications(ctx *context.Context) {
|
||||
}
|
||||
|
||||
ctx.Data["Title"] = ctx.Tr("notifications")
|
||||
ctx.Data["Keyword"] = keyword
|
||||
ctx.Data["Status"] = status
|
||||
ctx.Data["PageType"] = pageType
|
||||
ctx.Data["Notifications"] = notifications
|
||||
|
||||
ctx.Data["Link"] = setting.AppSubURL + "/notifications"
|
||||
ctx.Data["SequenceNumber"] = ctx.FormString("sequence-number")
|
||||
pager.AddParamFromRequest(ctx.Req)
|
||||
ctx.Data["Page"] = pager
|
||||
}
|
||||
|
||||
// NotificationStatusPost is a route for changing the status of a notification
|
||||
func NotificationStatusPost(ctx *context.Context) {
|
||||
var (
|
||||
notificationID = ctx.FormInt64("notification_id")
|
||||
statusStr = ctx.FormString("status")
|
||||
status activities_model.NotificationStatus
|
||||
)
|
||||
|
||||
switch statusStr {
|
||||
case "read":
|
||||
status = activities_model.NotificationStatusRead
|
||||
case "unread":
|
||||
status = activities_model.NotificationStatusUnread
|
||||
case "pinned":
|
||||
status = activities_model.NotificationStatusPinned
|
||||
notificationID := ctx.FormInt64("notification_id")
|
||||
var newStatus activities_model.NotificationStatus
|
||||
switch ctx.FormString("notification_action") {
|
||||
case "mark_as_read":
|
||||
newStatus = activities_model.NotificationStatusRead
|
||||
case "mark_as_unread":
|
||||
newStatus = activities_model.NotificationStatusUnread
|
||||
case "pin":
|
||||
newStatus = activities_model.NotificationStatusPinned
|
||||
default:
|
||||
ctx.ServerError("InvalidNotificationStatus", errors.New("Invalid notification status"))
|
||||
return
|
||||
return // ignore user's invalid input
|
||||
}
|
||||
|
||||
if _, err := activities_model.SetNotificationStatus(ctx, notificationID, ctx.Doer, status); err != nil {
|
||||
if _, err := activities_model.SetNotificationStatus(ctx, notificationID, ctx.Doer, newStatus); err != nil {
|
||||
ctx.ServerError("SetNotificationStatus", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !ctx.FormBool("noredirect") {
|
||||
url := fmt.Sprintf("%s/notifications?page=%s", setting.AppSubURL, url.QueryEscape(ctx.FormString("page")))
|
||||
ctx.Redirect(url, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
getNotifications(ctx)
|
||||
prepareUserNotificationsData(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
ctx.Data["Link"] = setting.AppSubURL + "/notifications"
|
||||
ctx.Data["SequenceNumber"] = ctx.Req.PostFormValue("sequence-number")
|
||||
|
||||
ctx.HTML(http.StatusOK, tplNotificationDiv)
|
||||
}
|
||||
|
||||
|
@ -1659,6 +1659,8 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Group("/devtest", func() {
|
||||
m.Any("", devtest.List)
|
||||
m.Any("/fetch-action-test", devtest.FetchActionTest)
|
||||
m.Any("/mail-preview", devtest.MailPreview)
|
||||
m.Any("/mail-preview/*", devtest.MailPreviewRender)
|
||||
m.Any("/{sub}", devtest.TmplCommon)
|
||||
m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView)
|
||||
m.Post("/actions-mock/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
|
||||
|
@ -251,7 +251,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
|
||||
RepoTransfer: transfer,
|
||||
Topics: util.SliceNilAsEmpty(repo.Topics),
|
||||
ObjectFormatName: repo.ObjectFormatName,
|
||||
Licenses: repoLicenses.StringList(),
|
||||
Licenses: util.SliceNilAsEmpty(repoLicenses.StringList()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"mime"
|
||||
"regexp"
|
||||
"strings"
|
||||
texttmpl "text/template"
|
||||
"sync/atomic"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
@ -23,6 +23,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/typesniffer"
|
||||
sender_service "code.gitea.io/gitea/services/mailer/sender"
|
||||
|
||||
@ -31,11 +32,13 @@ import (
|
||||
|
||||
const mailMaxSubjectRunes = 256 // There's no actual limit for subject in RFC 5322
|
||||
|
||||
var (
|
||||
bodyTemplates *template.Template
|
||||
subjectTemplates *texttmpl.Template
|
||||
subjectRemoveSpaces = regexp.MustCompile(`[\s]+`)
|
||||
)
|
||||
var loadedTemplates atomic.Pointer[templates.MailTemplates]
|
||||
|
||||
var subjectRemoveSpaces = regexp.MustCompile(`[\s]+`)
|
||||
|
||||
func LoadedTemplates() *templates.MailTemplates {
|
||||
return loadedTemplates.Load()
|
||||
}
|
||||
|
||||
// SendTestMail sends a test mail
|
||||
func SendTestMail(email string) error {
|
||||
|
@ -119,7 +119,7 @@ func composeIssueCommentMessages(ctx context.Context, comment *mailComment, lang
|
||||
}
|
||||
|
||||
var mailSubject bytes.Buffer
|
||||
if err := subjectTemplates.ExecuteTemplate(&mailSubject, tplName, mailMeta); err == nil {
|
||||
if err := LoadedTemplates().SubjectTemplates.ExecuteTemplate(&mailSubject, tplName, mailMeta); err == nil {
|
||||
subject = sanitizeSubject(mailSubject.String())
|
||||
if subject == "" {
|
||||
subject = fallback
|
||||
@ -134,7 +134,7 @@ func composeIssueCommentMessages(ctx context.Context, comment *mailComment, lang
|
||||
|
||||
var mailBody bytes.Buffer
|
||||
|
||||
if err := bodyTemplates.ExecuteTemplate(&mailBody, tplName, mailMeta); err != nil {
|
||||
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, tplName, mailMeta); err != nil {
|
||||
log.Error("ExecuteTemplate [%s]: %v", tplName+"/body", err)
|
||||
}
|
||||
|
||||
@ -260,14 +260,14 @@ func actionToTemplate(issue *issues_model.Issue, actionType activities_model.Act
|
||||
}
|
||||
|
||||
template = typeName + "/" + name
|
||||
ok := bodyTemplates.Lookup(template) != nil
|
||||
ok := LoadedTemplates().BodyTemplates.Lookup(template) != nil
|
||||
if !ok && typeName != "issue" {
|
||||
template = "issue/" + name
|
||||
ok = bodyTemplates.Lookup(template) != nil
|
||||
ok = LoadedTemplates().BodyTemplates.Lookup(template) != nil
|
||||
}
|
||||
if !ok {
|
||||
template = typeName + "/default"
|
||||
ok = bodyTemplates.Lookup(template) != nil
|
||||
ok = LoadedTemplates().BodyTemplates.Lookup(template) != nil
|
||||
}
|
||||
if !ok {
|
||||
template = "issue/default"
|
||||
|
@ -79,7 +79,7 @@ func mailNewRelease(ctx context.Context, lang string, tos []*user_model.User, re
|
||||
|
||||
var mailBody bytes.Buffer
|
||||
|
||||
if err := bodyTemplates.ExecuteTemplate(&mailBody, string(tplNewReleaseMail), mailMeta); err != nil {
|
||||
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, string(tplNewReleaseMail), mailMeta); err != nil {
|
||||
log.Error("ExecuteTemplate [%s]: %v", string(tplNewReleaseMail)+"/body", err)
|
||||
return
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
|
||||
"Destination": destination,
|
||||
}
|
||||
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil {
|
||||
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_mod
|
||||
}
|
||||
|
||||
var mailBody bytes.Buffer
|
||||
if err := bodyTemplates.ExecuteTemplate(&mailBody, string(tplTeamInviteMail), mailMeta); err != nil {
|
||||
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, string(tplTeamInviteMail), mailMeta); err != nil {
|
||||
log.Error("ExecuteTemplate [%s]: %v", string(tplTeamInviteMail)+"/body", err)
|
||||
return err
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/services/attachment"
|
||||
sender_service "code.gitea.io/gitea/services/mailer/sender"
|
||||
@ -95,6 +96,13 @@ func prepareMailerBase64Test(t *testing.T) (doer *user_model.User, repo *repo_mo
|
||||
return user, repo, issue, att1, att2
|
||||
}
|
||||
|
||||
func prepareMailTemplates(name, subjectTmpl, bodyTmpl string) {
|
||||
loadedTemplates.Store(&templates.MailTemplates{
|
||||
SubjectTemplates: texttmpl.Must(texttmpl.New(name).Parse(subjectTmpl)),
|
||||
BodyTemplates: template.Must(template.New(name).Parse(bodyTmpl)),
|
||||
})
|
||||
}
|
||||
|
||||
func TestComposeIssueComment(t *testing.T) {
|
||||
doer, _, issue, comment := prepareMailerTest(t)
|
||||
|
||||
@ -107,8 +115,7 @@ func TestComposeIssueComment(t *testing.T) {
|
||||
setting.IncomingEmail.Enabled = true
|
||||
defer func() { setting.IncomingEmail.Enabled = false }()
|
||||
|
||||
subjectTemplates = texttmpl.Must(texttmpl.New("issue/comment").Parse(subjectTpl))
|
||||
bodyTemplates = template.Must(template.New("issue/comment").Parse(bodyTpl))
|
||||
prepareMailTemplates("issue/comment", subjectTpl, bodyTpl)
|
||||
|
||||
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}}
|
||||
msgs, err := composeIssueCommentMessages(t.Context(), &mailComment{
|
||||
@ -153,8 +160,7 @@ func TestComposeIssueComment(t *testing.T) {
|
||||
func TestMailMentionsComment(t *testing.T) {
|
||||
doer, _, issue, comment := prepareMailerTest(t)
|
||||
comment.Poster = doer
|
||||
subjectTemplates = texttmpl.Must(texttmpl.New("issue/comment").Parse(subjectTpl))
|
||||
bodyTemplates = template.Must(template.New("issue/comment").Parse(bodyTpl))
|
||||
prepareMailTemplates("issue/comment", subjectTpl, bodyTpl)
|
||||
mails := 0
|
||||
|
||||
defer test.MockVariableValue(&SendAsync, func(msgs ...*sender_service.Message) {
|
||||
@ -169,9 +175,7 @@ func TestMailMentionsComment(t *testing.T) {
|
||||
func TestComposeIssueMessage(t *testing.T) {
|
||||
doer, _, issue, _ := prepareMailerTest(t)
|
||||
|
||||
subjectTemplates = texttmpl.Must(texttmpl.New("issue/new").Parse(subjectTpl))
|
||||
bodyTemplates = template.Must(template.New("issue/new").Parse(bodyTpl))
|
||||
|
||||
prepareMailTemplates("issue/new", subjectTpl, bodyTpl)
|
||||
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}}
|
||||
msgs, err := composeIssueCommentMessages(t.Context(), &mailComment{
|
||||
Issue: issue, Doer: doer, ActionType: activities_model.ActionCreateIssue,
|
||||
@ -200,15 +204,14 @@ func TestTemplateSelection(t *testing.T) {
|
||||
doer, repo, issue, comment := prepareMailerTest(t)
|
||||
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}}
|
||||
|
||||
subjectTemplates = texttmpl.Must(texttmpl.New("issue/default").Parse("issue/default/subject"))
|
||||
texttmpl.Must(subjectTemplates.New("issue/new").Parse("issue/new/subject"))
|
||||
texttmpl.Must(subjectTemplates.New("pull/comment").Parse("pull/comment/subject"))
|
||||
texttmpl.Must(subjectTemplates.New("issue/close").Parse("")) // Must default to fallback subject
|
||||
prepareMailTemplates("issue/default", "issue/default/subject", "issue/default/body")
|
||||
|
||||
bodyTemplates = template.Must(template.New("issue/default").Parse("issue/default/body"))
|
||||
template.Must(bodyTemplates.New("issue/new").Parse("issue/new/body"))
|
||||
template.Must(bodyTemplates.New("pull/comment").Parse("pull/comment/body"))
|
||||
template.Must(bodyTemplates.New("issue/close").Parse("issue/close/body"))
|
||||
texttmpl.Must(LoadedTemplates().SubjectTemplates.New("issue/new").Parse("issue/new/subject"))
|
||||
texttmpl.Must(LoadedTemplates().SubjectTemplates.New("pull/comment").Parse("pull/comment/subject"))
|
||||
texttmpl.Must(LoadedTemplates().SubjectTemplates.New("issue/close").Parse("")) // Must default to a fallback subject
|
||||
template.Must(LoadedTemplates().BodyTemplates.New("issue/new").Parse("issue/new/body"))
|
||||
template.Must(LoadedTemplates().BodyTemplates.New("pull/comment").Parse("pull/comment/body"))
|
||||
template.Must(LoadedTemplates().BodyTemplates.New("issue/close").Parse("issue/close/body"))
|
||||
|
||||
expect := func(t *testing.T, msg *sender_service.Message, expSubject, expBody string) {
|
||||
subject := msg.ToMessage().GetGenHeader("Subject")
|
||||
@ -253,9 +256,7 @@ func TestTemplateServices(t *testing.T) {
|
||||
expect := func(t *testing.T, issue *issues_model.Issue, comment *issues_model.Comment, doer *user_model.User,
|
||||
actionType activities_model.ActionType, fromMention bool, tplSubject, tplBody, expSubject, expBody string,
|
||||
) {
|
||||
subjectTemplates = texttmpl.Must(texttmpl.New("issue/default").Parse(tplSubject))
|
||||
bodyTemplates = template.Must(template.New("issue/default").Parse(tplBody))
|
||||
|
||||
prepareMailTemplates("issue/default", tplSubject, tplBody)
|
||||
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}}
|
||||
msg := testComposeIssueCommentMessage(t, &mailComment{
|
||||
Issue: issue, Doer: doer, ActionType: actionType,
|
||||
@ -512,8 +513,7 @@ func TestEmbedBase64Images(t *testing.T) {
|
||||
att2ImgBase64 := fmt.Sprintf(`<img src="%s"/>`, att2Base64)
|
||||
|
||||
t.Run("ComposeMessage", func(t *testing.T) {
|
||||
subjectTemplates = texttmpl.Must(texttmpl.New("issue/new").Parse(subjectTpl))
|
||||
bodyTemplates = template.Must(template.New("issue/new").Parse(bodyTpl))
|
||||
prepareMailTemplates("issue/new", subjectTpl, bodyTpl)
|
||||
|
||||
issue.Content = fmt.Sprintf(`MSG-BEFORE <image src="attachments/%s"> MSG-AFTER`, att1.UUID)
|
||||
require.NoError(t, issues_model.UpdateIssueCols(t.Context(), issue, "content"))
|
||||
|
@ -39,7 +39,7 @@ func sendUserMail(language string, u *user_model.User, tpl templates.TplName, co
|
||||
|
||||
var content bytes.Buffer
|
||||
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(tpl), data); err != nil {
|
||||
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(tpl), data); err != nil {
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
}
|
||||
@ -90,7 +90,7 @@ func SendActivateEmailMail(u *user_model.User, email string) {
|
||||
|
||||
var content bytes.Buffer
|
||||
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil {
|
||||
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil {
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
}
|
||||
@ -118,7 +118,7 @@ func SendRegisterNotifyMail(u *user_model.User) {
|
||||
|
||||
var content bytes.Buffer
|
||||
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil {
|
||||
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil {
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
}
|
||||
@ -149,7 +149,7 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository)
|
||||
|
||||
var content bytes.Buffer
|
||||
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
|
||||
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ func NewContext(ctx context.Context) {
|
||||
sender = &sender_service.SMTPSender{}
|
||||
}
|
||||
|
||||
subjectTemplates, bodyTemplates = templates.Mailer(ctx)
|
||||
templates.LoadMailTemplates(ctx, &loadedTemplates)
|
||||
|
||||
mailQueue = queue.CreateSimpleQueue(graceful.GetManager().ShutdownContext(), "mail", func(items ...*sender_service.Message) []*sender_service.Message {
|
||||
for _, msg := range items {
|
||||
|
@ -1,2 +1,3 @@
|
||||
{{template "base/head" ctx.RootData}}
|
||||
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/devtest.css?v={{AssetVersion}}">
|
||||
{{template "base/alert" .}}
|
||||
|
27
templates/devtest/mail-preview.tmpl
Normal file
27
templates/devtest/mail-preview.tmpl
Normal file
@ -0,0 +1,27 @@
|
||||
{{template "devtest/devtest-header"}}
|
||||
<div class="page-content devtest ui container">
|
||||
<div class="flex-text-block tw-flex-wrap">
|
||||
{{range $templateName := .MailTemplateNames}}
|
||||
<a class="ui button" href="?tmpl={{$templateName}}">{{$templateName}}</a>
|
||||
{{else}}
|
||||
<p>Mailer service is not enabled or no template is found</p>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{if .RenderMailTemplateName}}
|
||||
<div class="tw-my-2">
|
||||
<div>Preview of: {{.RenderMailTemplateName}}</div>
|
||||
<div>Subject: {{.RenderMailSubject}}</div>
|
||||
<iframe src="{{AppSubUrl}}/devtest/mail-preview/{{.RenderMailTemplateName}}" class="mail-preview-body"></iframe>
|
||||
<style>
|
||||
.mail-preview-body {
|
||||
border: 1px solid #ccc;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{template "devtest/devtest-footer"}}
|
3
templates/mail/auth/activate.mock.yml
Normal file
3
templates/mail/auth/activate.mock.yml
Normal file
@ -0,0 +1,3 @@
|
||||
DisplayName: User Display Name
|
||||
Code: The-Activation-Code
|
||||
ActiveCodeLives: 24h
|
@ -16,7 +16,7 @@
|
||||
<td class="author">
|
||||
<div class="tw-flex">
|
||||
{{$userName := .Author.Name}}
|
||||
{{if .User}}
|
||||
{{if and .User (gt .User.ID 0)}} /* User with id == 0 is a fake user from git author */
|
||||
{{if and .User.FullName DefaultShowFullName}}
|
||||
{{$userName = .User.FullName}}
|
||||
{{end}}
|
||||
|
@ -9,7 +9,7 @@
|
||||
{{end}}
|
||||
<div class="content comment-container">
|
||||
<div class="comment-header">
|
||||
<div class="comment-header-left tw-flex tw-items-center">
|
||||
<div class="comment-header-left">
|
||||
{{if .OriginalAuthor}}
|
||||
<span class="text black tw-font-semibold tw-mr-1">
|
||||
{{svg (MigrationIcon $.root.Repository.GetOriginalURLHostname)}}
|
||||
@ -30,7 +30,7 @@
|
||||
</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="comment-header-right actions tw-flex tw-items-center">
|
||||
<div class="comment-header-right">
|
||||
{{if .Invalidated}}
|
||||
{{$referenceUrl := printf "%s#%s" $.root.Issue.Link .HashTag}}
|
||||
<a href="{{$referenceUrl}}" class="ui label basic small" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.review.outdated_description"}}">
|
||||
|
@ -14,7 +14,7 @@
|
||||
{{end}}
|
||||
<div class="content comment-container">
|
||||
<div class="comment-header" role="heading" aria-level="3">
|
||||
<div class="comment-header-left tw-flex tw-items-center">
|
||||
<div class="comment-header-left">
|
||||
{{if .Issue.OriginalAuthor}}
|
||||
<span class="text black tw-font-semibold">
|
||||
{{svg (MigrationIcon .Repository.GetOriginalURLHostname)}}
|
||||
@ -36,7 +36,7 @@
|
||||
</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="comment-header-right actions tw-flex tw-items-center">
|
||||
<div class="comment-header-right">
|
||||
{{template "repo/issue/view_content/show_role" dict "ShowRole" .Issue.ShowRole "IgnorePoster" true}}
|
||||
{{if not $.Repository.IsArchived}}
|
||||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index)}}
|
||||
|
@ -27,7 +27,7 @@
|
||||
{{end}}
|
||||
<div class="content comment-container">
|
||||
<div class="comment-header" role="heading" aria-level="3">
|
||||
<div class="comment-header-left tw-flex tw-items-center">
|
||||
<div class="comment-header-left">
|
||||
{{if .OriginalAuthor}}
|
||||
<span class="text black tw-font-semibold tw-mr-1">
|
||||
{{svg (MigrationIcon $.Repository.GetOriginalURLHostname)}}
|
||||
@ -51,7 +51,7 @@
|
||||
</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="comment-header-right actions tw-flex tw-items-center">
|
||||
<div class="comment-header-right">
|
||||
{{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}}
|
||||
{{if not $.Repository.IsArchived}}
|
||||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}}
|
||||
@ -395,7 +395,7 @@
|
||||
<div class="timeline-item comment">
|
||||
<div class="content comment-container">
|
||||
<div class="comment-header">
|
||||
<div class="comment-header-left tw-flex tw-items-center">
|
||||
<div class="comment-header-left">
|
||||
{{if gt .Poster.ID 0}}
|
||||
<a class="inline-timeline-avatar" href="{{.Poster.HomeLink}}">
|
||||
{{ctx.AvatarUtils.Avatar .Poster 24}}
|
||||
@ -416,7 +416,7 @@
|
||||
{{ctx.Locale.Tr "repo.issues.review.left_comment"}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="comment-header-right actions tw-flex tw-items-center">
|
||||
<div class="comment-header-right">
|
||||
{{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}}
|
||||
{{if not $.Repository.IsArchived}}
|
||||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}}
|
||||
|
@ -58,7 +58,7 @@
|
||||
<div class="comment code-comment" id="{{.HashTag}}">
|
||||
<div class="content comment-container">
|
||||
<div class="comment-header">
|
||||
<div class="comment-header-left tw-flex tw-items-center">
|
||||
<div class="comment-header-left">
|
||||
{{if not .OriginalAuthor}}
|
||||
<a class="avatar">
|
||||
{{ctx.AvatarUtils.Avatar .Poster 20}}
|
||||
@ -79,7 +79,7 @@
|
||||
{{ctx.Locale.Tr "repo.issues.commented_at" .HashTag $createdSubStr}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="comment-header-right actions tw-flex tw-items-center">
|
||||
<div class="comment-header-right">
|
||||
{{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}}
|
||||
{{if not $.Repository.IsArchived}}
|
||||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}}
|
||||
|
26
templates/swagger/v1_json.tmpl
generated
26
templates/swagger/v1_json.tmpl
generated
@ -5165,7 +5165,7 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/ArtifactsList"
|
||||
"$ref": "#/responses/WorkflowRunsList"
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/responses/error"
|
||||
@ -21248,6 +21248,25 @@
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"ActionWorkflowResponse": {
|
||||
"description": "ActionWorkflowResponse returns a ActionWorkflow",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total_count": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"x-go-name": "TotalCount"
|
||||
},
|
||||
"workflows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ActionWorkflow"
|
||||
},
|
||||
"x-go-name": "Workflows"
|
||||
}
|
||||
},
|
||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||
},
|
||||
"ActionWorkflowRun": {
|
||||
"description": "ActionWorkflowRun represents a WorkflowRun",
|
||||
"type": "object",
|
||||
@ -28592,10 +28611,7 @@
|
||||
"ActionWorkflowList": {
|
||||
"description": "ActionWorkflowList",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ActionWorkflow"
|
||||
}
|
||||
"$ref": "#/definitions/ActionWorkflowResponse"
|
||||
}
|
||||
},
|
||||
"ActivityFeedsList": {
|
||||
|
@ -1,124 +1,96 @@
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content user notification" id="notification_div" data-sequence-number="{{.SequenceNumber}}">
|
||||
<div class="ui container">
|
||||
{{$statusUnread := 1}}{{$statusRead := 2}}{{$statusPinned := 3}}
|
||||
{{$notificationUnreadCount := call .PageGlobalData.GetNotificationUnreadCount}}
|
||||
<div class="tw-flex tw-items-center tw-justify-between tw-mb-[--page-spacing]">
|
||||
{{$pageTypeIsRead := eq $.PageType "read"}}
|
||||
<div class="flex-text-block tw-justify-between tw-mb-[--page-spacing]">
|
||||
<div class="small-menu-items ui compact tiny menu">
|
||||
<a class="{{if eq .Status 1}}active {{end}}item" href="{{AppSubUrl}}/notifications?q=unread">
|
||||
<a class="{{if not $pageTypeIsRead}}active{{end}} item" href="{{AppSubUrl}}/notifications?type=unread">
|
||||
{{ctx.Locale.Tr "notification.unread"}}
|
||||
<div class="notifications-unread-count ui label {{if not $notificationUnreadCount}}tw-hidden{{end}}">{{$notificationUnreadCount}}</div>
|
||||
</a>
|
||||
<a class="{{if eq .Status 2}}active {{end}}item" href="{{AppSubUrl}}/notifications?q=read">
|
||||
<a class="{{if $pageTypeIsRead}}active{{end}} item" href="{{AppSubUrl}}/notifications?type=read">
|
||||
{{ctx.Locale.Tr "notification.read"}}
|
||||
</a>
|
||||
</div>
|
||||
{{if and (eq .Status 1)}}
|
||||
{{if and (not $pageTypeIsRead) $notificationUnreadCount}}
|
||||
<form action="{{AppSubUrl}}/notifications/purge" method="post">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="{{if not $notificationUnreadCount}}tw-hidden{{end}}">
|
||||
<button class="ui mini button primary tw-mr-0" title="{{ctx.Locale.Tr "notification.mark_all_as_read"}}">
|
||||
{{svg "octicon-checklist"}}
|
||||
</button>
|
||||
</div>
|
||||
<button class="ui mini button primary tw-mr-0" title="{{ctx.Locale.Tr "notification.mark_all_as_read"}}">
|
||||
{{svg "octicon-checklist"}}
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="tw-p-0">
|
||||
<div id="notification_table">
|
||||
{{if not .Notifications}}
|
||||
<div class="tw-flex tw-items-center tw-flex-col tw-p-4">
|
||||
{{svg "octicon-inbox" 56 "tw-mb-4"}}
|
||||
{{if eq .Status 1}}
|
||||
{{ctx.Locale.Tr "notification.no_unread"}}
|
||||
<div id="notification_table">
|
||||
{{range $one := .Notifications}}
|
||||
<div class="notifications-item" id="notification_{{$one.ID}}" data-status="{{$one.Status}}">
|
||||
<div class="tw-self-start tw-mt-[2px]">
|
||||
{{if $one.Issue}}
|
||||
{{template "shared/issueicon" $one.Issue}}
|
||||
{{else}}
|
||||
{{ctx.Locale.Tr "notification.no_read"}}
|
||||
{{svg "octicon-repo" 16 "text grey"}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{range $notification := .Notifications}}
|
||||
<div class="notifications-item tw-flex tw-items-center tw-flex-wrap tw-gap-2 tw-p-2" id="notification_{{.ID}}" data-status="{{.Status}}">
|
||||
<div class="notifications-icon tw-ml-2 tw-mr-1 tw-self-start tw-mt-1">
|
||||
{{if .Issue}}
|
||||
{{template "shared/issueicon" .Issue}}
|
||||
{{else}}
|
||||
{{svg "octicon-repo" 16 "text grey"}}
|
||||
{{end}}
|
||||
</div>
|
||||
<a class="notifications-link tw-flex tw-flex-1 tw-flex-col silenced" href="{{.Link ctx}}">
|
||||
<div class="notifications-top-row tw-text-13 tw-break-anywhere">
|
||||
{{.Repository.FullName}} {{if .Issue}}<span class="text light-3">#{{.Issue.Index}}</span>{{end}}
|
||||
{{if eq .Status 3}}
|
||||
{{svg "octicon-pin" 13 "text blue tw-mt-0.5 tw-ml-1"}}
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="notifications-bottom-row tw-text-16 tw-py-0.5">
|
||||
<span class="issue-title tw-break-anywhere">
|
||||
{{if .Issue}}
|
||||
{{.Issue.Title | ctx.RenderUtils.RenderIssueSimpleTitle}}
|
||||
{{else}}
|
||||
{{.Repository.FullName}}
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="notifications-updated tw-items-center tw-mr-2">
|
||||
{{if .Issue}}
|
||||
{{DateUtils.TimeSince .Issue.UpdatedUnix}}
|
||||
{{else}}
|
||||
{{DateUtils.TimeSince .UpdatedUnix}}
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="notifications-buttons tw-items-center tw-justify-end tw-gap-1 tw-px-1">
|
||||
{{if ne .Status 3}}
|
||||
<form action="{{AppSubUrl}}/notifications/status" method="post">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<input type="hidden" name="notification_id" value="{{.ID}}">
|
||||
<input type="hidden" name="status" value="pinned">
|
||||
<button class="btn interact-bg tw-p-2" title="{{ctx.Locale.Tr "notification.pin"}}"
|
||||
data-url="{{AppSubUrl}}/notifications/status"
|
||||
data-status="pinned"
|
||||
data-page="{{$.Page.Paginater.Current}}"
|
||||
data-notification-id="{{.ID}}"
|
||||
data-q="{{$.Keyword}}">
|
||||
{{svg "octicon-pin"}}
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
{{if or (eq .Status 1) (eq .Status 3)}}
|
||||
<form action="{{AppSubUrl}}/notifications/status" method="post">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<input type="hidden" name="notification_id" value="{{.ID}}">
|
||||
<input type="hidden" name="status" value="read">
|
||||
<input type="hidden" name="page" value="{{$.Page.Paginater.Current}}">
|
||||
<button class="btn interact-bg tw-p-2" title="{{ctx.Locale.Tr "notification.mark_as_read"}}"
|
||||
data-url="{{AppSubUrl}}/notifications/status"
|
||||
data-status="read"
|
||||
data-page="{{$.Page.Paginater.Current}}"
|
||||
data-notification-id="{{.ID}}"
|
||||
data-q="{{$.Keyword}}">
|
||||
{{svg "octicon-check"}}
|
||||
</button>
|
||||
</form>
|
||||
{{else if eq .Status 2}}
|
||||
<form action="{{AppSubUrl}}/notifications/status" method="post">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<input type="hidden" name="notification_id" value="{{.ID}}">
|
||||
<input type="hidden" name="status" value="unread">
|
||||
<input type="hidden" name="page" value="{{$.Page.Paginater.Current}}">
|
||||
<button class="btn interact-bg tw-p-2" title="{{ctx.Locale.Tr "notification.mark_as_unread"}}"
|
||||
data-url="{{AppSubUrl}}/notifications/status"
|
||||
data-status="unread"
|
||||
data-page="{{$.Page.Paginater.Current}}"
|
||||
data-notification-id="{{.ID}}"
|
||||
data-q="{{$.Keyword}}">
|
||||
{{svg "octicon-bell"}}
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
<a class="notifications-link silenced tw-flex-1" href="{{$one.Link ctx}}">
|
||||
<div class="flex-text-block tw-text-[0.95em]">
|
||||
{{$one.Repository.FullName}} {{if $one.Issue}}<span class="text light-3">#{{$one.Issue.Index}}</span>{{end}}
|
||||
{{if eq $one.Status $statusPinned}}
|
||||
{{svg "octicon-pin" 13 "text blue"}}
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="tw-text-16 tw-py-0.5">
|
||||
{{if $one.Issue}}
|
||||
{{$one.Issue.Title | ctx.RenderUtils.RenderIssueSimpleTitle}}
|
||||
{{else}}
|
||||
{{$one.Repository.FullName}}
|
||||
{{end}}
|
||||
</div>
|
||||
</a>
|
||||
<div class="notifications-updated flex-text-inline">
|
||||
{{if $one.Issue}}
|
||||
{{DateUtils.TimeSince $one.Issue.UpdatedUnix}}
|
||||
{{else}}
|
||||
{{DateUtils.TimeSince $one.UpdatedUnix}}
|
||||
{{end}}
|
||||
</div>
|
||||
<form class="notifications-buttons" action="{{AppSubUrl}}/notifications/status?type={{$.PageType}}&page={{$.Page.Paginater.Current}}&perPage={{$.Page.Paginater.PagingNum}}" method="post"
|
||||
hx-boost="true" hx-target="#notification_div" hx-swap="outerHTML"
|
||||
>
|
||||
{{$.CsrfTokenHtml}}
|
||||
<input type="hidden" name="notification_id" value="{{$one.ID}}">
|
||||
{{if ne $one.Status $statusPinned}}
|
||||
<button class="btn interact-bg tw-p-2" data-tooltip-content="{{ctx.Locale.Tr "notification.pin"}}"
|
||||
name="notification_action" value="pin"
|
||||
>
|
||||
{{svg "octicon-pin"}}
|
||||
</button>
|
||||
{{end}}
|
||||
{{if or (eq $one.Status $statusUnread) (eq $one.Status $statusPinned)}}
|
||||
<button class="btn interact-bg tw-p-2" data-tooltip-content="{{ctx.Locale.Tr "notification.mark_as_read"}}"
|
||||
name="notification_action" value="mark_as_read"
|
||||
>
|
||||
{{svg "octicon-check"}}
|
||||
</button>
|
||||
{{else if eq $one.Status $statusRead}}
|
||||
<button class="btn interact-bg tw-p-2" data-tooltip-content="{{ctx.Locale.Tr "notification.mark_as_unread"}}"
|
||||
name="notification_action" value="mark_as_unread"
|
||||
>
|
||||
{{svg "octicon-bell"}}
|
||||
</button>
|
||||
{{end}}
|
||||
</form>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="empty-placeholder">
|
||||
{{svg "octicon-inbox" 56 "tw-mb-4"}}
|
||||
{{if $pageTypeIsRead}}
|
||||
{{ctx.Locale.Tr "notification.no_read"}}
|
||||
{{else}}
|
||||
{{ctx.Locale.Tr "notification.no_unread"}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{template "base/paginate" .}}
|
||||
</div>
|
||||
|
@ -185,10 +185,6 @@ details summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
details summary > * {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
progress {
|
||||
background: var(--color-secondary-dark-1);
|
||||
border-radius: var(--border-radius);
|
||||
@ -474,15 +470,6 @@ a.label,
|
||||
color: var(--color-text-light-2);
|
||||
}
|
||||
|
||||
.ui.comments .comment .actions a {
|
||||
color: var(--color-text-light);
|
||||
}
|
||||
|
||||
.ui.comments .comment .actions a.active,
|
||||
.ui.comments .comment .actions a:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
img.ui.avatar,
|
||||
.ui.avatar img,
|
||||
.ui.avatar svg {
|
||||
|
@ -93,7 +93,6 @@ a.ui.label:hover {
|
||||
background: var(--color-button);
|
||||
border: 1px solid var(--color-light-border);
|
||||
color: var(--color-text-light);
|
||||
padding: calc(0.5833em - 1px) calc(0.833em - 1px);
|
||||
}
|
||||
a.ui.basic.label:hover {
|
||||
text-decoration: none;
|
||||
@ -254,6 +253,7 @@ a.ui.ui.ui.basic.grey.label:hover {
|
||||
color: var(--color-label-hover-bg);
|
||||
}
|
||||
|
||||
/* "horizontal label" is actually "fat label" which has enough padding spaces to be used standalone in headers */
|
||||
.ui.horizontal.label {
|
||||
margin: 0 0.5em 0 0;
|
||||
padding: 0.4em 0.833em;
|
||||
|
@ -1420,13 +1420,15 @@ td .commit-summary {
|
||||
.comment-header {
|
||||
background: var(--color-box-header);
|
||||
border-bottom: 1px solid var(--color-secondary);
|
||||
padding: 0 1rem;
|
||||
padding: 0.5em 1rem;
|
||||
position: relative;
|
||||
color: var(--color-text);
|
||||
min-height: 41px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25em;
|
||||
}
|
||||
|
||||
.comment-header::before,
|
||||
@ -1468,17 +1470,16 @@ td .commit-summary {
|
||||
left: 7px;
|
||||
}
|
||||
|
||||
.comment-header .actions a:not(.label) {
|
||||
padding: 0.5rem !important;
|
||||
}
|
||||
|
||||
.comment-header .actions .label {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.comment-header-left,
|
||||
.comment-header-right {
|
||||
gap: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.comment-header-right {
|
||||
flex: 1;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.comment-body {
|
||||
@ -2014,15 +2015,6 @@ tbody.commit-list {
|
||||
.commit-table th.sha {
|
||||
display: none !important;
|
||||
}
|
||||
.comment-header {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.comment-header .comment-header-left {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.comment-header .comment-header-right {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.commit-status-header {
|
||||
|
@ -114,6 +114,14 @@
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.notifications-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em;
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
.notifications-item:hover {
|
||||
background: var(--color-hover);
|
||||
}
|
||||
@ -129,6 +137,9 @@
|
||||
|
||||
.notifications-item:hover .notifications-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
gap: 0.25em;
|
||||
}
|
||||
|
||||
.notifications-item:hover .notifications-updated {
|
||||
|
@ -2,7 +2,7 @@ import type {FileRenderPlugin} from '../render/plugin.ts';
|
||||
import {newRenderPlugin3DViewer} from '../render/plugins/3d-viewer.ts';
|
||||
import {newRenderPluginPdfViewer} from '../render/plugins/pdf-viewer.ts';
|
||||
import {registerGlobalInitFunc} from '../modules/observer.ts';
|
||||
import {createElementFromHTML, showElem, toggleClass} from '../utils/dom.ts';
|
||||
import {createElementFromHTML, showElem, toggleElemClass} from '../utils/dom.ts';
|
||||
import {html} from '../utils/html.ts';
|
||||
import {basename} from '../utils.ts';
|
||||
|
||||
@ -21,8 +21,8 @@ function showRenderRawFileButton(elFileView: HTMLElement, renderContainer: HTMLE
|
||||
const toggleButtons = elFileView.querySelector('.file-view-toggle-buttons');
|
||||
showElem(toggleButtons);
|
||||
const displayingRendered = Boolean(renderContainer);
|
||||
toggleClass(toggleButtons.querySelectorAll('.file-view-toggle-source'), 'active', !displayingRendered); // it may not exist
|
||||
toggleClass(toggleButtons.querySelector('.file-view-toggle-rendered'), 'active', displayingRendered);
|
||||
toggleElemClass(toggleButtons.querySelectorAll('.file-view-toggle-source'), 'active', !displayingRendered); // it may not exist
|
||||
toggleElemClass(toggleButtons.querySelector('.file-view-toggle-rendered'), 'active', displayingRendered);
|
||||
// TODO: if there is only one button, hide it?
|
||||
}
|
||||
|
||||
|
@ -1,40 +1,13 @@
|
||||
import {GET} from '../modules/fetch.ts';
|
||||
import {toggleElem, type DOMEvent, createElementFromHTML} from '../utils/dom.ts';
|
||||
import {toggleElem, createElementFromHTML} from '../utils/dom.ts';
|
||||
import {logoutFromWorker} from '../modules/worker.ts';
|
||||
|
||||
const {appSubUrl, notificationSettings, assetVersionEncoded} = window.config;
|
||||
let notificationSequenceNumber = 0;
|
||||
|
||||
export function initNotificationsTable() {
|
||||
const table = document.querySelector('#notification_table');
|
||||
if (!table) return;
|
||||
|
||||
// when page restores from bfcache, delete previously clicked items
|
||||
window.addEventListener('pageshow', (e) => {
|
||||
if (e.persisted) { // page was restored from bfcache
|
||||
const table = document.querySelector('#notification_table');
|
||||
const unreadCountEl = document.querySelector<HTMLElement>('.notifications-unread-count');
|
||||
let unreadCount = parseInt(unreadCountEl.textContent);
|
||||
for (const item of table.querySelectorAll('.notifications-item[data-remove="true"]')) {
|
||||
item.remove();
|
||||
unreadCount -= 1;
|
||||
}
|
||||
unreadCountEl.textContent = String(unreadCount);
|
||||
}
|
||||
});
|
||||
|
||||
// mark clicked unread links for deletion on bfcache restore
|
||||
for (const link of table.querySelectorAll<HTMLAnchorElement>('.notifications-item[data-status="1"] .notifications-link')) {
|
||||
link.addEventListener('click', (e: DOMEvent<MouseEvent>) => {
|
||||
e.target.closest('.notifications-item').setAttribute('data-remove', 'true');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function receiveUpdateCount(event: MessageEvent) {
|
||||
async function receiveUpdateCount(event: MessageEvent<{type: string, data: string}>) {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
const data = JSON.parse(event.data.data);
|
||||
for (const count of document.querySelectorAll('.notification_count')) {
|
||||
count.classList.toggle('tw-hidden', data.Count === 0);
|
||||
count.textContent = `${data.Count}`;
|
||||
@ -71,7 +44,7 @@ export function initNotificationCount() {
|
||||
type: 'start',
|
||||
url: `${window.location.origin}${appSubUrl}/user/events`,
|
||||
});
|
||||
worker.port.addEventListener('message', (event: MessageEvent) => {
|
||||
worker.port.addEventListener('message', (event: MessageEvent<{type: string, data: string}>) => {
|
||||
if (!event.data || !event.data.type) {
|
||||
console.error('unknown worker message event', event);
|
||||
return;
|
||||
@ -144,11 +117,11 @@ async function updateNotificationCountWithCallback(callback: (timeout: number, n
|
||||
}
|
||||
|
||||
async function updateNotificationTable() {
|
||||
const notificationDiv = document.querySelector('#notification_div');
|
||||
let notificationDiv = document.querySelector('#notification_div');
|
||||
if (notificationDiv) {
|
||||
try {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.set('div-only', String(true));
|
||||
params.set('div-only', 'true');
|
||||
params.set('sequence-number', String(++notificationSequenceNumber));
|
||||
const response = await GET(`${appSubUrl}/notifications?${params.toString()}`);
|
||||
|
||||
@ -160,7 +133,8 @@ async function updateNotificationTable() {
|
||||
const el = createElementFromHTML(data);
|
||||
if (parseInt(el.getAttribute('data-sequence-number')) === notificationSequenceNumber) {
|
||||
notificationDiv.outerHTML = data;
|
||||
initNotificationsTable();
|
||||
notificationDiv = document.querySelector('#notification_div');
|
||||
window.htmx.process(notificationDiv); // when using htmx, we must always remember to process the new content changed by us
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
@ -138,7 +138,14 @@ function initDiffHeaderPopup() {
|
||||
btn.setAttribute('data-header-popup-initialized', '');
|
||||
const popup = btn.nextElementSibling;
|
||||
if (!popup?.matches('.tippy-target')) throw new Error('Popup element not found');
|
||||
createTippy(btn, {content: popup, theme: 'menu', placement: 'bottom', trigger: 'click', interactive: true, hideOnClick: true});
|
||||
createTippy(btn, {
|
||||
content: popup,
|
||||
theme: 'menu',
|
||||
placement: 'bottom-end',
|
||||
trigger: 'click',
|
||||
interactive: true,
|
||||
hideOnClick: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {toggleClass} from '../utils/dom.ts';
|
||||
import {toggleElemClass} from '../utils/dom.ts';
|
||||
import {GET} from '../modules/fetch.ts';
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
|
||||
@ -9,11 +9,11 @@ export function initRepoGraphGit() {
|
||||
const elColorMonochrome = document.querySelector<HTMLElement>('#flow-color-monochrome');
|
||||
const elColorColored = document.querySelector<HTMLElement>('#flow-color-colored');
|
||||
const toggleColorMode = (mode: 'monochrome' | 'colored') => {
|
||||
toggleClass(graphContainer, 'monochrome', mode === 'monochrome');
|
||||
toggleClass(graphContainer, 'colored', mode === 'colored');
|
||||
toggleElemClass(graphContainer, 'monochrome', mode === 'monochrome');
|
||||
toggleElemClass(graphContainer, 'colored', mode === 'colored');
|
||||
|
||||
toggleClass(elColorMonochrome, 'active', mode === 'monochrome');
|
||||
toggleClass(elColorColored, 'active', mode === 'colored');
|
||||
toggleElemClass(elColorMonochrome, 'active', mode === 'monochrome');
|
||||
toggleElemClass(elColorColored, 'active', mode === 'colored');
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.set('mode', mode);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {minimatch} from 'minimatch';
|
||||
import {createMonaco} from './codeeditor.ts';
|
||||
import {onInputDebounce, queryElems, toggleClass, toggleElem} from '../utils/dom.ts';
|
||||
import {onInputDebounce, queryElems, toggleElem} from '../utils/dom.ts';
|
||||
import {POST} from '../modules/fetch.ts';
|
||||
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
@ -124,14 +124,18 @@ function initRepoSettingsOptions() {
|
||||
const pageContent = document.querySelector('.page-content.repository.settings.options');
|
||||
if (!pageContent) return;
|
||||
|
||||
// Enable or select internal/external wiki system and issue tracker.
|
||||
// toggle related panels for the checkbox/radio inputs, the "selector" may not exist
|
||||
const toggleTargetContextPanel = (selector: string, enabled: boolean) => {
|
||||
if (!selector) return;
|
||||
queryElems(document, selector, (el) => el.classList.toggle('disabled', !enabled));
|
||||
};
|
||||
queryElems<HTMLInputElement>(pageContent, '.enable-system', (el) => el.addEventListener('change', () => {
|
||||
toggleClass(el.getAttribute('data-target'), 'disabled', !el.checked);
|
||||
toggleClass(el.getAttribute('data-context'), 'disabled', el.checked);
|
||||
toggleTargetContextPanel(el.getAttribute('data-target'), el.checked);
|
||||
toggleTargetContextPanel(el.getAttribute('data-context'), !el.checked);
|
||||
}));
|
||||
queryElems<HTMLInputElement>(pageContent, '.enable-system-radio', (el) => el.addEventListener('change', () => {
|
||||
toggleClass(el.getAttribute('data-target'), 'disabled', el.value === 'false');
|
||||
toggleClass(el.getAttribute('data-context'), 'disabled', el.value === 'true');
|
||||
toggleTargetContextPanel(el.getAttribute('data-target'), el.value === 'true');
|
||||
toggleTargetContextPanel(el.getAttribute('data-context'), el.value === 'false');
|
||||
}));
|
||||
|
||||
queryElems<HTMLInputElement>(pageContent, '.js-tracker-issue-style', (el) => el.addEventListener('change', () => {
|
||||
|
@ -15,7 +15,7 @@ import {initTableSort} from './features/tablesort.ts';
|
||||
import {initAdminUserListSearchForm} from './features/admin/users.ts';
|
||||
import {initAdminConfigs} from './features/admin/config.ts';
|
||||
import {initMarkupAnchors} from './markup/anchors.ts';
|
||||
import {initNotificationCount, initNotificationsTable} from './features/notification.ts';
|
||||
import {initNotificationCount} from './features/notification.ts';
|
||||
import {initRepoIssueContentHistory} from './features/repo-issue-content.ts';
|
||||
import {initStopwatch} from './features/stopwatch.ts';
|
||||
import {initFindFileInRepo} from './features/repo-findfile.ts';
|
||||
@ -117,7 +117,6 @@ const initPerformanceTracer = callInitFunctions([
|
||||
initDashboardRepoList,
|
||||
|
||||
initNotificationCount,
|
||||
initNotificationsTable,
|
||||
|
||||
initOrgTeam,
|
||||
|
||||
|
@ -9,5 +9,15 @@ import {onDomReady} from './utils/dom.ts';
|
||||
import 'htmx.org';
|
||||
|
||||
onDomReady(async () => {
|
||||
await import(/* webpackChunkName: "index-domready" */'./index-domready.ts');
|
||||
// when navigate before the import complete, there will be an error from webpack chunk loader:
|
||||
// JavaScript promise rejection: Loading chunk index-domready failed.
|
||||
try {
|
||||
await import(/* webpackChunkName: "index-domready" */'./index-domready.ts');
|
||||
} catch (e) {
|
||||
if (e.name === 'ChunkLoadError') {
|
||||
console.error('Error loading index-domready:', e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -44,7 +44,7 @@ type ToastifyElement = HTMLElement & {_giteaToastifyInstance?: Toast };
|
||||
|
||||
// See https://github.com/apvarun/toastify-js#api for options
|
||||
function showToast(message: string, level: Intent, {gravity, position, duration, useHtmlBody, preventDuplicates = true, ...other}: ToastOpts = {}): Toast {
|
||||
const body = useHtmlBody ? String(message) : htmlEscape(message);
|
||||
const body = useHtmlBody ? message : htmlEscape(message);
|
||||
const parent = document.querySelector('.ui.dimmer.active') ?? document.body;
|
||||
const duplicateKey = preventDuplicates ? (preventDuplicates === true ? `${level}-${body}` : preventDuplicates) : '';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {decode, encode} from 'uint8-to-base64';
|
||||
import type {IssuePageInfo, IssuePathInfo, RepoOwnerPathInfo} from './types.ts';
|
||||
import {toggleClass, toggleElem} from './utils/dom.ts';
|
||||
import {toggleElemClass, toggleElem} from './utils/dom.ts';
|
||||
|
||||
// transform /path/to/file.ext to /path/to
|
||||
export function dirname(path: string): string {
|
||||
@ -194,7 +194,7 @@ export function toggleFullScreen(fullscreenElementsSelector: string, isFullScree
|
||||
|
||||
const fullScreenEl = document.querySelector(fullscreenElementsSelector);
|
||||
const outerEl = document.querySelector('.full.height');
|
||||
toggleClass(fullscreenElementsSelector, 'fullscreen', isFullScreen);
|
||||
toggleElemClass(fullscreenElementsSelector, 'fullscreen', isFullScreen);
|
||||
if (isFullScreen) {
|
||||
outerEl.append(fullScreenEl);
|
||||
} else {
|
||||
|
@ -25,7 +25,7 @@ function elementsCall(el: ElementArg, func: ElementsCallbackWithArgs, ...args: a
|
||||
throw new Error('invalid argument to be shown/hidden');
|
||||
}
|
||||
|
||||
export function toggleClass(el: ElementArg, className: string, force?: boolean): ArrayLikeIterable<Element> {
|
||||
export function toggleElemClass(el: ElementArg, className: string, force?: boolean): ArrayLikeIterable<Element> {
|
||||
return elementsCall(el, (e: Element) => {
|
||||
if (force === true) {
|
||||
e.classList.add(className);
|
||||
@ -44,7 +44,7 @@ export function toggleClass(el: ElementArg, className: string, force?: boolean):
|
||||
* @param force force=true to show or force=false to hide, undefined to toggle
|
||||
*/
|
||||
export function toggleElem(el: ElementArg, force?: boolean): ArrayLikeIterable<Element> {
|
||||
return toggleClass(el, 'tw-hidden', force === undefined ? force : !force);
|
||||
return toggleElemClass(el, 'tw-hidden', force === undefined ? force : !force);
|
||||
}
|
||||
|
||||
export function showElem(el: ElementArg): ArrayLikeIterable<Element> {
|
||||
@ -283,7 +283,7 @@ export function isElemVisible(el: HTMLElement): boolean {
|
||||
// This function DOESN'T account for all possible visibility scenarios, its behavior is covered by the tests of "querySingleVisibleElem"
|
||||
if (!el) return false;
|
||||
// checking el.style.display is not necessary for browsers, but it is required by some tests with happy-dom because happy-dom doesn't really do layout
|
||||
return !el.classList.contains('tw-hidden') && Boolean((el.offsetWidth || el.offsetHeight || el.getClientRects().length) && el.style.display !== 'none');
|
||||
return !el.classList.contains('tw-hidden') && (el.offsetWidth || el.offsetHeight || el.getClientRects().length) && el.style.display !== 'none';
|
||||
}
|
||||
|
||||
// replace selected text in a textarea while preserving editor history, e.g. CTRL-Z works after this
|
||||
|
Loading…
x
Reference in New Issue
Block a user