Compare commits

...

5 Commits

Author SHA1 Message Date
wxiaoguang d4af698440
Merge 24f0b31474 into 982b20d259 2024-05-06 00:39:16 +08:00
wxiaoguang 982b20d259
Do not show monaco JS errors (#30862)
Fix #30861
2024-05-05 16:34:13 +00:00
wxiaoguang 5c236bd4c0
Fix issue/PR title edit (#30858)
1. "enter" doesn't work (I think it is the last enter support for #14843)
2. if a branch name contains something like `&`, then the branch selector doesn't update
2024-05-05 13:09:41 +00:00
yp05327 ecd1d96f49
Add result check in TestAPIEditUser (#29674)
Fix #29514
There are too many usage of `NewRequestWithValues`, so there's no need
to check all of them.
Just one is enough I think.
2024-05-05 02:10:20 +00:00
wxiaoguang 24f0b31474 fix 2024-05-03 18:37:57 +08:00
20 changed files with 412 additions and 357 deletions

View File

@ -0,0 +1,109 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/devtest.css?v={{AssetVersion}}">
<div class="page-content devtest ui container">
<div>
<h2>Dropdown</h2>
<div>
<div class="ui dropdown tw-border tw-border-red tw-border-dashed" data-tooltip-content="border for demo purpose only">
<span class="text">search-input &amp; flex-item in menu</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu flex-items-menu">
<div class="ui icon search input"><i class="icon">{{svg "octicon-search"}}</i><input type="text" value="search input in menu"></div>
<div class="item"><input type="radio">item</div>
<div class="item"><input type="radio">item</div>
</div>
</div>
<div class="ui search selection dropdown">
<span class="text">search ...</span>
<input name="value" class="search">
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{svg "octicon-x" 14 "remove icon"}}
<div class="menu">
<div class="item">item</div>
</div>
</div>
<div class="ui multiple selection dropdown">
<input class="hidden" value="1">
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{svg "octicon-x" 14 "remove icon"}}
<div class="default text">empty multiple dropdown</div>
<div class="menu">
<div class="item">item</div>
</div>
</div>
<div class="ui multiple clearable search selection dropdown">
<input type="hidden" value="1">
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{svg "octicon-x" 14 "remove icon"}}
<div class="default text">clearable search dropdown</div>
<div class="menu">
<div class="item" data-value="1">item</div>
</div>
</div>
<div class="ui buttons">
<button class="ui button">Button with Dropdown</button>
<div class="ui dropdown button icon">
{{svg "octicon-triangle-down"}}
<div class="menu">
<div class="item">item</div>
</div>
</div>
</div>
</div>
<h2>Selection</h2>
<div>
{{/* the "selection" class is optional, it will be added by JS automatically */}}
<select class="ui dropdown selection ellipsis-items-nowrap">
<option>a</option>
<option>abcdefuvwxyz</option>
<option>loooooooooooooooooooooooooooooooooooooooooooooooooooooooooong</option>
</select>
<select class="ui dropdown ellipsis-items-nowrap tw-max-w-[8em]">
<option>loooooooooooooooooooooooooooooooooooooooooooooooooooooooooong</option>
<option>abcdefuvwxyz</option>
<option>a</option>
</select>
</div>
<h2>Dropdown Button (demo only without menu)</h2>
<div>
<div class="ui dropdown mini button">
<span class="text">mini dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui dropdown tiny button">
<span class="text">tiny dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui button dropdown">
<span class="text">button dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
</div>
<div>
<div class="ui dropdown mini compact button">
<span class="text">mini compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui dropdown tiny compact button">
<span class="text">tiny compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui button compact dropdown">
<span class="text">button compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
</div>
<div>
<hr>
<div class="ui tiny button">Other button align with ...</div>
<div class="ui dropdown tiny button">
<span class="text">... Dropdown Button</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
</div>
</div>
</div>
{{template "base/footer" .}}

View File

