From 2cc4f7c0474611180ad30b6cda30956b678ed3ff Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 6 Jun 2026 19:52:55 -0500 Subject: [PATCH] feat: org settings for Issue Types + MCP SSE hosted + npm auto-publish - Org settings page for managing Issue Type definitions (CRUD) - MCP SSE endpoint deployed at git.mokoconsulting.tech/mcp/ - npm auto-publish workflow on MCP source changes to main --- .mokogitea/workflows/npm-publish.yml | 51 +++++++++++++ options/locale/locale_en-US.json | 12 +++ routers/web/org/issue_types.go | 98 +++++++++++++++++++++++++ routers/web/web.go | 6 ++ templates/org/settings/issue_types.tmpl | 81 ++++++++++++++++++++ templates/org/settings/navbar.tmpl | 3 + 6 files changed, 251 insertions(+) create mode 100644 .mokogitea/workflows/npm-publish.yml create mode 100644 routers/web/org/issue_types.go create mode 100644 templates/org/settings/issue_types.tmpl diff --git a/.mokogitea/workflows/npm-publish.yml b/.mokogitea/workflows/npm-publish.yml new file mode 100644 index 0000000000..3e61625131 --- /dev/null +++ b/.mokogitea/workflows/npm-publish.yml @@ -0,0 +1,51 @@ +name: Publish MCP to npm +on: + push: + branches: [main] + paths: + - '.mokogitea/mcp/**' + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + registry-url: 'https://registry.npmjs.org' + + - name: Install and build + working-directory: .mokogitea/mcp + run: | + npm ci + npx tsc + + - name: Check version change + id: version + working-directory: .mokogitea/mcp + run: | + LOCAL_VERSION=$(node -p "require('./package.json').version") + NPM_VERSION=$(npm view @mokoconsulting/mokogitea-mcp version 2>/dev/null || echo "0.0.0") + if [ "$LOCAL_VERSION" != "$NPM_VERSION" ]; then + echo "changed=true" >> $GITHUB_OUTPUT + echo "Version changed: $NPM_VERSION -> $LOCAL_VERSION" + else + echo "changed=false" >> $GITHUB_OUTPUT + echo "Version unchanged: $LOCAL_VERSION" + fi + + - name: Publish to npm + if: steps.version.outputs.changed == 'true' + working-directory: .mokogitea/mcp + run: npm publish --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Publish to Gitea registry + if: steps.version.outputs.changed == 'true' + working-directory: .mokogitea/mcp + run: | + npm publish --registry ${{ github.server_url }}/api/packages/${{ github.repository_owner }}/npm/ \ + --//$(echo "${{ github.server_url }}" | sed 's|https://||')/api/packages/${{ github.repository_owner }}/npm/:_authToken=${{ secrets.GITEA_TOKEN }} diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 5ede6e91cf..9e5aef5955 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -2992,6 +2992,18 @@ "org.settings.issue_priority_created": "Issue priority created.", "org.settings.issue_priority_updated": "Issue priority updated.", "org.settings.issue_priority_deleted": "Issue priority deleted.", + "org.settings.issue_types": "Issue Types", + "org.settings.issue_types_desc": "Define issue types for all repositories in this organization.", + "org.settings.issue_types_empty": "No custom issue types defined yet.", + "org.settings.issue_type_add": "Add Type", + "org.settings.issue_type_name": "Type Name", + "org.settings.issue_type_color": "Color", + "org.settings.issue_type_description": "Description", + "org.settings.issue_type_default": "Default", + "org.settings.issue_type_sort_order": "Sort Order", + "org.settings.issue_type_created": "Issue type created.", + "org.settings.issue_type_updated": "Issue type updated.", + "org.settings.issue_type_deleted": "Issue type deleted.", "org.settings.update_streams": "Update Server", "org.settings.licensing": "Update Server", "org.settings.licensing_desc": "Manage update feeds and optional license key gating across all repositories in this organization.", diff --git a/routers/web/org/issue_types.go b/routers/web/org/issue_types.go new file mode 100644 index 0000000000..c61fe2966e --- /dev/null +++ b/routers/web/org/issue_types.go @@ -0,0 +1,98 @@ +// Copyright 2026 Moko Consulting +// SPDX-License-Identifier: GPL-3.0-or-later + +package org + +import ( + "net/http" + "strconv" + + issues_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/issues" + "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/templates" + "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/context" +) + +const tplOrgIssueTypes templates.TplName = "org/settings/issue_types" + +func SettingsIssueTypes(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("org.settings.issue_types") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsSettingsIssueTypes"] = true + + defs, err := issues_model.GetAllIssueTypeDefsByOrg(ctx, ctx.Org.Organization.ID) + if err != nil { + ctx.ServerError("GetAllIssueTypeDefsByOrg", err) + return + } + ctx.Data["IssueTypes"] = defs + ctx.HTML(http.StatusOK, tplOrgIssueTypes) +} + +func SettingsIssueTypesCreatePost(ctx *context.Context) { + sortOrder, _ := strconv.Atoi(ctx.FormString("sort_order")) + def := &issues_model.IssueTypeDef{ + OrgID: ctx.Org.Organization.ID, + Name: ctx.FormString("name"), + Color: ctx.FormString("color"), + Description: ctx.FormString("description"), + SortOrder: sortOrder, + IsDefault: ctx.FormString("is_default") == "on", + IsActive: true, + } + if def.Name == "" { + ctx.Flash.Error("Type name is required") + ctx.Redirect(ctx.Org.OrgLink + "/settings/issue-types") + return + } + if err := issues_model.CreateIssueTypeDef(ctx, def); err != nil { + ctx.ServerError("CreateIssueTypeDef", err) + return + } + ctx.Flash.Success(ctx.Tr("org.settings.issue_type_created")) + ctx.Redirect(ctx.Org.OrgLink + "/settings/issue-types") +} + +func SettingsIssueTypesEditPost(ctx *context.Context) { + id := ctx.PathParamInt64("id") + def, err := issues_model.GetIssueTypeDefByID(ctx, id) + if err != nil { + ctx.ServerError("GetIssueTypeDefByID", err) + return + } + if def.OrgID != ctx.Org.Organization.ID { + ctx.NotFound(nil) + return + } + def.Name = ctx.FormString("name") + def.Color = ctx.FormString("color") + def.Description = ctx.FormString("description") + def.IsDefault = ctx.FormString("is_default") == "on" + def.IsActive = ctx.FormString("is_active") == "on" + sortOrder, _ := strconv.Atoi(ctx.FormString("sort_order")) + def.SortOrder = sortOrder + if err := issues_model.UpdateIssueTypeDef(ctx, def); err != nil { + ctx.ServerError("UpdateIssueTypeDef", err) + return + } + ctx.Flash.Success(ctx.Tr("org.settings.issue_type_updated")) + ctx.Redirect(ctx.Org.OrgLink + "/settings/issue-types") +} + +func SettingsIssueTypesDeletePost(ctx *context.Context) { + id := ctx.PathParamInt64("id") + def, err := issues_model.GetIssueTypeDefByID(ctx, id) + if err != nil { + ctx.ServerError("GetIssueTypeDefByID", err) + return + } + if def.OrgID != ctx.Org.Organization.ID { + ctx.NotFound(nil) + return + } + if err := issues_model.DeleteIssueTypeDef(ctx, id); err != nil { + ctx.ServerError("DeleteIssueTypeDef", err) + return + } + ctx.Flash.Success(ctx.Tr("org.settings.issue_type_deleted")) + ctx.Redirect(ctx.Org.OrgLink + "/settings/issue-types") +} diff --git a/routers/web/web.go b/routers/web/web.go index 27ec398fc3..491bc86372 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1079,6 +1079,12 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Post("/{id}/edit", org.SettingsIssuePrioritiesEditPost) m.Post("/{id}/delete", org.SettingsIssuePrioritiesDeletePost) }) + m.Group("/issue-types", func() { + m.Get("", org.SettingsIssueTypes) + m.Post("", org.SettingsIssueTypesCreatePost) + m.Post("/{id}/edit", org.SettingsIssueTypesEditPost) + m.Post("/{id}/delete", org.SettingsIssueTypesDeletePost) + }) }, ctxDataSet("EnableOAuth2", setting.OAuth2.Enabled, "EnablePackages", setting.Packages.Enabled, "PageIsOrgSettings", true)) }, context.OrgAssignment(context.OrgAssignmentOptions{RequireOwner: true})) }, reqSignIn) diff --git a/templates/org/settings/issue_types.tmpl b/templates/org/settings/issue_types.tmpl new file mode 100644 index 0000000000..d3f1c581f4 --- /dev/null +++ b/templates/org/settings/issue_types.tmpl @@ -0,0 +1,81 @@ +{{template "org/settings/layout_head" (dict "ctxData" . "pageClass" "organization settings issue-types")}} +

