Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,6 @@ export default defineConfig([
'no-restricted-imports': [2, {paths: [
{name: 'jquery', message: 'Use the global $ instead', allowTypeImports: true},
{name: 'htmx.org', message: 'Use the global htmx instead', allowTypeImports: true},
{name: 'idiomorph/htmx', message: 'Loaded in globals.ts', allowTypeImports: true},
]}],
'no-restricted-syntax': [2, 'WithStatement', 'ForInStatement', 'LabeledStatement', 'SequenceExpression'],
'no-return-assign': [0],
Expand Down
5 changes: 5 additions & 0 deletions modules/web/middleware/cookie.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ func DeleteRedirectToCookie(resp http.ResponseWriter) {
}

func RedirectLinkUserLogin(req *http.Request) string {
if req.Header.Get("X-Gitea-Fetch-Action") != "" {
// when building the redirect link for a fetch request, the current link might be a partial page,
// so we only redirect to the login page without redirect_to parameter
return setting.AppSubURL + "/user/login"
}
return setting.AppSubURL + "/user/login?redirect_to=" + url.QueryEscape(setting.AppSubURL+req.URL.RequestURI())
}

Expand Down
4 changes: 2 additions & 2 deletions routers/common/redirect.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ func FetchRedirectDelegate(resp http.ResponseWriter, req *http.Request) {
// 2. when use "window.reload()", the hash is not respected, the newly loaded page won't scroll to the hash target.
// The typical page is "issue comment" page. The backend responds "/owner/repo/issues/1#comment-2",
// then frontend needs this delegate to redirect to the new location with hash correctly.
redirect := req.PostFormValue("redirect")
if !httplib.IsCurrentGiteaSiteURL(req.Context(), redirect) {
redirect := req.FormValue("redirect")
if req.Method != http.MethodPost || !httplib.IsCurrentGiteaSiteURL(req.Context(), redirect) {
resp.WriteHeader(http.StatusBadRequest)
return
}
Expand Down
7 changes: 3 additions & 4 deletions routers/web/devtest/devtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func List(ctx *context.Context) {

func FetchActionTest(ctx *context.Context) {
_ = ctx.Req.ParseForm()
ctx.Flash.Info("fetch-action: " + ctx.Req.Method + " " + ctx.Req.RequestURI + "\n" +
ctx.Flash.Info("fetch action: " + ctx.Req.Method + " " + ctx.Req.RequestURI + "\n" +
"Form: " + ctx.Req.Form.Encode() + "\n" +
"PostForm: " + ctx.Req.PostForm.Encode(),
)
Expand Down Expand Up @@ -241,9 +241,8 @@ func prepareMockDataUnicodeEscape(ctx *context.Context) {

func TmplCommon(ctx *context.Context) {
prepareMockData(ctx)
if ctx.Req.Method == http.MethodPost {
_ = ctx.Req.ParseForm()
ctx.Flash.Info("form: "+ctx.Req.Method+" "+ctx.Req.RequestURI+"\n"+
if ctx.Req.Method == http.MethodPost && ctx.FormBool("mock_response_delay") {
ctx.Flash.Info("form submit: "+ctx.Req.Method+" "+ctx.Req.RequestURI+"\n"+
"Form: "+ctx.Req.Form.Encode()+"\n"+
"PostForm: "+ctx.Req.PostForm.Encode(),
true,
Expand Down
1 change: 0 additions & 1 deletion routers/web/repo/star.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,5 @@ func ActionStar(ctx *context.Context) {
ctx.ServerError("GetRepositoryByName", err)
return
}
ctx.RespHeader().Add("hx-trigger", "refreshUserCards") // see the `hx-trigger="refreshUserCards ..."` comments in tmpl
ctx.HTML(http.StatusOK, tplStarUnstar)
}
6 changes: 4 additions & 2 deletions routers/web/repo/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,15 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
return nil
}

{
{ // this block is for testing purpose only
if timeout != 0 && !setting.IsProd && !setting.IsInTesting {
log.Debug("first call to get directory file commit info")
clearFilesCommitInfo := func() {
log.Warn("clear directory file commit info to force async loading on frontend")
for i := range files {
files[i].Commit = nil
if i%2 == 0 { // for testing purpose, only clear half of the files' commit info
files[i].Commit = nil
}
}
Comment thread
wxiaoguang marked this conversation as resolved.
}
_ = clearFilesCommitInfo
Expand Down
1 change: 0 additions & 1 deletion routers/web/repo/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,5 @@ func ActionWatch(ctx *context.Context) {
ctx.ServerError("GetRepositoryByName", err)
return
}
ctx.RespHeader().Add("hx-trigger", "refreshUserCards") // see the `hx-trigger="refreshUserCards ..."` comments in tmpl
ctx.HTML(http.StatusOK, tplWatchUnwatch)
}
2 changes: 1 addition & 1 deletion routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -1710,7 +1710,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {

m.Get("/forks", repo.Forks)
m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, repo.RawDiff)
m.Post("/lastcommit/*", context.RepoRefByType(git.RefTypeCommit), repo.LastCommit)
m.Get("/lastcommit/*", context.RepoRefByType(git.RefTypeCommit), repo.LastCommit)
}, optSignIn, context.RepoAssignment, reqUnitCodeReader)
// end "/{username}/{reponame}": repo code

Expand Down
10 changes: 4 additions & 6 deletions services/context/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,10 @@ func (b *Base) Redirect(location string, status ...int) {
// So in this case, we should remove the session cookie from the response header
removeSessionCookieHeader(b.Resp)
}
// in case the request is made by htmx, have it redirect the browser instead of trying to follow the redirect inside htmx
if b.Req.Header.Get("HX-Request") == "true" {
b.Resp.Header().Set("HX-Redirect", location)
// we have to return a non-redirect status code so XMLHTTPRequest will not immediately follow the redirect
// so as to give htmx redirect logic a chance to run
b.Status(http.StatusNoContent)
// In case the request is made by "fetch-action" module, make JS redirect to the new location
// Otherwise, the JS fetch will follow the redirection and read a "login" page, embed it to the current page, which is not expected.
if b.Req.Header.Get("X-Gitea-Fetch-Action") != "" {
b.JSON(http.StatusOK, map[string]any{"redirect": location})
return
}
http.Redirect(b.Resp, b.Req, location, code)
Expand Down
7 changes: 4 additions & 3 deletions services/context/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ func TestRedirect(t *testing.T) {

req, _ = http.NewRequest(http.MethodGet, "/", nil)
resp := httptest.NewRecorder()
req.Header.Add("HX-Request", "true")
req.Header.Add("X-Gitea-Fetch-Action", "1")
b := NewBaseContextForTest(resp, req)
b.Redirect("/other")
assert.Equal(t, "/other", resp.Header().Get("HX-Redirect"))
assert.Equal(t, http.StatusNoContent, resp.Code)
assert.Contains(t, resp.Header().Get("Content-Type"), "application/json")
assert.JSONEq(t, `{"redirect":"/other"}`, resp.Body.String())
assert.Equal(t, http.StatusOK, resp.Code)
}
5 changes: 1 addition & 4 deletions templates/admin/dashboard.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@
</h4>
{{/* TODO: make these stats work in multi-server deployments, likely needs per-server stats in DB */}}
<div class="ui attached table segment">
<div class="no-loading-indicator tw-hidden"></div>
<div hx-get="{{$.Link}}/system_status" hx-swap="morph:innerHTML" hx-trigger="every 5s" hx-indicator=".no-loading-indicator">
{{template "admin/system_status" .}}
</div>
{{template "admin/system_status" .}}
</div>
</div>
{{template "admin/layout_footer" .}}
2 changes: 1 addition & 1 deletion templates/admin/notice.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
</div>
</div>
</div>
<button class="ui small button" id="delete-selection" data-link="{{.Link}}/delete" data-redirect="?page={{.Page.Paginater.Current}}">
<button class="ui small button" id="delete-selection" data-link="{{.Link}}/delete">
<span class="text">{{ctx.Locale.Tr "admin.notices.delete_selected"}}</span>
</button>
</th>
Expand Down
2 changes: 1 addition & 1 deletion templates/admin/system_status.tmpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<dl class="admin-dl-horizontal">
<dl class="admin-dl-horizontal" data-fetch-url="{{AppSubUrl}}/-/admin/system_status" data-fetch-sync="$morph" data-fetch-trigger="every 5s">
<dt>{{ctx.Locale.Tr "admin.dashboard.server_uptime"}}</dt>
<dd><relative-time format="duration" datetime="{{.SysStatus.StartTime}}">{{.SysStatus.StartTime}}</relative-time></dd>
<dt>{{ctx.Locale.Tr "admin.dashboard.current_goroutine"}}</dt>
Expand Down
2 changes: 1 addition & 1 deletion templates/base/head.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
{{template "base/head_script" .}}
{{template "custom/header" .}}
</head>
<body hx-swap="outerHTML" hx-ext="morph" hx-push-url="false">
<body hx-swap="outerHTML" hx-push-url="false">
{{template "custom/body_outer_pre" .}}

<div class="full height">
Expand Down
5 changes: 2 additions & 3 deletions templates/devtest/fetch-action.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div>
<h1>link-action</h1>
<div>
Use "window.fetch" to send a request to backend, the request is defined in an "A" or "BUTTON" element.
The request is defined in an "A" or "BUTTON" element.
It might be renamed to "link-fetch-action" to match the "form-fetch-action".
</div>
<div>
Expand All @@ -15,7 +15,6 @@
</div>
<div>
<h1>form-fetch-action</h1>
<div>Use "window.fetch" to send a form request to backend</div>
<div class="flex-relaxed-list fetch-action-demo-forms">
<form method="get" action="./fetch-action-test?k=1" class="form-fetch-action">
<button name="btn">submit get</button>
Expand All @@ -25,7 +24,7 @@
<div><label><input name="check" type="checkbox"> check</label></div>
<div><button name="btn">submit post</button></div>
</form>
<form method="post" action="./no-such-uri" class="form-fetch-action">
<form method="post" action="/-/no-such-uri" class="form-fetch-action">
<div class="tw-py-8">bad action url</div>
<div><button name="btn">submit test</button></div>
</form>
Expand Down
22 changes: 5 additions & 17 deletions templates/devtest/fomantic-modal.tmpl
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
{{template "devtest/devtest-header"}}
<div class="page-content devtest ui container">
{{template "base/alert" .}}
<div class="modal-buttons flex-text-block tw-flex-wrap"></div>
<script>
document.addEventListener('gitea:index-ready', () => {
for (const el of $('.ui.modal:not([data-skip-button])')) {
const $btn = $('<button class="ui button">').text(`${el.id}`).on('click', () => {
$(el).modal({onApprove() {alert('confirmed')}}).modal('show');
});
$('.modal-buttons').append($btn);
}
});
</script>

<div id="test-modal-form-1" class="ui mini modal">
<div class="header">Form dialog (layout 1)</div>
<form class="content" method="post">
<form class="content" method="post" action="?mock_response_delay=1">
<div class="ui input tw-w-full"><input name="user_input"></div>
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
</form>
</div>

<div id="test-modal-form-2" class="ui mini modal">
<div class="header">Form dialog (layout 2)</div>
<form method="post">
<form method="post" action="?mock_response_delay=1">
<div class="content">
<div class="ui input tw-w-full"><input name="user_input"></div>
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
Expand All @@ -33,7 +21,7 @@

<div id="test-modal-form-3" class="ui mini modal">
<div class="header">Form dialog (layout 3)</div>
<form method="post">
<form method="post" action="?mock_response_delay=1">
<div class="content">
<div class="ui input tw-w-full"><input name="user_input"></div>
</div>
Expand All @@ -46,15 +34,15 @@
<div class="content">
<div class="ui input tw-w-full"><input name="user_input"></div>
</div>
<form method="post">
<form method="post" action="?mock_response_delay=1">
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
</form>
</div>

<div id="test-modal-form-5" class="ui mini modal">
<div class="header">Form dialog (layout 5)</div>
<div class="content">
<form method="post">
<form method="post" action="?mock_response_delay=1">
<div class="ui input tw-w-full"><input name="user_input"></div>
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
</form>
Expand Down
11 changes: 0 additions & 11 deletions templates/devtest/gitea-ui.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,6 @@
</div>
</li>
</ul>
<script>
document.addEventListener('gitea:index-ready', () => {
const $buttons = $('#devtest-button-samples').find('button.ui');

const $buttonStyles = $('input[name*="button-style"]');
$buttonStyles.on('click', () => $buttonStyles.map((_, el) => $buttons.toggleClass(el.value, el.checked)));

const $buttonStates = $('input[name*="button-state"]');
$buttonStates.on('click', () => $buttonStates.map((_, el) => $buttons.prop(el.value, el.checked)));
});
</script>
</div>
</div>

Expand Down
2 changes: 1 addition & 1 deletion templates/projects/view.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
>
{{svg "octicon-star"}} {{ctx.Locale.Tr "repo.projects.column.set_default"}}
</a>
<a class="item button link-action" data-url="{{$.Link}}/{{.ID}}" data-link-action-method="DELETE"
<a class="item button link-action" data-url="{{$.Link}}/{{.ID}}" data-fetch-method="DELETE"
data-modal-confirm-header="{{ctx.Locale.Tr "repo.projects.column.delete"}}"
data-modal-confirm-content="{{ctx.Locale.Tr "repo.projects.column.deletion_desc"}}"
>
Expand Down
13 changes: 6 additions & 7 deletions templates/repo/actions/workflow_dispatch.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
</div>
<div id="runWorkflowDispatchModal" class="ui tiny modal">
<div class="content">
<form id="runWorkflowDispatchForm" class="ui form" action="{{$.Link}}/run?workflow={{$.CurWorkflow}}&actor={{$.CurActor}}&status={{.Status}}" method="post">
<form id="runWorkflowDispatchForm" class="ui form ignore-dirty" action="{{$.Link}}/run?workflow={{$.CurWorkflow}}&actor={{$.CurActor}}&status={{.Status}}" method="post">
<div class="ui inline field required tw-flex tw-items-center">
<span class="ui inline required field">
<label>{{ctx.Locale.Tr "actions.workflow.from_ref"}}:</label>
</span>
<div class="ui inline field dropdown button select-branch branch-selector-dropdown ellipsis-text-items">
<input type="hidden" name="ref" hx-sync="this:replace" hx-target="#runWorkflowDispatchModalInputs" hx-swap="innerHTML" hx-get="{{$.Link}}/workflow-dispatch-inputs?workflow={{$.CurWorkflow}}" hx-trigger="change" value="refs/heads/{{index .Branches 0}}">
<input type="hidden" name="ref" value="refs/heads/{{index .Branches 0}}"
data-fetch-trigger="change" data-fetch-sync="$body #runWorkflowDispatchModalInputs"
data-fetch-url="{{$.Link}}/workflow-dispatch-inputs?workflow={{$.CurWorkflow}}"
>
{{svg "octicon-git-branch" 14}}
<div class="default text">{{index .Branches 0}}</div>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
Expand Down Expand Up @@ -45,12 +48,8 @@
</div>
</div>
</div>

<div class="divider"></div>

<div id="runWorkflowDispatchModalInputs">
{{template "repo/actions/workflow_dispatch_inputs" .}}
</div>
{{template "repo/actions/workflow_dispatch_inputs" .}}
</form>
</div>
</div>
2 changes: 2 additions & 0 deletions templates/repo/actions/workflow_dispatch_inputs.tmpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<div id="runWorkflowDispatchModalInputs">
{{if not .WorkflowDispatchConfig}}
<div class="ui error message tw-block">{{/* using "ui message" in "ui form" needs to force to display */}}
{{if not .CurWorkflowExists}}
Expand Down Expand Up @@ -44,3 +45,4 @@
</div>
{{end}}
{{end}}
</div>
2 changes: 1 addition & 1 deletion templates/repo/commit_load_branches_and_tags.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</div>
{{end}}
<button class="ui button ellipsis-button load-branches-and-tags tw-mt-2" aria-expanded="false"
data-fetch-url="{{.RepoLink}}/commit/{{.CommitID}}/load-branches-and-tags"
data-url="{{.RepoLink}}/commit/{{.CommitID}}/load-branches-and-tags"
data-tooltip-content="{{ctx.Locale.Tr "repo.commit.load_referencing_branches_and_tags"}}"
>...</button>
<div class="branch-and-tag-detail tw-hidden">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{{if and $.UpdateAllowed $.UpdateByRebaseAllowed}}
<div class="tw-inline-block">
<div id="update-pr-branch-with-base" class="ui buttons">
<button class="ui button" data-do="{{$.Issue.Link}}/update" data-redirect="{{$.Issue.Link}}">
<button class="ui button" data-do="{{$.Issue.Link}}/update">
<span class="button-text">
{{ctx.Locale.Tr "repo.pulls.update_branch"}}
</span>
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/settings/webhook/history.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<div class="ui right">
<!-- the button is wrapped with a span because the tooltip doesn't show on hover if we put data-tooltip-content directly on the button -->
<span data-tooltip-content="{{if or $isNew .Webhook.IsActive}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc"}}{{else}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc_disabled"}}{{end}}">
<button class="ui tiny button{{if not (or $isNew .Webhook.IsActive)}} disabled{{end}}" id="test-delivery" data-link="{{.Link}}/test" data-redirect="{{.Link}}">
<button class="ui tiny button{{if not (or $isNew .Webhook.IsActive)}} disabled{{end}}" id="test-delivery" data-link="{{.Link}}/test">
<span class="text">{{ctx.Locale.Tr "repo.settings.webhook.test_delivery"}}</span>
</button>
</span>
Expand Down
32 changes: 19 additions & 13 deletions templates/repo/star_unstar.tmpl
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
<form class="flex-text-inline" hx-boost="true" hx-target="this" method="post" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}unstar{{else}}star{{end}}">
<div class="ui labeled button" {{if not $.IsSigned}}data-tooltip-content="{{ctx.Locale.Tr "repo.star_guest_user"}}"{{end}}>
{{$buttonText := ctx.Locale.Tr "repo.star"}}
{{if $.IsStaringRepo}}{{$buttonText = ctx.Locale.Tr "repo.unstar"}}{{end}}
<button type="submit" class="ui compact small basic button"{{if not $.IsSigned}} disabled{{end}} aria-label="{{$buttonText}}">
{{svg (Iif $.IsStaringRepo "octicon-star-fill" "octicon-star")}}
<span class="not-mobile" aria-hidden="true">{{$buttonText}}</span>
</button>
<a hx-boost="false" class="ui basic label" href="{{$.RepoLink}}/stars">
{{CountFmt .Repository.NumStars}}
</a>
</div>
</form>
<div class="ui labeled button" {{if not $.IsSigned}}data-tooltip-content="{{ctx.Locale.Tr "repo.star_guest_user"}}"{{end}}>
{{$buttonText := ctx.Locale.Tr "repo.star"}}
{{if $.IsStaringRepo}}{{$buttonText = ctx.Locale.Tr "repo.unstar"}}{{end}}
<button type="button" class="ui compact small basic button" aria-label="{{$buttonText}}"
{{if $.IsSigned}}
data-fetch-method="post"
data-fetch-url="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}unstar{{else}}star{{end}}"
data-fetch-sync="$closest(.ui.labeled.button)"
{{else}}
disabled
{{end}}
>
{{svg (Iif $.IsStaringRepo "octicon-star-fill" "octicon-star")}}
<span class="not-mobile" aria-hidden="true">{{$buttonText}}</span>
</button>
Comment thread
wxiaoguang marked this conversation as resolved.
<a class="ui basic label" href="{{$.RepoLink}}/stars">
{{CountFmt .Repository.NumStars}}
</a>
</div>
13 changes: 2 additions & 11 deletions templates/repo/user_cards.tmpl
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
<!-- Refresh the content if a htmx response contains "HX-Trigger" header.
This usually happens when a user stays on the watchers/stargazers page
when they watched/unwatched/starred/unstarred and the list should be refreshed.
To test go to the watchers page and click the watch button. The user cards should reload.
At the moment, no JS initialization would re-trigger (fortunately there is no JS for this page).
-->
<div class="no-loading-indicator tw-hidden"></div>
<div class="user-cards"
hx-trigger="refreshUserCards from:body" hx-indicator=".no-loading-indicator"
hx-get="" hx-swap="outerHTML" hx-select=".user-cards"
>
{{/* need to reload after "watch/unwatch" or "star/unstar" fetch actions */}}
<div class="user-cards" id="user-cards-container" data-fetch-trigger="fetch-reload">
{{if .CardsTitle}}
<h2 class="ui dividing header">
{{.CardsTitle}}
Expand Down
Loading