@ -180,94 +180,6 @@
<input type="text" placeholder="place holder">
</div>
</div>
<h2>Dropdown with SVG</h2>
<div>
<div class="ui dropdown tw-border tw-border-red tw-border-dashed" data-tooltip-content="border for demo purpose only">
<span class="text">search-input &amp; flex-item in menu</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu flex-items-menu">
<div class="ui icon search input"><i class="icon">{{svg "octicon-search"}}</i><input type="text" value="search input in menu"></div>
<div class="item"><input type="radio">item</div>
<div class="item"><input type="radio">item</div>
</div>
</div>
<div class="ui search selection dropdown">
<span class="text">search ...</span>
<input name="value" class="search">
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{svg "octicon-x" 14 "remove icon"}}
<div class="menu">
<div class="item">item</div>
</div>
</div>
<div class="ui multiple selection dropdown">
<input class="hidden" value="1">
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{svg "octicon-x" 14 "remove icon"}}
<div class="default text">empty multiple dropdown</div>
<div class="menu">
<div class="item">item</div>
</div>
</div>
<div class="ui multiple clearable search selection dropdown">
<input type="hidden" value="1">
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{svg "octicon-x" 14 "remove icon"}}
<div class="default text">clearable search dropdown</div>
<div class="menu">
<div class="item" data-value="1">item</div>
</div>
</div>
<div class="ui buttons">
<button class="ui button">Button with Dropdown</button>
<div class="ui dropdown button icon">
{{svg "octicon-triangle-down"}}
<div class="menu">
<div class="item">item</div>
</div>
</div>
</div>
</div>
<div>
<div class="ui dropdown mini button">
<span class="text">mini dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui dropdown tiny button">
<span class="text">tiny dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui button dropdown">
<span class="text">button dropdown</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
</div>
<div>
<div class="ui dropdown mini compact button">
<span class="text">mini compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui dropdown tiny compact button">
<span class="text">tiny compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
<div class="ui button compact dropdown">
<span class="text">button compact</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
</div>
<div>
<hr>
<div class="ui tiny button">Button align with ...</div>
<div class="ui dropdown tiny button">
<span class="text">... Dropdown Button</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</div>
</div>
</div>
<div>

View File

@ -69,7 +69,7 @@
<div class="js-branch-tag-selector {{if .ContainerClasses}}{{.ContainerClasses}}{{end}}">
{{/* show dummy elements before Vue componment is mounted, this code must match the code in BranchTagSelector.vue */}}
<div class="ui dropdown custom branch-selector-dropdown">
<div class="ui dropdown custom branch-selector-dropdown ellipsis-items-nowrap">
<div class="ui button branch-dropdown-button">
<span class="flex-text-block gt-ellipsis">
{{if .release}}

View File

