diff --git a/routers/web/repo/issue_watch.go b/routers/web/repo/issue_watch.go index 1cb5cc7162d89..fc04c4e40b3cd 100644 --- a/routers/web/repo/issue_watch.go +++ b/routers/web/repo/issue_watch.go @@ -41,7 +41,7 @@ func IssueWatch(ctx *context.Context) { return } - watch, err := strconv.ParseBool(ctx.Req.PostForm.Get("watch")) + watch, err := strconv.ParseBool(ctx.FormString("watch")) if err != nil { ctx.ServerError("watch is not bool", err) return @@ -52,5 +52,5 @@ func IssueWatch(ctx *context.Context) { return } - ctx.Redirect(issue.Link()) + ctx.JSONOK() } diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 4334e4bcbdc21..f46cc0d630e58 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -267,23 +267,13 @@ {{if and $.IssueWatch (not .Repository.IsArchived)}}
-
- {{ctx.Locale.Tr "notification.notifications"}} -
-
- - {{$.CsrfTokenHtml}} - -
-
+
{{end}} {{if .Repository.IsTimetrackerEnabled $.Context}} diff --git a/web_src/js/components/issue/Subscribe.vue b/web_src/js/components/issue/Subscribe.vue new file mode 100644 index 0000000000000..75b2a05b6585f --- /dev/null +++ b/web_src/js/components/issue/Subscribe.vue @@ -0,0 +1,70 @@ + + diff --git a/web_src/js/index.js b/web_src/js/index.js index 4713618506b0c..227950038245d 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -85,6 +85,7 @@ import {initRepoIssueList} from './features/repo-issue-list.js'; import {initCommonIssueListQuickGoto} from './features/common-issue-list.js'; import {initRepoDiffCommitBranchesAndTags} from './features/repo-diff-commit.js'; import {initDirAuto} from './modules/dirauto.js'; +import {initIssueSubsribe} from './components/issue/Subscribe.vue'; // Init Gitea's Fomantic settings initGiteaFomantic(); @@ -184,4 +185,6 @@ onDomReady(() => { initRepoDiffView(); initPdfViewer(); initScopedAccessTokenCategories(); + + initIssueSubsribe(); }); diff --git a/web_src/js/init.js b/web_src/js/init.js new file mode 100644 index 0000000000000..c70d9ea602104 --- /dev/null +++ b/web_src/js/init.js @@ -0,0 +1,37 @@ +import {createApp} from 'vue'; + +// convertName convert the html tag a-b to aB +export function convertName(o) { + return o.replace(/-(\w)/g, (_, c) => { + return c ? c.toUpperCase() : ''; + }); +} + +// initComponent will mount the component with tag id named id and vue sfc +// it will also assign all attributes of the tag with the prefix data-locale- and data- +// to the component as props +export function initComponent(id, sfc) { + const el = document.getElementById(id); + if (!el) return; + + const data = {}; + + for (const attr of el.getAttributeNames()) { + if (attr.startsWith('data-locale-')) { + data.locale = data.locale || {}; + data.locale[convertName(attr.slice(12))] = el.getAttribute(attr); + } else if (attr.startsWith('data-')) { + data[convertName(attr.slice(5))] = el.getAttribute(attr); + } + } + + if (!sfc.props.locale) { + sfc.props.locale = { + type: Object, + default: () => {}, + }; + } + + const view = createApp(sfc, data); + view.mount(el); +} diff --git a/web_src/js/init.test.js b/web_src/js/init.test.js new file mode 100644 index 0000000000000..356b63bb694e5 --- /dev/null +++ b/web_src/js/init.test.js @@ -0,0 +1,7 @@ +import {convertName} from './init.js'; + +test('init', () => { + expect(convertName('abc')).toEqual('abc'); + expect(convertName('abc-repo')).toEqual('abcRepo'); + expect(convertName('abc-repo-issue')).toEqual('abcRepoIssue'); +}); diff --git a/web_src/js/svg.js b/web_src/js/svg.js index c2a96fba3f040..048b8362d885e 100644 --- a/web_src/js/svg.js +++ b/web_src/js/svg.js @@ -69,6 +69,8 @@ import octiconTag from '../../public/assets/img/svg/octicon-tag.svg'; import octiconTriangleDown from '../../public/assets/img/svg/octicon-triangle-down.svg'; import octiconX from '../../public/assets/img/svg/octicon-x.svg'; import octiconXCircleFill from '../../public/assets/img/svg/octicon-x-circle-fill.svg'; +import octiconMute from '../../public/assets/img/svg/octicon-mute.svg'; +import octiconUnmute from '../../public/assets/img/svg/octicon-unmute.svg'; const svgs = { 'gitea-double-chevron-left': giteaDoubleChevronLeft, @@ -140,6 +142,8 @@ const svgs = { 'octicon-triangle-down': octiconTriangleDown, 'octicon-x': octiconX, 'octicon-x-circle-fill': octiconXCircleFill, + 'octicon-mute': octiconMute, + 'octicon-unmute': octiconUnmute, }; // TODO: use a more general approach to access SVG icons.