+ {{ctx.Locale.Tr "org.settings.issue_types"}} +

+
+

{{ctx.Locale.Tr "org.settings.issue_types_desc"}}

+ + {{if .IssueTypes}} + + + + + + + + + + + + {{range .IssueTypes}} + + + + + + + + {{end}} + +
{{ctx.Locale.Tr "org.settings.issue_type_color"}}{{ctx.Locale.Tr "org.settings.issue_type_name"}}{{ctx.Locale.Tr "org.settings.issue_type_default"}}{{ctx.Locale.Tr "org.settings.issue_type_sort_order"}}
+ {{if .Color}}{{else}}-{{end}} + + {{.Name}} + {{if not .IsActive}}Inactive{{end}} + {{if .Description}}
{{.Description}}{{end}} +
+ {{if .IsDefault}}{{ctx.Locale.Tr "org.settings.issue_type_default"}}{{else}}-{{end}} + {{.SortOrder}} +
+ {{$.CsrfTokenHtml}} + +
+
+ {{else}} +

{{ctx.Locale.Tr "org.settings.issue_types_empty"}}

+ {{end}} + +
+
{{ctx.Locale.Tr "org.settings.issue_type_add"}}
+
+ {{.CsrfTokenHtml}} +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+ + +
+
+
+ +
+
+{{template "org/settings/layout_footer" .}} diff --git a/templates/org/settings/navbar.tmpl b/templates/org/settings/navbar.tmpl index 8a3a42283f..f4875e7f38 100644 --- a/templates/org/settings/navbar.tmpl +++ b/templates/org/settings/navbar.tmpl @@ -37,6 +37,9 @@ {{svg "octicon-flame"}} {{ctx.Locale.Tr "org.settings.issue_priorities"}} + + {{svg "octicon-tag"}} {{ctx.Locale.Tr "org.settings.issue_types"}} + {{if .EnableActions}}
{{svg "octicon-play"}} {{ctx.Locale.Tr "actions.actions"}} -- 2.52.0