@ -128,107 +128,109 @@
{{if .IsGenerated}}<div class="fork-flag">{{ctx.Locale.Tr "repo.generated_from"}} <a href="{{(.TemplateRepo ctx).Link}}">{{(.TemplateRepo ctx).FullName}}</a></div>{{end}}
</div>
{{end}}
<overflow-menu class="ui container secondary pointing tabular top attached borderless menu tw-pt-0 tw-my-0">
{{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}}
<div class="overflow-menu-items">
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}}
<a class="{{if .PageIsViewCode}}active {{end}}item" href="{{.RepoLink}}{{if and (ne .BranchName .Repository.DefaultBranch) (not $.PageIsWiki)}}/src/{{.BranchNameSubURL}}{{end}}">
{{svg "octicon-code"}} {{ctx.Locale.Tr "repo.code"}}
</a>
{{end}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeIssues}}
<a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoLink}}/issues">
{{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues"}}
{{if .Repository.NumOpenIssues}}
<span class="ui small label">{{CountFmt .Repository.NumOpenIssues}}</span>
{{end}}
<div class="ui container">
<overflow-menu class="ui secondary pointing menu">
{{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}}
<div class="overflow-menu-items">
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}}
<a class="{{if .PageIsViewCode}}active {{end}}item" href="{{.RepoLink}}{{if and (ne .BranchName .Repository.DefaultBranch) (not $.PageIsWiki)}}/src/{{.BranchNameSubURL}}{{end}}">
{{svg "octicon-code"}} {{ctx.Locale.Tr "repo.code"}}
</a>
{{end}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalTracker}}
<a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer">
{{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.issues"}}
</a>
{{end}}
{{if and .Repository.CanEnablePulls (.Permission.CanRead ctx.Consts.RepoUnitTypePullRequests)}}
<a class="{{if .PageIsPullList}}active {{end}}item" href="{{.RepoLink}}/pulls">
{{svg "octicon-git-pull-request"}} {{ctx.Locale.Tr "repo.pulls"}}
{{if .Repository.NumOpenPulls}}
<span class="ui small label">{{CountFmt .Repository.NumOpenPulls}}</span>
{{end}}
</a>
{{end}}
{{if and .EnableActions (not .UnitActionsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeActions)}}
<a class="{{if .PageIsActions}}active {{end}}item" href="{{.RepoLink}}/actions">
{{svg "octicon-play"}} {{ctx.Locale.Tr "actions.actions"}}
{{if .Repository.NumOpenActionRuns}}
<span class="ui small label">{{CountFmt .Repository.NumOpenActionRuns}}</span>
{{end}}
</a>
{{end}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypePackages}}
<a href="{{.RepoLink}}/packages" class="{{if .IsPackagesPage}}active {{end}}item">
{{svg "octicon-package"}} {{ctx.Locale.Tr "packages.title"}}
</a>
{{end}}
{{$projectsUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeProjects}}
{{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeProjects) ($projectsUnit.ProjectsConfig.IsProjectsAllowed "repo")}}
<a href="{{.RepoLink}}/projects" class="{{if .IsProjectsPage}}active {{end}}item">
{{svg "octicon-project"}} {{ctx.Locale.Tr "repo.project_board"}}
{{if .Repository.NumOpenProjects}}
<span class="ui small label">{{CountFmt .Repository.NumOpenProjects}}</span>
{{end}}
</a>
{{end}}
{{if and (.Permission.CanRead ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}}
<a class="{{if or .PageIsReleaseList .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/releases">
{{svg "octicon-tag"}} {{ctx.Locale.Tr "repo.releases"}}
{{if .NumReleases}}
<span class="ui small label">{{CountFmt .NumReleases}}</span>
{{end}}
</a>
{{end}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeWiki}}
<a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki">
{{svg "octicon-book"}} {{ctx.Locale.Tr "repo.wiki"}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeIssues}}
<a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoLink}}/issues">
{{svg "octicon-issue-opened"}} {{ctx.Locale.Tr "repo.issues"}}
{{if .Repository.NumOpenIssues}}
<span class="ui small label">{{CountFmt .Repository.NumOpenIssues}}</span>
{{end}}
</a>
{{end}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalTracker}}
<a class="{{if .PageIsIssueList}}active {{end}}item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer">
{{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.issues"}}
</a>
{{end}}
{{if and .Repository.CanEnablePulls (.Permission.CanRead ctx.Consts.RepoUnitTypePullRequests)}}
<a class="{{if .PageIsPullList}}active {{end}}item" href="{{.RepoLink}}/pulls">
{{svg "octicon-git-pull-request"}} {{ctx.Locale.Tr "repo.pulls"}}
{{if .Repository.NumOpenPulls}}
<span class="ui small label">{{CountFmt .Repository.NumOpenPulls}}</span>
{{end}}
</a>
{{end}}
{{if and .EnableActions (not .UnitActionsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeActions)}}
<a class="{{if .PageIsActions}}active {{end}}item" href="{{.RepoLink}}/actions">
{{svg "octicon-play"}} {{ctx.Locale.Tr "actions.actions"}}
{{if .Repository.NumOpenActionRuns}}
<span class="ui small label">{{CountFmt .Repository.NumOpenActionRuns}}</span>
{{end}}
</a>
{{end}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypePackages}}
<a href="{{.RepoLink}}/packages" class="{{if .IsPackagesPage}}active {{end}}item">
{{svg "octicon-package"}} {{ctx.Locale.Tr "packages.title"}}
</a>
{{end}}
{{$projectsUnit := .Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeProjects}}
{{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead ctx.Consts.RepoUnitTypeProjects) ($projectsUnit.ProjectsConfig.IsProjectsAllowed "repo")}}
<a href="{{.RepoLink}}/projects" class="{{if .IsProjectsPage}}active {{end}}item">
{{svg "octicon-project"}} {{ctx.Locale.Tr "repo.project_board"}}
{{if .Repository.NumOpenProjects}}
<span class="ui small label">{{CountFmt .Repository.NumOpenProjects}}</span>
{{end}}
</a>
{{end}}
{{if and (.Permission.CanRead ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}}
<a class="{{if or .PageIsReleaseList .PageIsTagList}}active {{end}}item" href="{{.RepoLink}}/releases">
{{svg "octicon-tag"}} {{ctx.Locale.Tr "repo.releases"}}
{{if .NumReleases}}
<span class="ui small label">{{CountFmt .NumReleases}}</span>
{{end}}
</a>
{{end}}
{{end}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalWiki}}
<a class="item" href="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}" target="_blank" rel="noopener noreferrer">
{{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.wiki"}}
</a>
{{end}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeWiki}}
<a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki">
{{svg "octicon-book"}} {{ctx.Locale.Tr "repo.wiki"}}
</a>
{{end}}
{{if and (.Permission.CanReadAny ctx.Consts.RepoUnitTypePullRequests ctx.Consts.RepoUnitTypeIssues ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}}
<a class="{{if .PageIsActivity}}active {{end}}item" href="{{.RepoLink}}/activity">
{{svg "octicon-pulse"}} {{ctx.Locale.Tr "repo.activity"}}
</a>
{{end}}
{{if .Permission.CanRead ctx.Consts.RepoUnitTypeExternalWiki}}
<a class="item" href="{{(.Repository.MustGetUnit $.Context ctx.Consts.RepoUnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}" target="_blank" rel="noopener noreferrer">
{{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.wiki"}}
</a>
{{end}}
{{template "custom/extra_tabs" .}}
{{if and (.Permission.CanReadAny ctx.Consts.RepoUnitTypePullRequests ctx.Consts.RepoUnitTypeIssues ctx.Consts.RepoUnitTypeReleases) (not .IsEmptyRepo)}}
<a class="{{if .PageIsActivity}}active {{end}}item" href="{{.RepoLink}}/activity">
{{svg "octicon-pulse"}} {{ctx.Locale.Tr "repo.activity"}}
</a>
{{end}}
{{if .Permission.IsAdmin}}
<span class="item-flex-space"></span>
{{template "custom/extra_tabs" .}}
{{if .Permission.IsAdmin}}
<span class="item-flex-space"></span>
<a class="{{if .PageIsRepoSettings}}active {{end}} item" href="{{.RepoLink}}/settings">
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}
</a>
{{end}}
</div>
{{else if .Permission.IsAdmin}}
<div class="overflow-menu-items">
<a class="{{if .PageIsRepoSettings}}active {{end}} item" href="{{.RepoLink}}/settings">
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}
</a>
{{end}}
</div>
{{else if .Permission.IsAdmin}}
<div class="overflow-menu-items">
<a class="{{if .PageIsRepoSettings}}active {{end}} item" href="{{.RepoLink}}/settings">
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}
</a>
</div>
{{end}}
</overflow-menu>
</div>
{{end}}
</overflow-menu>
</div>
<div class="ui tabs divider"></div>
</div>

View File

@ -4,7 +4,7 @@
<form method="post" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/ref" id="update_issueref_form">
{{$.CsrfTokenHtml}}
</form>
<div class="ui dropdown select-branch branch-selector-dropdown {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}}"
<div class="ui dropdown select-branch branch-selector-dropdown ellipsis-items-nowrap {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}}"
data-no-results="{{ctx.Locale.Tr "no_results_found"}}"
{{if not .Issue}}data-for-new-issue="true"{{end}}
>

View File

@ -7,7 +7,7 @@
{{.CsrfTokenHtml}}
<div class="field">
<label><strong>{{ctx.Locale.Tr "repository"}}</strong></label>
<div class="ui search selection dropdown issue_reference_repository_search">
<div class="ui search selection dropdown issue_reference_repository_search ellipsis-items-nowrap">
<div class="default text gt-ellipsis">{{.Repository.FullName}}</div>
<div class="menu"></div>
</div>

View File

@ -4,29 +4,36 @@
</div>
{{end}}
<div class="issue-title-header">
<div class="issue-title" id="issue-title-wrapper">
{{$canEditIssueTitle := and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}}
<div class="issue-title" id="issue-title-display">
<h1 class="gt-word-break">
<span id="issue-title">{{RenderIssueTitle $.Context .Issue.Title ($.Repository.ComposeMetas ctx) | RenderCodeBlock}} <span class="index">#{{.Issue.Index}}</span>
</span>
<div id="edit-title-input" class="ui input tw-flex-1 tw-hidden">
<input value="{{.Issue.Title}}" maxlength="255" autocomplete="off">
</div>
{{RenderIssueTitle $.Context .Issue.Title ($.Repository.ComposeMetas ctx) | RenderCodeBlock}}
<span class="index">#{{.Issue.Index}}</span>
</h1>
<div class="issue-title-buttons">
{{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}}
<button id="edit-title" class="ui small basic button edit-button not-in-edit{{if .Issue.IsPull}} tw-mr-0{{end}}">{{ctx.Locale.Tr "repo.issues.edit"}}</button>
{{if $canEditIssueTitle}}
<button id="issue-title-edit-show" class="ui small basic button">{{ctx.Locale.Tr "repo.issues.edit"}}</button>
{{end}}
{{if not .Issue.IsPull}}
<a role="button" class="ui small primary button new-issue-button tw-mr-0" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{ctx.Locale.Tr "repo.issues.new"}}</a>
<a role="button" class="ui small primary button" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{ctx.Locale.Tr "repo.issues.new"}}</a>
{{end}}
</div>
{{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}}
<div class="edit-buttons">
<button id="cancel-edit-title" class="ui small basic button in-edit tw-hidden">{{ctx.Locale.Tr "repo.issues.cancel"}}</button>
<button id="save-edit-title" class="ui small primary button in-edit tw-hidden tw-mr-0" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title" {{if .Issue.IsPull}}data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch"{{end}}>{{ctx.Locale.Tr "repo.issues.save"}}</button>
</div>
{{end}}
</div>
{{if $canEditIssueTitle}}
<div class="ui form issue-title tw-hidden" id="issue-title-editor">
<div class="ui input tw-flex-1">
<input value="{{.Issue.Title}}" data-old-title="{{.Issue.Title}}" maxlength="255" autocomplete="off">
</div>
<div class="issue-title-buttons">
<button class="ui small basic cancel button">{{ctx.Locale.Tr "repo.issues.cancel"}}</button>
<button class="ui small primary button"
data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/title"
{{if .Issue.IsPull}}data-target-update-url="{{$.RepoLink}}/pull/{{.Issue.Index}}/target_branch"{{end}}>
{{ctx.Locale.Tr "repo.issues.save"}}
</button>
</div>
</div>
{{end}}
<div class="issue-title-meta">
{{if .HasMerged}}
<div class="ui purple label issue-state-label">{{svg "octicon-git-merge" 16 "tw-mr-1"}} {{if eq .Issue.PullRequest.Status 3}}{{ctx.Locale.Tr "repo.pulls.manually_merged"}}{{else}}{{ctx.Locale.Tr "repo.pulls.merged"}}{{end}}</div>
@ -63,14 +70,14 @@
{{end}}
{{else}}
{{if .Issue.OriginalAuthor}}
<span id="pull-desc" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}}</span>
<span id="pull-desc-display" class="pull-desc">{{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}}</span>
{{else}}
<span id="pull-desc" class="pull-desc">
<span id="pull-desc-display" class="pull-desc">
<a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a>
{{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}}
</span>
{{end}}
<span id="pull-desc-edit" class="tw-hidden flex-text-block">
<span id="pull-desc-editor" class="tw-hidden flex-text-block">
<div class="ui floating filter dropdown">
<div class="ui basic small button tw-mr-0">
<span class="text">{{ctx.Locale.Tr "repo.pulls.compare_compare"}}: {{$.HeadTarget}}</span>

