Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 07409afc4c | |||
| 0789135e85 | |||
| b285606044 | |||
| 90f3cc9166 | |||
| 26fde4a50e | |||
| 5996661b6f | |||
| b64ed1972a | |||
| 71e0af4196 |
@@ -32,9 +32,66 @@ func Branding(ctx *context.Context) {
|
||||
ctx.Data["HasLogo"] = fileExists(filepath.Join(imgDir, "logo.png"))
|
||||
ctx.Data["HasFavicon"] = fileExists(filepath.Join(imgDir, "favicon.png"))
|
||||
|
||||
ctx.Data["MetaDescription"] = setting.UI.Meta.Description
|
||||
ctx.Data["MetaAuthor"] = setting.UI.Meta.Author
|
||||
ctx.Data["HelpURL"] = setting.HelpURL
|
||||
ctx.Data["SupportURL"] = setting.SupportURL
|
||||
|
||||
ctx.HTML(http.StatusOK, tplBranding)
|
||||
}
|
||||
|
||||
// BrandingSettings handles the text branding form submission.
|
||||
func BrandingSettings(ctx *context.Context) {
|
||||
appName := ctx.FormString("app_name")
|
||||
description := ctx.FormString("description")
|
||||
helpURL := ctx.FormString("help_url")
|
||||
supportURL := ctx.FormString("support_url")
|
||||
author := ctx.FormString("author")
|
||||
|
||||
// Update in-memory settings
|
||||
if appName != "" {
|
||||
setting.AppName = appName
|
||||
}
|
||||
if description != "" {
|
||||
setting.UI.Meta.Description = description
|
||||
}
|
||||
setting.HelpURL = helpURL
|
||||
setting.SupportURL = supportURL
|
||||
if author != "" {
|
||||
setting.UI.Meta.Author = author
|
||||
}
|
||||
|
||||
// Persist to app.ini
|
||||
cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
|
||||
if err != nil {
|
||||
ctx.Flash.Error("Failed to load config: " + err.Error())
|
||||
ctx.Redirect(setting.AppSubURL + "/-/admin/branding")
|
||||
return
|
||||
}
|
||||
|
||||
if appName != "" {
|
||||
cfg.Section("").Key("APP_NAME").SetValue(appName)
|
||||
}
|
||||
if description != "" {
|
||||
cfg.Section("ui.meta").Key("DESCRIPTION").SetValue(description)
|
||||
}
|
||||
cfg.Section("").Key("HELP_URL").SetValue(helpURL)
|
||||
cfg.Section("").Key("SUPPORT_URL").SetValue(supportURL)
|
||||
if author != "" {
|
||||
cfg.Section("ui.meta").Key("AUTHOR").SetValue(author)
|
||||
}
|
||||
|
||||
if err := cfg.SaveTo(setting.CustomConf); err != nil {
|
||||
ctx.Flash.Error("Failed to save config: " + err.Error())
|
||||
log.Error("SaveTo %s: %v", setting.CustomConf, err)
|
||||
} else {
|
||||
ctx.Flash.Success("Branding settings saved")
|
||||
log.Info("Branding settings updated: AppName=%s, Author=%s", appName, author)
|
||||
}
|
||||
|
||||
ctx.Redirect(setting.AppSubURL + "/-/admin/branding")
|
||||
}
|
||||
|
||||
// BrandingUpload handles branding image uploads.
|
||||
func BrandingUpload(ctx *context.Context) {
|
||||
imageType := ctx.FormString("type")
|
||||
@@ -66,14 +123,12 @@ func BrandingUpload(ctx *context.Context) {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Validate file size (max 2MB)
|
||||
if header.Size > 2*1024*1024 {
|
||||
ctx.Flash.Error("File too large (max 2MB)")
|
||||
ctx.Redirect(setting.AppSubURL + "/-/admin/branding")
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure the custom image directory exists
|
||||
imgDir := brandingImageDir()
|
||||
if err := os.MkdirAll(imgDir, 0o755); err != nil {
|
||||
ctx.Flash.Error("Failed to create image directory")
|
||||
@@ -82,7 +137,6 @@ func BrandingUpload(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Write the file
|
||||
destPath := filepath.Join(imgDir, filename)
|
||||
dest, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
@@ -100,11 +154,10 @@ func BrandingUpload(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Also remove SVG override if present (PNG should take priority)
|
||||
// Remove SVG override if present
|
||||
svgPath := filepath.Join(imgDir, filename[:len(filename)-4]+".svg")
|
||||
if fileExists(svgPath) {
|
||||
os.Remove(svgPath)
|
||||
log.Info("Removed SVG override: %s", svgPath)
|
||||
}
|
||||
|
||||
ctx.Flash.Success("Branding image updated: " + imageType)
|
||||
@@ -112,6 +165,40 @@ func BrandingUpload(ctx *context.Context) {
|
||||
ctx.Redirect(setting.AppSubURL + "/-/admin/branding")
|
||||
}
|
||||
|
||||
// BrandingReset removes a custom branding image, reverting to the built-in default.
|
||||
func BrandingReset(ctx *context.Context) {
|
||||
imageType := ctx.FormString("type")
|
||||
|
||||
var filename string
|
||||
switch imageType {
|
||||
case "nav-icon":
|
||||
filename = "logo-small.png"
|
||||
case "logo":
|
||||
filename = "logo.png"
|
||||
case "favicon":
|
||||
filename = "favicon.png"
|
||||
default:
|
||||
ctx.Flash.Error("Invalid image type")
|
||||
ctx.Redirect(setting.AppSubURL + "/-/admin/branding")
|
||||
return
|
||||
}
|
||||
|
||||
path := filepath.Join(brandingImageDir(), filename)
|
||||
if fileExists(path) {
|
||||
if err := os.Remove(path); err != nil {
|
||||
ctx.Flash.Error("Failed to remove custom image")
|
||||
log.Error("Remove %s: %v", path, err)
|
||||
} else {
|
||||
ctx.Flash.Success("Reset to default: " + imageType)
|
||||
log.Info("Branding reset to default: %s", filename)
|
||||
}
|
||||
} else {
|
||||
ctx.Flash.Info("Already using default: " + imageType)
|
||||
}
|
||||
|
||||
ctx.Redirect(setting.AppSubURL + "/-/admin/branding")
|
||||
}
|
||||
|
||||
func fileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
|
||||
@@ -768,6 +768,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {
|
||||
m.Group("/branding", func() {
|
||||
m.Get("", admin.Branding)
|
||||
m.Post("/upload", admin.BrandingUpload)
|
||||
m.Post("/settings", admin.BrandingSettings)
|
||||
m.Get("/reset", admin.BrandingReset)
|
||||
})
|
||||
|
||||
m.Group("/monitor", func() {
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
|
||||
"git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
|
||||
@@ -18,8 +17,9 @@ import (
|
||||
)
|
||||
|
||||
// GenerateReleaseChecksums computes SHA256 checksums for all attachments
|
||||
// on a release and creates a [filename].sha256 file for each one.
|
||||
// on a release and adds a checksums.sha256 manifest file as an attachment.
|
||||
func GenerateReleaseChecksums(ctx context.Context, rel *repo_model.Release) error {
|
||||
// Load attachments into rel.Attachments
|
||||
if err := repo_model.GetReleaseAttachments(ctx, rel); err != nil {
|
||||
return fmt.Errorf("GetReleaseAttachments: %w", err)
|
||||
}
|
||||
@@ -28,19 +28,20 @@ func GenerateReleaseChecksums(ctx context.Context, rel *repo_model.Release) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove existing .sha256 files
|
||||
// Remove existing checksums file if present
|
||||
for _, a := range rel.Attachments {
|
||||
if strings.HasSuffix(a.Name, ".sha256") {
|
||||
if a.Name == "checksums.sha256" {
|
||||
if err := repo_model.DeleteAttachment(ctx, a, true); err != nil {
|
||||
log.Warn("Failed to delete old %s: %v", a.Name, err)
|
||||
log.Warn("Failed to delete old checksums.sha256: %v", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Compute SHA256 for each non-checksum attachment and create individual .sha256 files
|
||||
created := 0
|
||||
// Compute SHA256 for each attachment
|
||||
var manifest bytes.Buffer
|
||||
for _, a := range rel.Attachments {
|
||||
if strings.HasSuffix(a.Name, ".sha256") {
|
||||
if a.Name == "checksums.sha256" {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -58,24 +59,24 @@ func GenerateReleaseChecksums(ctx context.Context, rel *repo_model.Release) erro
|
||||
}
|
||||
fr.Close()
|
||||
|
||||
checksumContent := fmt.Sprintf("%x %s\n", h.Sum(nil), a.Name)
|
||||
checksumReader := bytes.NewBufferString(checksumContent)
|
||||
|
||||
checksumAttach := &repo_model.Attachment{
|
||||
RepoID: rel.RepoID,
|
||||
ReleaseID: rel.ID,
|
||||
Name: a.Name + ".sha256",
|
||||
}
|
||||
|
||||
if _, err := attachment_service.NewAttachment(ctx, checksumAttach, checksumReader, int64(len(checksumContent))); err != nil {
|
||||
log.Warn("Failed to create %s: %v", checksumAttach.Name, err)
|
||||
continue
|
||||
}
|
||||
created++
|
||||
fmt.Fprintf(&manifest, "%x %s\n", h.Sum(nil), a.Name)
|
||||
}
|
||||
|
||||
if created > 0 {
|
||||
log.Info("Generated %d .sha256 checksum files for release %s (repo %d)", created, rel.TagName, rel.RepoID)
|
||||
if manifest.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create the checksums.sha256 attachment
|
||||
checksumAttach := &repo_model.Attachment{
|
||||
RepoID: rel.RepoID,
|
||||
ReleaseID: rel.ID,
|
||||
Name: "checksums.sha256",
|
||||
}
|
||||
|
||||
if _, err := attachment_service.NewAttachment(ctx, checksumAttach, &manifest, int64(manifest.Len())); err != nil {
|
||||
return fmt.Errorf("create checksums.sha256 attachment: %w", err)
|
||||
}
|
||||
|
||||
log.Info("Generated checksums.sha256 for release %s (repo %d)", rel.TagName, rel.RepoID)
|
||||
return nil
|
||||
}
|
||||
|
||||
+104
-58
@@ -4,67 +4,113 @@
|
||||
{{svg "octicon-paintbrush" 16}} Branding
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p>Upload custom branding images. Changes take effect immediately.</p>
|
||||
|
||||
<!-- Nav Icon -->
|
||||
<div class="ui segment">
|
||||
<div class="tw-flex tw-items-center tw-gap-4 tw-mb-4">
|
||||
<img src="{{AssetUrlPrefix}}/img/logo-small.png?v={{ctx.CspScriptNonce}}" style="width: 48px; height: 48px; object-fit: contain;" onerror="this.src='{{AssetUrlPrefix}}/img/logo.png'">
|
||||
<div>
|
||||
<strong>Nav Icon</strong>
|
||||
<div class="tw-text-text-light">Top-left corner, 30x30px recommended</div>
|
||||
</div>
|
||||
{{if .HasNavIcon}}<span class="ui green label">Custom</span>{{else}}<span class="ui grey label">Default</span>{{end}}
|
||||
</div>
|
||||
<form method="post" action="{{AppSubUrl}}/-/admin/branding/upload" enctype="multipart/form-data">
|
||||
{{.CsrfTokenHtml}}
|
||||
<input type="hidden" name="type" value="nav-icon">
|
||||
<div class="tw-flex tw-gap-2">
|
||||
<input type="file" name="file" accept="image/png,image/svg+xml" required>
|
||||
<button type="submit" class="ui primary small button">{{svg "octicon-upload" 14}} Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- Text Branding -->
|
||||
<h5>Identity</h5>
|
||||
<form method="post" action="{{AppSubUrl}}/-/admin/branding/settings">
|
||||
{{.CsrfTokenHtml}}
|
||||
<table class="ui very basic table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 30%;"><strong>Application Name</strong><div class="tw-text-text-light tw-text-sm">Shown in page titles, emails, and footer</div></td>
|
||||
<td><input type="text" name="app_name" value="{{AppName}}" class="tw-w-full" placeholder="MokoGitea"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Description</strong><div class="tw-text-text-light tw-text-sm">Meta description for SEO and social sharing</div></td>
|
||||
<td><input type="text" name="description" value="{{.MetaDescription}}" class="tw-w-full" placeholder="Self-hosted Git service"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Help URL</strong><div class="tw-text-text-light tw-text-sm">Knowledge base or documentation link shown in help menus</div></td>
|
||||
<td><input type="text" name="help_url" value="{{.HelpURL}}" class="tw-w-full" placeholder="https://git.mokoconsulting.tech/MokoConsulting/MokoGitea/wiki"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Support URL</strong><div class="tw-text-text-light tw-text-sm">Ticket system, email, or contact page for user support requests</div></td>
|
||||
<td><input type="text" name="support_url" value="{{.SupportURL}}" class="tw-w-full" placeholder="https://mokoconsulting.tech/support"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Author</strong><div class="tw-text-text-light tw-text-sm">Meta author tag</div></td>
|
||||
<td><input type="text" name="author" value="{{.MetaAuthor}}" class="tw-w-full" placeholder="Moko Consulting"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="submit" class="ui primary small button tw-mt-2">{{svg "octicon-check" 14}} Save Settings</button>
|
||||
</form>
|
||||
|
||||
<!-- Login Logo -->
|
||||
<div class="ui segment">
|
||||
<div class="tw-flex tw-items-center tw-gap-4 tw-mb-4">
|
||||
<img src="{{AssetUrlPrefix}}/img/logo.png?v={{ctx.CspScriptNonce}}" style="max-width: 120px; max-height: 48px; object-fit: contain;">
|
||||
<div>
|
||||
<strong>Login Logo</strong>
|
||||
<div class="tw-text-text-light">Login page and homepage, wide format recommended</div>
|
||||
</div>
|
||||
{{if .HasLogo}}<span class="ui green label">Custom</span>{{else}}<span class="ui grey label">Default</span>{{end}}
|
||||
</div>
|
||||
<form method="post" action="{{AppSubUrl}}/-/admin/branding/upload" enctype="multipart/form-data">
|
||||
{{.CsrfTokenHtml}}
|
||||
<input type="hidden" name="type" value="logo">
|
||||
<div class="tw-flex tw-gap-2">
|
||||
<input type="file" name="file" accept="image/png,image/svg+xml" required>
|
||||
<button type="submit" class="ui primary small button">{{svg "octicon-upload" 14}} Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<!-- Favicon -->
|
||||
<div class="ui segment">
|
||||
<div class="tw-flex tw-items-center tw-gap-4 tw-mb-4">
|
||||
<img src="{{AssetUrlPrefix}}/img/favicon.png?v={{ctx.CspScriptNonce}}" style="width: 48px; height: 48px; object-fit: contain;">
|
||||
<div>
|
||||
<strong>Favicon</strong>
|
||||
<div class="tw-text-text-light">Browser tab icon, 256x256px recommended</div>
|
||||
</div>
|
||||
{{if .HasFavicon}}<span class="ui green label">Custom</span>{{else}}<span class="ui grey label">Default</span>{{end}}
|
||||
</div>
|
||||
<form method="post" action="{{AppSubUrl}}/-/admin/branding/upload" enctype="multipart/form-data">
|
||||
{{.CsrfTokenHtml}}
|
||||
<input type="hidden" name="type" value="favicon">
|
||||
<div class="tw-flex tw-gap-2">
|
||||
<input type="file" name="file" accept="image/png,image/svg+xml,image/x-icon" required>
|
||||
<button type="submit" class="ui primary small button">{{svg "octicon-upload" 14}} Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- Image Branding -->
|
||||
<h5>Images</h5>
|
||||
<p class="tw-text-text-light tw-text-sm">Changes take effect immediately.</p>
|
||||
<table class="ui very basic table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 30%;">Setting</th>
|
||||
<th style="width: 40%;">Upload</th>
|
||||
<th style="width: 30%;">Preview</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Nav Icon -->
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Nav Icon</strong> {{if .HasNavIcon}}<span class="ui mini green label">Custom</span>{{else}}<span class="ui mini grey label">Default</span>{{end}}
|
||||
<div class="tw-text-text-light tw-text-sm tw-mt-1">Top-left corner across all pages. Square, 30x30px.</div>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" action="{{AppSubUrl}}/-/admin/branding/upload" enctype="multipart/form-data">
|
||||
{{.CsrfTokenHtml}}
|
||||
<input type="hidden" name="type" value="nav-icon">
|
||||
<input type="file" name="file" accept="image/png,image/svg+xml" required class="tw-mb-2" style="max-width: 100%;">
|
||||
<br><button type="submit" class="ui primary mini button">{{svg "octicon-upload" 12}} Upload</button>
|
||||
{{if .HasNavIcon}}<a href="{{AppSubUrl}}/-/admin/branding/reset?type=nav-icon" class="ui mini button tw-ml-2">{{svg "octicon-sync" 12}} Reset</a>{{end}}
|
||||
</form>
|
||||
</td>
|
||||
<td class="tw-text-center" style="background: var(--color-secondary); border-radius: var(--border-radius);">
|
||||
<img src="{{AssetUrlPrefix}}/img/logo-small.png?v={{ctx.CspScriptNonce}}" style="max-height: 48px; max-width: 48px; object-fit: contain;" onerror="this.src='{{AssetUrlPrefix}}/img/logo.png'">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Login Logo -->
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Login Logo</strong> {{if .HasLogo}}<span class="ui mini green label">Custom</span>{{else}}<span class="ui mini grey label">Default</span>{{end}}
|
||||
<div class="tw-text-text-light tw-text-sm tw-mt-1">Login page and homepage. Wide format, max 220px display.</div>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" action="{{AppSubUrl}}/-/admin/branding/upload" enctype="multipart/form-data">
|
||||
{{.CsrfTokenHtml}}
|
||||
<input type="hidden" name="type" value="logo">
|
||||
<input type="file" name="file" accept="image/png,image/svg+xml" required class="tw-mb-2" style="max-width: 100%;">
|
||||
<br><button type="submit" class="ui primary mini button">{{svg "octicon-upload" 12}} Upload</button>
|
||||
{{if .HasLogo}}<a href="{{AppSubUrl}}/-/admin/branding/reset?type=logo" class="ui mini button tw-ml-2">{{svg "octicon-sync" 12}} Reset</a>{{end}}
|
||||
</form>
|
||||
</td>
|
||||
<td class="tw-text-center" style="background: var(--color-secondary); border-radius: var(--border-radius);">
|
||||
<img src="{{AssetUrlPrefix}}/img/logo.png?v={{ctx.CspScriptNonce}}" style="max-height: 48px; max-width: 140px; object-fit: contain;">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Favicon -->
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Favicon</strong> {{if .HasFavicon}}<span class="ui mini green label">Custom</span>{{else}}<span class="ui mini grey label">Default</span>{{end}}
|
||||
<div class="tw-text-text-light tw-text-sm tw-mt-1">Browser tab and PWA app icon. Square, 256x256px.</div>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" action="{{AppSubUrl}}/-/admin/branding/upload" enctype="multipart/form-data">
|
||||
{{.CsrfTokenHtml}}
|
||||
<input type="hidden" name="type" value="favicon">
|
||||
<input type="file" name="file" accept="image/png,image/svg+xml,image/x-icon" required class="tw-mb-2" style="max-width: 100%;">
|
||||
<br><button type="submit" class="ui primary mini button">{{svg "octicon-upload" 12}} Upload</button>
|
||||
{{if .HasFavicon}}<a href="{{AppSubUrl}}/-/admin/branding/reset?type=favicon" class="ui mini button tw-ml-2">{{svg "octicon-sync" 12}} Reset</a>{{end}}
|
||||
</form>
|
||||
</td>
|
||||
<td class="tw-text-center" style="background: var(--color-secondary); border-radius: var(--border-radius);">
|
||||
<img src="{{AssetUrlPrefix}}/img/favicon.png?v={{ctx.CspScriptNonce}}" style="max-height: 48px; max-width: 48px; object-fit: contain;">
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{template "admin/layout_footer" .}}
|
||||
|
||||
+29
-29
@@ -3,83 +3,83 @@
|
||||
<div class="header item">{{ctx.Locale.Tr "admin.settings"}}</div>
|
||||
|
||||
<details class="item toggleable-item" {{if or .PageIsAdminDashboard .PageIsAdminSelfCheck}}open{{end}}>
|
||||
<summary>{{ctx.Locale.Tr "admin.maintenance"}}</summary>
|
||||
<summary>{{svg "octicon-tools" 16}} {{ctx.Locale.Tr "admin.maintenance"}}</summary>
|
||||
<div class="menu">
|
||||
<a class="{{if .PageIsAdminDashboard}}active {{end}}item" href="{{AppSubUrl}}/-/admin">
|
||||
{{ctx.Locale.Tr "admin.dashboard"}}
|
||||
{{svg "octicon-dashboard" 16}} {{ctx.Locale.Tr "admin.dashboard"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsAdminSelfCheck}}active {{end}}item" href="{{AppSubUrl}}/-/admin/self_check">
|
||||
{{ctx.Locale.Tr "admin.self_check"}}
|
||||
{{svg "octicon-check-circle" 16}} {{ctx.Locale.Tr "admin.self_check"}}
|
||||
</a>
|
||||
</div>
|
||||
</details>
|
||||
<details class="item toggleable-item" {{if or .PageIsAdminUsers .PageIsAdminBadges .PageIsAdminEmails .PageIsAdminOrganizations .PageIsAdminAuthentications}}open{{end}}>
|
||||
<summary>{{ctx.Locale.Tr "admin.identity_access"}}</summary>
|
||||
<summary>{{svg "octicon-people" 16}} {{ctx.Locale.Tr "admin.identity_access"}}</summary>
|
||||
<div class="menu">
|
||||
<a class="{{if .PageIsAdminAuthentications}}active {{end}}item" href="{{AppSubUrl}}/-/admin/auths">
|
||||
{{ctx.Locale.Tr "admin.authentication"}}
|
||||
{{svg "octicon-shield-lock" 16}} {{ctx.Locale.Tr "admin.authentication"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsAdminOrganizations}}active {{end}}item" href="{{AppSubUrl}}/-/admin/orgs">
|
||||
{{ctx.Locale.Tr "admin.organizations"}}
|
||||
{{svg "octicon-organization" 16}} {{ctx.Locale.Tr "admin.organizations"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsAdminUsers}}active {{end}}item" href="{{AppSubUrl}}/-/admin/users">
|
||||
{{ctx.Locale.Tr "admin.users"}}
|
||||
{{svg "octicon-person" 16}} {{ctx.Locale.Tr "admin.users"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsAdminBadges}}active {{end}}item" href="{{AppSubUrl}}/-/admin/badges">
|
||||
{{ctx.Locale.Tr "admin.badges"}}
|
||||
{{svg "octicon-id-badge" 16}} {{ctx.Locale.Tr "admin.badges"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsAdminEmails}}active {{end}}item" href="{{AppSubUrl}}/-/admin/emails">
|
||||
{{ctx.Locale.Tr "admin.emails"}}
|
||||
{{svg "octicon-mail" 16}} {{ctx.Locale.Tr "admin.emails"}}
|
||||
</a>
|
||||
</div>
|
||||
</details>
|
||||
<details class="item toggleable-item" {{if or .PageIsAdminRepositories (and .EnablePackages .PageIsAdminPackages)}}open{{end}}>
|
||||
<summary>{{ctx.Locale.Tr "admin.assets"}}</summary>
|
||||
<summary>{{svg "octicon-database" 16}} {{ctx.Locale.Tr "admin.assets"}}</summary>
|
||||
<div class="menu">
|
||||
{{if .EnablePackages}}
|
||||
<a class="{{if .PageIsAdminPackages}}active {{end}}item" href="{{AppSubUrl}}/-/admin/packages">
|
||||
{{ctx.Locale.Tr "packages.title"}}
|
||||
{{svg "octicon-package" 16}} {{ctx.Locale.Tr "packages.title"}}
|
||||
</a>
|
||||
{{end}}
|
||||
<a class="{{if .PageIsAdminRepositories}}active {{end}}item" href="{{AppSubUrl}}/-/admin/repos">
|
||||
{{ctx.Locale.Tr "admin.repositories"}}
|
||||
{{svg "octicon-repo" 16}} {{ctx.Locale.Tr "admin.repositories"}}
|
||||
</a>
|
||||
</div>
|
||||
</details>
|
||||
<!-- Webhooks and OAuth can be both disabled here, so add this if statement to display different ui -->
|
||||
{{if and (not DisableWebhooks) .EnableOAuth2}}
|
||||
<details class="item toggleable-item" {{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks .PageIsAdminApplications}}open{{end}}>
|
||||
<summary>{{ctx.Locale.Tr "admin.integrations"}}</summary>
|
||||
<summary>{{svg "octicon-plug" 16}} {{ctx.Locale.Tr "admin.integrations"}}</summary>
|
||||
<div class="menu">
|
||||
<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/-/admin/applications">
|
||||
{{ctx.Locale.Tr "settings.applications"}}
|
||||
{{svg "octicon-key" 16}} {{ctx.Locale.Tr "settings.applications"}}
|
||||
</a>
|
||||
<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/-/admin/hooks">
|
||||
{{ctx.Locale.Tr "admin.hooks"}}
|
||||
{{svg "octicon-webhook" 16}} {{ctx.Locale.Tr "admin.hooks"}}
|
||||
</a>
|
||||
</div>
|
||||
</details>
|
||||
{{else}}
|
||||
{{if not DisableWebhooks}}
|
||||
<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/-/admin/hooks">
|
||||
{{ctx.Locale.Tr "admin.hooks"}}
|
||||
{{svg "octicon-webhook" 16}} {{ctx.Locale.Tr "admin.hooks"}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if .EnableOAuth2}}
|
||||
<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/-/admin/applications">
|
||||
{{ctx.Locale.Tr "settings.applications"}}
|
||||
{{svg "octicon-key" 16}} {{ctx.Locale.Tr "settings.applications"}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .EnableActions}}
|
||||
<details class="item toggleable-item" {{if or .PageIsSharedSettingsRunners .PageIsSharedSettingsVariables}}open{{end}}>
|
||||
<summary>{{ctx.Locale.Tr "actions.actions"}}</summary>
|
||||
<summary>{{svg "octicon-play" 16}} {{ctx.Locale.Tr "actions.actions"}}</summary>
|
||||
<div class="menu">
|
||||
<a class="{{if .PageIsSharedSettingsRunners}}active {{end}}item" href="{{AppSubUrl}}/-/admin/actions/runners">
|
||||
{{ctx.Locale.Tr "actions.runners"}}
|
||||
{{svg "octicon-server" 16}} {{ctx.Locale.Tr "actions.runners"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsSharedSettingsVariables}}active {{end}}item" href="{{AppSubUrl}}/-/admin/actions/variables">
|
||||
{{ctx.Locale.Tr "actions.variables"}}
|
||||
{{svg "octicon-list-unordered" 16}} {{ctx.Locale.Tr "actions.variables"}}
|
||||
</a>
|
||||
</div>
|
||||
</details>
|
||||
@@ -88,33 +88,33 @@
|
||||
{{svg "octicon-paintbrush" 16}} Branding
|
||||
</a>
|
||||
<details class="item toggleable-item" {{if or .PageIsAdminConfig}}open{{end}}>
|
||||
<summary>{{ctx.Locale.Tr "admin.config"}}</summary>
|
||||
<summary>{{svg "octicon-gear" 16}} {{ctx.Locale.Tr "admin.config"}}</summary>
|
||||
<div class="menu">
|
||||
<a class="{{if .PageIsAdminConfigSummary}}active {{end}}item" href="{{AppSubUrl}}/-/admin/config">
|
||||
{{ctx.Locale.Tr "admin.config_summary"}}
|
||||
{{svg "octicon-info" 16}} {{ctx.Locale.Tr "admin.config_summary"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsAdminConfigSettings}}active {{end}}item" href="{{AppSubUrl}}/-/admin/config/settings">
|
||||
{{ctx.Locale.Tr "admin.config_settings"}}
|
||||
{{svg "octicon-sliders" 16}} {{ctx.Locale.Tr "admin.config_settings"}}
|
||||
</a>
|
||||
</div>
|
||||
</details>
|
||||
<a class="{{if .PageIsAdminNotices}}active {{end}}item" href="{{AppSubUrl}}/-/admin/notices">
|
||||
{{ctx.Locale.Tr "admin.notices"}}
|
||||
{{svg "octicon-alert" 16}} {{ctx.Locale.Tr "admin.notices"}}
|
||||
</a>
|
||||
<details class="item toggleable-item" {{if or .PageIsAdminMonitorStats .PageIsAdminMonitorCron .PageIsAdminMonitorQueue .PageIsAdminMonitorTrace}}open{{end}}>
|
||||
<summary>{{ctx.Locale.Tr "admin.monitor"}}</summary>
|
||||
<summary>{{svg "octicon-pulse" 16}} {{ctx.Locale.Tr "admin.monitor"}}</summary>
|
||||
<div class="menu">
|
||||
<a class="{{if .PageIsAdminMonitorStats}}active {{end}}item" href="{{AppSubUrl}}/-/admin/monitor/stats">
|
||||
{{ctx.Locale.Tr "admin.monitor.stats"}}
|
||||
{{svg "octicon-graph" 16}} {{ctx.Locale.Tr "admin.monitor.stats"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsAdminMonitorCron}}active {{end}}item" href="{{AppSubUrl}}/-/admin/monitor/cron">
|
||||
{{ctx.Locale.Tr "admin.monitor.cron"}}
|
||||
{{svg "octicon-clock" 16}} {{ctx.Locale.Tr "admin.monitor.cron"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsAdminMonitorQueue}}active {{end}}item" href="{{AppSubUrl}}/-/admin/monitor/queue">
|
||||
{{ctx.Locale.Tr "admin.monitor.queues"}}
|
||||
{{svg "octicon-stack" 16}} {{ctx.Locale.Tr "admin.monitor.queues"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsAdminMonitorTrace}}active {{end}}item" href="{{AppSubUrl}}/-/admin/monitor/stacktrace">
|
||||
{{ctx.Locale.Tr "admin.monitor.trace"}}
|
||||
{{svg "octicon-cpu" 16}} {{ctx.Locale.Tr "admin.monitor.trace"}}
|
||||
</a>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
Reference in New Issue
Block a user