View File

@ -345,7 +345,7 @@
<div class="inline field">
{{$unitInternalWiki := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeWiki}}
<label>{{ctx.Locale.Tr "repo.settings.default_wiki_everyone_access"}}</label>
<select name="default_wiki_everyone_access" class="ui dropdown">
<select name="default_wiki_everyone_access" class="ui selection dropdown">
{{/* everyone access mode is different from others, none means it is unset and won't be applied */}}
<option value="none" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option>
<option value="read" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 1) "selected"}}>{{ctx.Locale.Tr "settings.permission_read"}}</option>

View File

@ -195,14 +195,17 @@ func TestAPIEditUser(t *testing.T) {
token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin)
urlStr := fmt.Sprintf("/api/v1/admin/users/%s", "user2")
fullNameToChange := "Full Name User 2"
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
// required
"login_name": "user2",
"source_id": "0",
// to change
"full_name": "Full Name User 2",
"full_name": fullNameToChange,
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusOK)
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"})
assert.Equal(t, fullNameToChange, user2.FullName)
empty := ""
req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{
@ -216,7 +219,7 @@ func TestAPIEditUser(t *testing.T) {
json.Unmarshal(resp.Body.Bytes(), &errMap)
assert.EqualValues(t, "e-mail invalid [email: ]", errMap["message"].(string))
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"})
user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"})
assert.False(t, user2.IsRestricted)
bTrue := true
req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{

View File

@ -144,7 +144,7 @@ func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
val := htmlDoc.doc.Find("#issue-title").Text()
val := htmlDoc.doc.Find("#issue-title-display").Text()
assert.Contains(t, val, title)
val = htmlDoc.doc.Find(".comment .render-content p").First().Text()
assert.Equal(t, content, val)

View File

@ -125,7 +125,7 @@ func TestPullCreate_TitleEscape(t *testing.T) {
req := NewRequest(t, "GET", url)
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
editTestTitleURL, exists := htmlDoc.doc.Find("#save-edit-title").First().Attr("data-update-url")
editTestTitleURL, exists := htmlDoc.doc.Find(".issue-title-buttons button[data-update-url]").First().Attr("data-update-url")
assert.True(t, exists, "The template has changed")
req = NewRequestWithValues(t, "POST", editTestTitleURL, map[string]string{

View File

@ -342,8 +342,6 @@ a.label,
.ui.dropdown .menu > .item {
color: var(--color-text);
overflow: hidden;
text-overflow: ellipsis;
}
.ui.dropdown .menu > .item:hover {
@ -374,7 +372,6 @@ a.label,
.ui.selection.dropdown .menu > .item {
border-color: var(--color-secondary);
white-space: nowrap;
}
.ui.selection.visible.dropdown > .text:not(.default) {
@ -1342,7 +1339,11 @@ table th[data-sortt-desc] .svg {
align-items: center;
gap: .25rem;
vertical-align: middle;
min-width: 0;
min-width: 0; /* make ellipsis work */
}
.ui.ui.dropdown.selection {
min-width: 14em; /* match the default min width */
}
.ui.dropdown .ui.label .svg {
@ -1369,3 +1370,16 @@ table th[data-sortt-desc] .svg {
gap: .5rem;
min-width: 0;
}
.ui.dropdown.ellipsis-items-nowrap > .text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.ellipsis-items-nowrap > .item,
.ui.dropdown.ellipsis-items-nowrap .menu > .item {
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}

View File

@ -448,6 +448,10 @@ textarea:focus,
}
}
.ui.form .field > .selection.dropdown {
min-width: 14em; /* matches the default min width */
}
.new.webhook form .help {
margin-left: 25px;
}

View File

@ -2,26 +2,20 @@
unused rules here after refactoring, please remove them. */
.ui.container {
display: block;
max-width: 100%;
}
.ui.fluid.container {
width: 100%;
}
.ui[class*="center aligned"].container {
text-align: center;
}
/* overwrite width of containers inside the main page content div (div with class "page-content") */
.page-content .ui.ui.ui.container:not(.fluid) {
width: 1280px;
max-width: calc(100% - calc(2 * var(--page-margin-x)));
margin-left: auto;
margin-right: auto;
}
.ui.fluid.container {
width: 100%;
}
.ui.container.fluid.padded {
padding: 0 var(--page-margin-x);
}
.ui[class*="center aligned"].container {
text-align: center;
}

View File

@ -575,34 +575,7 @@ td .commit-summary {
display: inline-block;
}
.issue-title-header {
width: 100%;
padding-bottom: 4px;
margin-bottom: 1rem;
}
.issue-title-meta {
display: flex;
align-items: center;
}
.repository.view.issue .issue-title-buttons,
.repository.view.issue .edit-buttons {
display: flex;
}
@media (max-width: 767.98px) {
.repository.view.issue .issue-title {
flex-direction: column;
}
.repository.view.issue .issue-title-buttons,
.repository.view.issue .edit-buttons {
width: 100%;
justify-content: space-between;
}
.repository.view.issue .edit-buttons {
margin-top: .5rem;
}
.comment.form .issue-content-left .avatar {
display: none;
}
@ -617,15 +590,37 @@ td .commit-summary {
}
}
/* issue title & meta & edit */
.issue-title-header {
width: 100%;
padding-bottom: 4px;
margin-bottom: 1rem;
}
.issue-title-meta {
display: flex;
align-items: center;
}
.repository.view.issue .issue-title-buttons {
display: flex;
gap: 0.5em;
}
.repository.view.issue .issue-title-buttons > .ui.button {
margin: 0;
height: 35px;
}
.repository.view.issue .issue-title {
display: flex;
align-items: center;
gap: 0.5em;
margin-bottom: 8px;
min-height: 40px; /* avoid layout shift on edit */
}
.repository.view.issue .issue-title h1 {
display: flex;
align-items: center;
flex: 1;
width: 100%;
font-weight: var(--font-weight-normal);
@ -633,14 +628,24 @@ td .commit-summary {
line-height: 40px;
margin: 0;
padding-right: 0.25rem;
min-height: 41px; /* avoid layout shift on edit */
}
.repository.view.issue .issue-title h1 .ui.input {
font-size: 0.5em;
@media (max-width: 767.98px) {
.repository.view.issue .issue-title {
flex-direction: column;
}
.repository.view.issue .issue-title-buttons {
width: 100%;
justify-content: space-between;
}
}
.repository.view.issue .issue-title h1 .ui.input input {
.repository.view.issue .issue-title .ui.input {
width: 100%;
height: 35px;
}
.repository.view.issue .issue-title .ui.input input {
font-size: 1.5em;
padding: 2px .5rem;
}
@ -653,10 +658,6 @@ td .commit-summary {
margin-right: 10px;
}
.issue-title .edit-zone {
margin-top: 10px;
}
.issue-state-label {
display: flex !important;
align-items: center !important;
@ -2859,6 +2860,10 @@ tbody.commit-list {
margin-top: 4px;
}
.ui.dropdown.branch-selector-dropdown .scrolling.menu {
max-width: min(400px, 90vw);
}
.branch-selector-dropdown .branch-dropdown-button {
margin: 0;
max-width: 340px;
@ -2908,6 +2913,8 @@ tbody.commit-list {
}
.branch-selector-dropdown .menu .item .rss-icon {
position: absolute;
right: 4px;
visibility: hidden; /* only show RSS icon on hover */
}

View File

@ -6,13 +6,20 @@
// This file must be imported before any lazy-loading is being attempted.
__webpack_public_path__ = `${window.config?.assetUrlPrefix ?? '/assets'}/`;
export function showGlobalErrorMessage(msg) {
const pageContent = document.querySelector('.page-content');
if (!pageContent) return;
function shouldIgnoreError(err) {
const ignorePatterns = [
'/assets/js/monaco.', // https://github.com/go-gitea/gitea/issues/30861 , https://github.com/microsoft/monaco-editor/issues/4496
];
for (const pattern of ignorePatterns) {
if (err.stack?.includes(pattern)) return true;
}
return false;
}
// compact the message to a data attribute to avoid too many duplicated messages
const msgCompact = msg.replace(/\W/g, '').trim();
let msgDiv = pageContent.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`);
export function showGlobalErrorMessage(msg) {
const msgContainer = document.querySelector('.page-content') ?? document.body;
const msgCompact = msg.replace(/\W/g, '').trim(); // compact the message to a data attribute to avoid too many duplicated messages
let msgDiv = msgContainer.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`);
if (!msgDiv) {
const el = document.createElement('div');
el.innerHTML = `<div class="ui container negative message center aligned js-global-error tw-mt-[15px] tw-whitespace-pre-line"></div>`;
@ -23,7 +30,7 @@ export function showGlobalErrorMessage(msg) {
msgDiv.setAttribute(`data-global-error-msg-compact`, msgCompact);
msgDiv.setAttribute(`data-global-error-msg-count`, msgCount.toString());
msgDiv.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : '');
pageContent.prepend(msgDiv);
msgContainer.prepend(msgDiv);
}
/**
@ -52,10 +59,12 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno
if (runModeIsProd) return;
}
// If the error stack trace does not include the base URL of our script assets, it likely came
// from a browser extension or inline script. Do not show such errors in production.
if (err instanceof Error && !err.stack?.includes(assetBaseUrl) && runModeIsProd) {
return;
if (err instanceof Error) {
// If the error stack trace does not include the base URL of our script assets, it likely came
// from a browser extension or inline script. Do not show such errors in production.
if (!err.stack?.includes(assetBaseUrl) && runModeIsProd) return;
// Ignore some known errors that are unable to fix
if (shouldIgnoreError(err)) return;
}
let msg = err?.message ?? message;

View File

@ -246,7 +246,7 @@ export function initRepoBranchTagSelector(selector) {
export default sfc; // activate IDE's Vue plugin
</script>
<template>
<div class="ui dropdown custom branch-selector-dropdown">
<div class="ui dropdown custom branch-selector-dropdown ellipsis-items-nowrap">
<div class="ui button branch-dropdown-button" @click="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible">
<span class="flex-text-block gt-ellipsis">
<template v-if="release">{{ textReleaseCompare }}</template>
@ -280,7 +280,7 @@ export default sfc; // activate IDE's Vue plugin
<div class="ui label" v-if="item.name===repoDefaultBranch && mode === 'branches'">
{{ textDefaultBranchLabel }}
</div>
<a v-show="enableFeed && mode === 'branches'" role="button" class="rss-icon tw-float-right" :href="rssURLPrefix + item.url" target="_blank" @click.stop>
<a v-show="enableFeed && mode === 'branches'" role="button" class="rss-icon" :href="rssURLPrefix + item.url" target="_blank" @click.stop>
<!-- creating a lot of Vue component is pretty slow, so we use a static SVG here -->
<svg width="14" height="14" class="svg octicon-rss"><use href="#svg-symbol-octicon-rss"/></svg>
</a>

View File

@ -47,10 +47,18 @@ export function initFootLanguageMenu() {
export function initGlobalEnterQuickSubmit() {
document.addEventListener('keydown', (e) => {
const isQuickSubmitEnter = ((e.ctrlKey && !e.altKey) || e.metaKey) && (e.key === 'Enter');
if (isQuickSubmitEnter && e.target.matches('textarea')) {
e.preventDefault();
handleGlobalEnterQuickSubmit(e.target);
if (e.key !== 'Enter') return;
const hasCtrlOrMeta = ((e.ctrlKey || e.metaKey) && !e.altKey);
if (hasCtrlOrMeta && e.target.matches('textarea')) {
if (handleGlobalEnterQuickSubmit(e.target)) {
e.preventDefault();
}
} else if (e.target.matches('input') && !e.target.closest('form')) {
// input in a normal form could handle Enter key by default, so we only handle the input outside a form
// eslint-disable-next-line unicorn/no-lonely-if
if (handleGlobalEnterQuickSubmit(e.target)) {
e.preventDefault();
}
}
});
}

View File

@ -3,16 +3,17 @@ export function handleGlobalEnterQuickSubmit(target) {
if (form) {
if (!form.checkValidity()) {
form.reportValidity();
return;
} else {
// here use the event to trigger the submit event (instead of calling `submit()` method directly)
// otherwise the `areYouSure` handler won't be executed, then there will be an annoying "confirm to leave" dialog
form.dispatchEvent(new SubmitEvent('submit', {bubbles: true, cancelable: true}));
}
// here use the event to trigger the submit event (instead of calling `submit()` method directly)
// otherwise the `areYouSure` handler won't be executed, then there will be an annoying "confirm to leave" dialog
form.dispatchEvent(new SubmitEvent('submit', {bubbles: true, cancelable: true}));
return;
return true;
}
form = target.closest('.ui.form');
if (form) {
form.querySelector('.ui.primary.button')?.click();
return true;
}
return false;
}

View File

@ -7,6 +7,7 @@ import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkd
import {toAbsoluteUrl} from '../utils.js';
import {initDropzone} from './common-global.js';
import {POST, GET} from '../modules/fetch.js';
import {showErrorToast} from '../modules/toast.js';
const {appSubUrl} = window.config;
@ -123,8 +124,8 @@ export function initRepoIssueSidebarList() {
return;
}
filteredResponse.results.push({
name: `#${issue.number} ${htmlEscape(issue.title)
}<div class="text small gt-word-break">${htmlEscape(issue.repository.full_name)}</div>`,
name: `<div class="gt-ellipsis">#${issue.number} ${htmlEscape(issue.title)}</div>
<div class="text small gt-word-break">${htmlEscape(issue.repository.full_name)}</div>`,
value: issue.id,
});
});
@ -602,85 +603,69 @@ export function initRepoIssueWipToggle() {
});
}
async function pullrequest_targetbranch_change(update_url) {
const targetBranch = $('#pull-target-branch').data('branch');
const $branchTarget = $('#branch_target');
if (targetBranch === $branchTarget.text()) {
window.location.reload();
return false;
}
try {
await POST(update_url, {data: new URLSearchParams({target_branch: targetBranch})});
} catch (error) {
console.error(error);
} finally {
window.location.reload();
}
}
export function initRepoIssueTitleEdit() {
// Edit issue title
const $issueTitle = $('#issue-title');
const $editInput = $('#edit-title-input input');
const issueTitleDisplay = document.querySelector('#issue-title-display');
const issueTitleEditor = document.querySelector('#issue-title-editor');
if (!issueTitleEditor) return;
const editTitleToggle = function () {
toggleElem($issueTitle);
toggleElem('.not-in-edit');
toggleElem('#edit-title-input');
toggleElem('#pull-desc');
toggleElem('#pull-desc-edit');
toggleElem('.in-edit');
toggleElem('.new-issue-button');
document.getElementById('issue-title-wrapper')?.classList.toggle('edit-active');
$editInput[0].focus();
$editInput[0].select();
return false;
};
$('#edit-title').on('click', editTitleToggle);
$('#cancel-edit-title').on('click', editTitleToggle);
$('#save-edit-title').on('click', editTitleToggle).on('click', async function () {
const pullrequest_target_update_url = this.getAttribute('data-target-update-url');
if (!$editInput.val().length || $editInput.val() === $issueTitle.text()) {
$editInput.val($issueTitle.text());
await pullrequest_targetbranch_change(pullrequest_target_update_url);
} else {
try {
const params = new URLSearchParams();
params.append('title', $editInput.val());
const response = await POST(this.getAttribute('data-update-url'), {data: params});
const data = await response.json();
$editInput.val(data.title);
$issueTitle.text(data.title);
if (pullrequest_target_update_url) {
await pullrequest_targetbranch_change(pullrequest_target_update_url); // it will reload the window
} else {
window.location.reload();
}
} catch (error) {
console.error(error);
}
const issueTitleInput = issueTitleEditor.querySelector('input');
const oldTitle = issueTitleInput.getAttribute('data-old-title');
issueTitleDisplay.querySelector('#issue-title-edit-show').addEventListener('click', () => {
hideElem(issueTitleDisplay);
hideElem('#pull-desc-display');
showElem(issueTitleEditor);
showElem('#pull-desc-editor');
if (!issueTitleInput.value.trim()) {
issueTitleInput.value = oldTitle;
}
issueTitleInput.focus();
});
issueTitleEditor.querySelector('.ui.cancel.button').addEventListener('click', () => {
hideElem(issueTitleEditor);
hideElem('#pull-desc-editor');
showElem(issueTitleDisplay);
showElem('#pull-desc-display');
});
const editSaveButton = issueTitleEditor.querySelector('.ui.primary.button');
editSaveButton.addEventListener('click', async () => {
const prTargetUpdateUrl = editSaveButton.getAttribute('data-target-update-url');
const newTitle = issueTitleInput.value.trim();
try {
if (newTitle && newTitle !== oldTitle) {
const resp = await POST(editSaveButton.getAttribute('data-update-url'), {data: new URLSearchParams({title: newTitle})});
if (!resp.ok) {
throw new Error(`Failed to update issue title: ${resp.statusText}`);
}
}
if (prTargetUpdateUrl) {
const newTargetBranch = document.querySelector('#pull-target-branch').getAttribute('data-branch');
const oldTargetBranch = document.querySelector('#branch_target').textContent;
if (newTargetBranch !== oldTargetBranch) {
const resp = await POST(prTargetUpdateUrl, {data: new URLSearchParams({target_branch: newTargetBranch})});
if (!resp.ok) {
throw new Error(`Failed to update PR target branch: ${resp.statusText}`);
}
}
}
window.location.reload();
} catch (error) {
console.error(error);
showErrorToast(error.message);
}
return false;
});
}
export function initRepoIssueBranchSelect() {
const changeBranchSelect = function () {
const $selectionTextField = $('#pull-target-branch');
const baseName = $selectionTextField.data('basename');
const branchNameNew = $(this).data('branch');
const branchNameOld = $selectionTextField.data('branch');
// Replace branch name to keep translation from HTML template
$selectionTextField.html($selectionTextField.html().replace(
`${baseName}:${branchNameOld}`,
`${baseName}:${branchNameNew}`,
));
$selectionTextField.data('branch', branchNameNew); // update branch name in setting
};
$('#branch-select > .item').on('click', changeBranchSelect);
document.querySelector('#branch-select')?.addEventListener('click', (e) => {
const el = e.target.closest('.item[data-branch]');
if (!el) return;
const pullTargetBranch = document.querySelector('#pull-target-branch');
const baseName = pullTargetBranch.getAttribute('data-basename');
const branchNameNew = el.getAttribute('data-branch');
const branchNameOld = pullTargetBranch.getAttribute('data-branch');
pullTargetBranch.textContent = pullTargetBranch.textContent.replace(`${baseName}:${branchNameOld}`, `${baseName}:${branchNameNew}`);
pullTargetBranch.setAttribute('data-branch', branchNameNew);
});
}
export function initSingleCommentEditor($commentForm) {