mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-20 20:07:03 +01:00
feat(tmpl): Introduce semantic HTML in forms
Modifies forms: - (new) org team - (new) repo webhook - (new) repo protected branch The forms are not completely rewritten to semantic HTML yet. The focus of this change was on standard elements, some custom solutions were left untouched for now. - swaps the order fo permission radio buttons as per https://codeberg.org/forgejo/forgejo/issues/4983 - uses fieldsets to group related inputs - ensures consistent styling across forms - can be improved later, e.g. using horizontal lines between sections - fixes: previous font size of labels was smaller than the font size of the help text - help text are now part of the label, clicking them now also activates the input - drop unused CSS (no required checkboxes in grouped class remain) - playwright testing: - move login boilerplate to utils - automated form accessibility checking - allow defining the scope, because legacy parts of the forms are not yet accessible - assert some CSS properties that should not be overriden - the Makefile adjustment was necessary, because eslint scanned some internal files in the tests/e2e/reports directory
This commit is contained in:
parent
f9ba752140
commit
c9e402afdc
13 changed files with 296 additions and 216 deletions
2
Makefile
2
Makefile
|
@ -154,7 +154,7 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMAN
|
|||
GO_DIRS := build cmd models modules routers services tests
|
||||
WEB_DIRS := web_src/js web_src/css
|
||||
|
||||
ESLINT_FILES := web_src/js tools *.js tests/e2e
|
||||
ESLINT_FILES := web_src/js tools *.js tests/e2e/*.js tests/e2e/shared/*.js
|
||||
STYLELINT_FILES := web_src/css web_src/js/components/*.vue
|
||||
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github $(wildcard *.go *.js *.md *.yml *.yaml *.toml)
|
||||
|
||||
|
|
22
package-lock.json
generated
22
package-lock.json
generated
|
@ -60,6 +60,7 @@
|
|||
"wrap-ansi": "9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@axe-core/playwright": "4.9.1",
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "4.4.0",
|
||||
"@playwright/test": "1.46.1",
|
||||
"@stoplight/spectral-cli": "6.11.1",
|
||||
|
@ -136,6 +137,27 @@
|
|||
"@types/json-schema": "^7.0.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@axe-core/playwright": {
|
||||
"version": "4.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.9.1.tgz",
|
||||
"integrity": "sha512-8m4WZbZq7/aq7ZY5IG8GqV+ZdvtGn/iJdom+wBg+iv/3BAOBIfNQtIu697a41438DzEEyptXWmC3Xl5Kx/o9/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"axe-core": "~4.9.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"playwright-core": ">= 1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@axe-core/playwright/node_modules/axe-core": {
|
||||
"version": "4.9.1",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz",
|
||||
"integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
"wrap-ansi": "9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@axe-core/playwright": "4.9.1",
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "4.4.0",
|
||||
"@playwright/test": "1.46.1",
|
||||
"@stoplight/spectral-cli": "6.11.1",
|
||||
|
|
|
@ -25,53 +25,40 @@
|
|||
<span class="help">{{ctx.Locale.Tr "org.team_desc_helper"}}</span>
|
||||
</div>
|
||||
{{if not (eq .Team.LowerName "owners")}}
|
||||
<div class="grouped field">
|
||||
<label>{{ctx.Locale.Tr "org.team_access_desc"}}</label>
|
||||
<br>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="repo_access" value="specific" {{if not .Team.IncludesAllRepositories}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "org.teams.specific_repositories"}}</label>
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.specific_repositories_helper"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="repo_access" value="all" {{if .Team.IncludesAllRepositories}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "org.teams.all_repositories"}}</label>
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.all_repositories_helper"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset>
|
||||
<legend>{{ctx.Locale.Tr "org.team_access_desc"}}</legend>
|
||||
<label>
|
||||
<input type="radio" name="repo_access" value="specific" {{if not .Team.IncludesAllRepositories}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "org.teams.specific_repositories"}}
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.specific_repositories_helper"}}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="repo_access" value="all" {{if .Team.IncludesAllRepositories}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "org.teams.all_repositories"}}
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.all_repositories_helper"}}</span>
|
||||
</label>
|
||||
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="can_create_org_repo">{{ctx.Locale.Tr "org.teams.can_create_org_repo"}}</label>
|
||||
<input id="can_create_org_repo" name="can_create_org_repo" type="checkbox" {{if .Team.CanCreateOrgRepo}}checked{{end}}>
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.can_create_org_repo_helper"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grouped field">
|
||||
<label>{{ctx.Locale.Tr "org.team_permission_desc"}}</label>
|
||||
<br>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="permission" value="read" {{if or .PageIsOrgTeamsNew (eq .Team.AccessMode 1) (eq .Team.AccessMode 2)}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "org.teams.general_access"}}</label>
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.general_access_helper"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="permission" value="admin" {{if eq .Team.AccessMode 3}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "org.teams.admin_access"}}</label>
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.admin_access_helper"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<label>
|
||||
<input name="can_create_org_repo" type="checkbox" {{if .Team.CanCreateOrgRepo}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "org.teams.can_create_org_repo"}}
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.can_create_org_repo_helper"}}</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{ctx.Locale.Tr "org.team_permission_desc"}}</legend>
|
||||
<label>
|
||||
<input type="radio" name="permission" value="admin" {{if eq .Team.AccessMode 3}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "org.teams.admin_access"}}
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.admin_access_helper"}}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="permission" value="read" {{if or .PageIsOrgTeamsNew (eq .Team.AccessMode 1) (eq .Team.AccessMode 2)}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "org.teams.general_access"}}
|
||||
<span class="help">{{ctx.Locale.Tr "org.teams.general_access_helper"}}</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<div class="team-units required grouped field {{if eq .Team.AccessMode 3}}tw-hidden{{end}}">
|
||||
<div class="team-units required field {{if eq .Team.AccessMode 3}}tw-hidden{{end}}">
|
||||
<label>{{ctx.Locale.Tr "org.team_unit_desc"}}</label>
|
||||
<table class="ui celled table">
|
||||
<thead>
|
||||
|
@ -90,44 +77,36 @@
|
|||
{{if ge $unit.MaxPerm 2}}
|
||||
<tr>
|
||||
<td>
|
||||
<div {{if $unit.Type.UnitGlobalDisabled}}class="field" data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{- else -}}class="field"{{end}}>
|
||||
<div>
|
||||
<label>{{ctx.Locale.Tr $unit.NameKey}}{{if $unit.Type.UnitGlobalDisabled}} {{ctx.Locale.Tr "org.team_unit_disabled"}}{{end}}</label>
|
||||
<span class="help">{{ctx.Locale.Tr $unit.DescKey}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<label {{if $unit.Type.UnitGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}>
|
||||
{{ctx.Locale.Tr $unit.NameKey}}{{if $unit.Type.UnitGlobalDisabled}} {{ctx.Locale.Tr "org.team_unit_disabled"}}{{end}}
|
||||
<span class="help">{{ctx.Locale.Tr $unit.DescKey}}</span>
|
||||
</label>
|
||||
</td>
|
||||
<td class="center aligned">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="unit_{{$unit.Type.Value}}" value="0"{{if or ($unit.Type.UnitGlobalDisabled) (eq ($.Team.UnitAccessMode $.Context $unit.Type) 0)}} checked{{end}} title="{{ctx.Locale.Tr "org.teams.none_access"}}">
|
||||
</div>
|
||||
<input type="radio" name="unit_{{$unit.Type.Value}}" value="0"{{if or ($unit.Type.UnitGlobalDisabled) (eq ($.Team.UnitAccessMode $.Context $unit.Type) 0)}} checked{{end}} title="{{ctx.Locale.Tr "org.teams.none_access"}}">
|
||||
</td>
|
||||
<td class="center aligned">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="unit_{{$unit.Type.Value}}" value="1"{{if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode $.Context $unit.Type) 1)}} checked{{end}} {{if $unit.Type.UnitGlobalDisabled}}disabled{{end}} title="{{ctx.Locale.Tr "org.teams.read_access"}}">
|
||||
</div>
|
||||
<input type="radio" name="unit_{{$unit.Type.Value}}" value="1"{{if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode $.Context $unit.Type) 1)}} checked{{end}} {{if $unit.Type.UnitGlobalDisabled}}disabled{{end}} title="{{ctx.Locale.Tr "org.teams.read_access"}}">
|
||||
</td>
|
||||
<td class="center aligned">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="unit_{{$unit.Type.Value}}" value="2"{{if (ge ($.Team.UnitAccessMode $.Context $unit.Type) 2)}} checked{{end}} {{if $unit.Type.UnitGlobalDisabled}}disabled{{end}} title="{{ctx.Locale.Tr "org.teams.write_access"}}">
|
||||
</div>
|
||||
<input type="radio" name="unit_{{$unit.Type.Value}}" value="2"{{if (ge ($.Team.UnitAccessMode $.Context $unit.Type) 2)}} checked{{end}} {{if $unit.Type.UnitGlobalDisabled}}disabled{{end}} title="{{ctx.Locale.Tr "org.teams.write_access"}}">
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
<fieldset>
|
||||
{{range $t, $unit := $.Units}}
|
||||
{{if lt $unit.MaxPerm 2}}
|
||||
<div {{if $unit.Type.UnitGlobalDisabled}}class="field" data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{else}}class="field"{{end}}>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="unit_{{$unit.Type.Value}}" value="1"{{if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode $.Context $unit.Type) 1)}} checked{{end}} {{if $unit.Type.UnitGlobalDisabled}}disabled{{end}}>
|
||||
<label>{{ctx.Locale.Tr $unit.NameKey}}{{if $unit.Type.UnitGlobalDisabled}} {{ctx.Locale.Tr "org.team_unit_disabled"}}{{end}}</label>
|
||||
<span class="help">{{ctx.Locale.Tr $unit.DescKey}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<label {{if $unit.Type.UnitGlobalDisabled}}data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}>
|
||||
<input type="checkbox" name="unit_{{$unit.Type.Value}}" value="1"{{if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode $.Context $unit.Type) 1)}} checked{{end}} {{if $unit.Type.UnitGlobalDisabled}}disabled{{end}}>
|
||||
{{ctx.Locale.Tr $unit.NameKey}}{{if $unit.Type.UnitGlobalDisabled}} {{ctx.Locale.Tr "org.team_unit_disabled"}}{{end}}
|
||||
<span class="help">{{ctx.Locale.Tr $unit.DescKey}}</span>
|
||||
</label>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</fieldset>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
|
|
|
@ -1,52 +1,44 @@
|
|||
{{template "repo/settings/layout_head" (dict "ctxData" . "pageClass" "repository settings branches")}}
|
||||
<div class="repo-setting-content">
|
||||
<form class="ui form" action="{{.Link}}" method="post">
|
||||
<h4 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "repo.settings.branch_protection" .Rule.RuleName}}
|
||||
</h4>
|
||||
<div class="ui attached segment branch-protection">
|
||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.protect_patterns"}}</h5>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_branch_name_pattern"}}</label>
|
||||
<h4 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "repo.settings.branch_protection" .Rule.RuleName}}
|
||||
</h4>
|
||||
<form class="ui form attached segment" action="{{.Link}}" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<input name="rule_id" type="hidden" value="{{.Rule.ID}}">
|
||||
<fieldset class="branch-protection">
|
||||
<legend>{{ctx.Locale.Tr "repo.settings.protect_patterns"}}</legend>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_branch_name_pattern"}}
|
||||
<input name="rule_name" type="text" value="{{.Rule.RuleName}}">
|
||||
<input name="rule_id" type="hidden" value="{{.Rule.ID}}">
|
||||
<p class="help tw-ml-0">{{ctx.Locale.Tr "repo.settings.protect_branch_name_pattern_desc"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_protected_file_patterns"}}</label>
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.protect_branch_name_pattern_desc"}}</span>
|
||||
</label>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_protected_file_patterns"}}
|
||||
<input name="protected_file_patterns" type="text" value="{{.Rule.ProtectedFilePatterns}}">
|
||||
<p class="help tw-ml-0">{{ctx.Locale.Tr "repo.settings.protect_protected_file_patterns_desc"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_unprotected_file_patterns"}}</label>
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.protect_protected_file_patterns_desc"}}</span>
|
||||
</label>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_unprotected_file_patterns"}}
|
||||
<input name="unprotected_file_patterns" type="text" value="{{.Rule.UnprotectedFilePatterns}}">
|
||||
<p class="help tw-ml-0">{{ctx.Locale.Tr "repo.settings.protect_unprotected_file_patterns_desc"}}</p>
|
||||
</div>
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.protect_unprotected_file_patterns_desc"}}</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
{{.CsrfTokenHtml}}
|
||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.event_push"}}</h5>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input name="enable_push" type="radio" value="none" class="toggle-target-disabled" data-target="#whitelist_box" {{if not .Rule.CanPush}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_disable_push"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.protect_disable_push_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input name="enable_push" type="radio" value="all" class="toggle-target-disabled" data-target="#whitelist_box" {{if and (.Rule.CanPush) (not .Rule.EnableWhitelist)}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_enable_push"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.protect_enable_push_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grouped fields">
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input name="enable_push" type="radio" value="whitelist" class="toggle-target-enabled" data-target="#whitelist_box" {{if and (.Rule.CanPush) (.Rule.EnableWhitelist)}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_whitelist_committers"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.protect_whitelist_committers_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset>
|
||||
<legend>{{ctx.Locale.Tr "repo.settings.event_push"}}</legend>
|
||||
<label>
|
||||
<input name="enable_push" type="radio" value="none" class="toggle-target-disabled" data-target="#whitelist_box" {{if not .Rule.CanPush}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.protect_disable_push"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.protect_disable_push_desc"}}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input name="enable_push" type="radio" value="all" class="toggle-target-disabled" data-target="#whitelist_box" {{if and (.Rule.CanPush) (not .Rule.EnableWhitelist)}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.protect_enable_push"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.protect_enable_push_desc"}}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input name="enable_push" type="radio" value="whitelist" class="toggle-target-enabled" data-target="#whitelist_box" {{if and (.Rule.CanPush) (.Rule.EnableWhitelist)}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.protect_whitelist_committers"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.protect_whitelist_committers_desc"}}</span>
|
||||
</label>
|
||||
<div id="whitelist_box" class="grouped fields {{if not .Rule.EnableWhitelist}}disabled{{end}}">
|
||||
<div class="checkbox-sub-item field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_whitelist_users"}}</label>
|
||||
|
@ -86,28 +78,25 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input name="require_signed_commits" type="checkbox" {{if .Rule.RequireSignedCommits}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.require_signed_commits"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.require_signed_commits_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.event_pull_request_approvals"}}</h5>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_required_approvals"}}</label>
|
||||
<label>
|
||||
<input name="require_signed_commits" type="checkbox" {{if .Rule.RequireSignedCommits}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.require_signed_commits"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.require_signed_commits_desc"}}</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{ctx.Locale.Tr "repo.settings.event_pull_request_approvals"}}</legend>
|
||||
<label>
|
||||
{{ctx.Locale.Tr "repo.settings.protect_required_approvals"}}
|
||||
<input name="required_approvals" type="number" value="{{.Rule.RequiredApprovals}}">
|
||||
<p class="help tw-ml-0">{{ctx.Locale.Tr "repo.settings.protect_required_approvals_desc"}}</p>
|
||||
</div>
|
||||
<div class="grouped fields">
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input name="enable_approvals_whitelist" type="checkbox" class="toggle-target-enabled" data-target="#approvals_whitelist_box" {{if .Rule.EnableApprovalsWhitelist}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_approvals_whitelist_enabled"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.protect_approvals_whitelist_enabled_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help tw-ml-0">{{ctx.Locale.Tr "repo.settings.protect_required_approvals_desc"}}</span>
|
||||
</label>
|
||||
<fieldset>
|
||||
<label>
|
||||
<input name="enable_approvals_whitelist" type="checkbox" class="toggle-target-enabled" data-target="#approvals_whitelist_box" {{if .Rule.EnableApprovalsWhitelist}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.protect_approvals_whitelist_enabled"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.protect_approvals_whitelist_enabled_desc"}}</span>
|
||||
</label>
|
||||
<div id="approvals_whitelist_box" class="grouped fields {{if not .Rule.EnableApprovalsWhitelist}}disabled{{end}}">
|
||||
<div class="checkbox-sub-item field">
|
||||
<label>{{ctx.Locale.Tr "repo.settings.protect_approvals_whitelist_users"}}</label>
|
||||
|
@ -141,14 +130,12 @@
|
|||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input id="dismiss_stale_approvals" name="dismiss_stale_approvals" type="checkbox" {{if .Rule.DismissStaleApprovals}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.dismiss_stale_approvals"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.dismiss_stale_approvals_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<label>
|
||||
<input id="dismiss_stale_approvals" name="dismiss_stale_approvals" type="checkbox" {{if .Rule.DismissStaleApprovals}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.dismiss_stale_approvals"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.dismiss_stale_approvals_desc"}}</span>
|
||||
</label>
|
||||
<div id="ignore_stale_approvals_box" class="field {{if .Rule.DismissStaleApprovals}}disabled{{end}}">
|
||||
<div class="ui checkbox">
|
||||
<input id="ignore_stale_approvals" name="ignore_stale_approvals" type="checkbox" {{if .Rule.IgnoreStaleApprovals}}checked{{end}}>
|
||||
|
@ -156,7 +143,7 @@
|
|||
<p class="help">{{ctx.Locale.Tr "repo.settings.ignore_stale_approvals_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grouped fields">
|
||||
<fieldset>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input name="enable_status_check" type="checkbox" class="toggle-target-enabled" data-target="#statuscheck_contexts_box" {{if .Rule.EnableStatusCheck}}checked{{end}}>
|
||||
|
@ -188,8 +175,10 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.event_pull_request_merge"}}</h5>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{ctx.Locale.Tr "repo.settings.event_pull_request_merge"}}</legend>
|
||||
<div class="grouped fields">
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
|
@ -239,41 +228,31 @@
|
|||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input name="block_on_rejected_reviews" type="checkbox" {{if .Rule.BlockOnRejectedReviews}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.block_rejected_reviews"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.block_rejected_reviews_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input name="block_on_official_review_requests" type="checkbox" {{if .Rule.BlockOnOfficialReviewRequests}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.block_on_official_review_requests"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.block_on_official_review_requests_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input name="block_on_outdated_branch" type="checkbox" {{if .Rule.BlockOnOutdatedBranch}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.block_outdated_branch"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.block_outdated_branch_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.event_pull_request_enforcement"}}</h5>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input name="apply_to_admins" type="checkbox" {{if .Rule.ApplyToAdmins}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.enforce_on_admins"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.enforce_on_admins_desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="field">
|
||||
<button class="ui primary button">{{ctx.Locale.Tr "repo.settings.protected_branch.save_rule"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<label>
|
||||
<input name="block_on_rejected_reviews" type="checkbox" {{if .Rule.BlockOnRejectedReviews}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.block_rejected_reviews"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.block_rejected_reviews_desc"}}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input name="block_on_official_review_requests" type="checkbox" {{if .Rule.BlockOnOfficialReviewRequests}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.block_on_official_review_requests"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.block_on_official_review_requests_desc"}}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input name="block_on_outdated_branch" type="checkbox" {{if .Rule.BlockOnOutdatedBranch}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.block_outdated_branch"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.block_outdated_branch_desc"}}</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{ctx.Locale.Tr "repo.settings.event_pull_request_enforcement"}}</legend>
|
||||
<label>
|
||||
<input name="apply_to_admins" type="checkbox" {{if .Rule.ApplyToAdmins}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.enforce_on_admins"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.enforce_on_admins_desc"}}</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
<button class="ui primary button">{{ctx.Locale.Tr "repo.settings.protected_branch.save_rule"}}</button>
|
||||
</form>
|
||||
</div>
|
||||
{{template "repo/settings/layout_footer" .}}
|
||||
|
|
|
@ -1,26 +1,20 @@
|
|||
{{$isNew:=or .PageIsSettingsHooksNew .PageIsAdminDefaultHooksNew .PageIsAdminSystemHooksNew}}
|
||||
<div class="field">
|
||||
<h4>{{ctx.Locale.Tr "repo.settings.event_desc"}}</h4>
|
||||
<div class="grouped event type fields">
|
||||
<div class="field">
|
||||
<div class="ui radio non-events checkbox">
|
||||
<input name="events" type="radio" value="push_only" {{if or $isNew .Webhook.PushOnly}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.event_push_only"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio non-events checkbox">
|
||||
<input name="events" type="radio" value="send_everything" {{if .Webhook.SendEverything}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.event_send_everything"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio events checkbox">
|
||||
<input name="events" type="radio" value="choose_events" {{if .Webhook.ChooseEvents}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.event_choose"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="event type">
|
||||
<legend>{{ctx.Locale.Tr "repo.settings.event_desc"}}</legend>
|
||||
<label class="non-events">
|
||||
<input name="events" type="radio" value="push_only" {{if or $isNew .Webhook.PushOnly}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.event_push_only"}}
|
||||
</label>
|
||||
<label class="non-events">
|
||||
<input name="events" type="radio" value="send_everything" {{if .Webhook.SendEverything}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.event_send_everything"}}
|
||||
</label>
|
||||
<label class="events">
|
||||
<input name="events" type="radio" value="choose_events" {{if .Webhook.ChooseEvents}}checked{{end}}>
|
||||
{{ctx.Locale.Tr "repo.settings.event_choose"}}
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<div class="events fields ui grid {{if not .Webhook.ChooseEvents}}tw-hidden{{end}}">
|
||||
<!-- Repository Events -->
|
||||
|
@ -270,20 +264,18 @@
|
|||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<fieldset>
|
||||
<label>
|
||||
<input name="active" type="checkbox" {{if or $isNew .Webhook.IsActive}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "repo.settings.active"}}</label>
|
||||
{{ctx.Locale.Tr "repo.settings.active"}}
|
||||
<span class="help">{{ctx.Locale.Tr "repo.settings.active_helper"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
</label>
|
||||
{{if $isNew}}
|
||||
<button class="ui primary button">{{ctx.Locale.Tr "repo.settings.add_webhook"}}</button>
|
||||
{{else}}
|
||||
<button class="ui primary button">{{ctx.Locale.Tr "repo.settings.update_webhook"}}</button>
|
||||
<a class="ui red delete-button button" data-url="{{.BaseLink}}/delete" data-id="{{.Webhook.ID}}">{{ctx.Locale.Tr "repo.settings.delete_webhook"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{template "repo/settings/webhook/delete_modal" .}}
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
// @ts-check
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, login_user, load_logged_in_context} from './utils_e2e.js';
|
||||
import {test, login_user, login} from './utils_e2e.js';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
|
||||
async function login({browser}, workerInfo) {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
return await context.newPage();
|
||||
}
|
||||
|
||||
// belongs to test: Pull: Toggle WIP
|
||||
const prTitle = 'pull5';
|
||||
|
||||
|
|
25
tests/e2e/org-settings.test.e2e.js
Normal file
25
tests/e2e/org-settings.test.e2e.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
// @ts-check
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, login_user, login} from './utils_e2e.js';
|
||||
import {validate_form} from './shared/forms.js';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
|
||||
test('org team settings', async ({browser}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name === 'Mobile Safari', 'Cannot get it to work - as usual');
|
||||
const page = await login({browser}, workerInfo);
|
||||
const response = await page.goto('/org/org3/teams/team1/edit');
|
||||
await expect(response?.status()).toBe(200);
|
||||
|
||||
await page.locator('input[name="permission"][value="admin"]').click();
|
||||
await expect(page.locator('.team-units')).toBeHidden();
|
||||
|
||||
// we are validating the form here, because the now hidden part has accessibility issues anyway
|
||||
// this should be moved up or down once they are fixed.
|
||||
await validate_form({page});
|
||||
|
||||
await page.locator('input[name="permission"][value="read"]').click();
|
||||
await expect(page.locator('.team-units')).toBeVisible();
|
||||
});
|
37
tests/e2e/repo-settings.test.e2e.js
Normal file
37
tests/e2e/repo-settings.test.e2e.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
// @ts-check
|
||||
import {expect} from '@playwright/test';
|
||||
import {test, login_user, login} from './utils_e2e.js';
|
||||
import {validate_form} from './shared/forms.js';
|
||||
|
||||
test.beforeAll(async ({browser}, workerInfo) => {
|
||||
await login_user(browser, workerInfo, 'user2');
|
||||
});
|
||||
|
||||
test('repo webhook settings', async ({browser}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name === 'Mobile Safari', 'Cannot get it to work - as usual');
|
||||
const page = await login({browser}, workerInfo);
|
||||
const response = await page.goto('/user2/repo1/settings/hooks/forgejo/new');
|
||||
await expect(response?.status()).toBe(200);
|
||||
|
||||
await page.locator('input[name="events"][value="choose_events"]').click();
|
||||
await expect(page.locator('.events.fields')).toBeVisible();
|
||||
|
||||
await page.locator('input[name="events"][value="push_only"]').click();
|
||||
await expect(page.locator('.events.fields')).toBeHidden();
|
||||
await page.locator('input[name="events"][value="send_everything"]').click();
|
||||
await expect(page.locator('.events.fields')).toBeHidden();
|
||||
|
||||
// restrict to improved semantic HTML, the rest of the page fails the accessibility check
|
||||
// only execute when the ugly part is hidden - would benefit from refactoring, too
|
||||
await validate_form({page}, 'fieldset');
|
||||
});
|
||||
|
||||
test('repo branch protection settings', async ({browser}, workerInfo) => {
|
||||
test.skip(workerInfo.project.name === 'Mobile Safari', 'Cannot get it to work - as usual');
|
||||
const page = await login({browser}, workerInfo);
|
||||
const response = await page.goto('/user2/repo1/settings/branches/edit');
|
||||
await expect(response?.status()).toBe(200);
|
||||
|
||||
// not yet accessible :(
|
||||
// await validate_form({page}, 'fieldset');
|
||||
});
|
16
tests/e2e/shared/forms.js
Normal file
16
tests/e2e/shared/forms.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import {expect} from '@playwright/test';
|
||||
import AxeBuilder from '@axe-core/playwright';
|
||||
|
||||
export async function validate_form({page}, scope) {
|
||||
scope ??= 'form';
|
||||
const accessibilityScanResults = await new AxeBuilder({page}).include(scope).analyze();
|
||||
expect(accessibilityScanResults.violations).toEqual([]);
|
||||
|
||||
// assert CSS properties that needed to be overriden for forms (ensure they remain active)
|
||||
const boxes = page.getByRole('checkbox').or(page.getByRole('radio'));
|
||||
for (const b of await boxes.all()) {
|
||||
await expect(b).toHaveCSS('margin-left', '0px');
|
||||
await expect(b).toHaveCSS('margin-top', '0px');
|
||||
await expect(b).toHaveCSS('vertical-align', 'baseline');
|
||||
}
|
||||
}
|
|
@ -58,6 +58,11 @@ export async function load_logged_in_context(browser, workerInfo, user) {
|
|||
return context;
|
||||
}
|
||||
|
||||
export async function login({browser}, workerInfo) {
|
||||
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||
return await context.newPage();
|
||||
}
|
||||
|
||||
export async function save_visual(page) {
|
||||
// Optionally include visual testing
|
||||
if (process.env.VISUAL_TEST) {
|
||||
|
|
|
@ -1,3 +1,33 @@
|
|||
fieldset {
|
||||
margin: 0.5em 0 1em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
fieldset legend {
|
||||
font-weight: var(--font-weight-medium);
|
||||
margin-bottom: 0.75em;
|
||||
}
|
||||
|
||||
fieldset label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
form fieldset label .help {
|
||||
font-weight: var(--font-weight-normal);
|
||||
display: block !important; /* overrides another rule in this file, remove when obsolete */
|
||||
}
|
||||
|
||||
fieldset input[type="checkbox"],
|
||||
fieldset input[type="radio"] {
|
||||
margin-right: 0.75em;
|
||||
vertical-align: initial !important; /* overrides a semantic.css rule, remove when obsolete */
|
||||
}
|
||||
|
||||
fieldset label:has(input[type="text"]),
|
||||
fieldset label:has(input[type="number"]) {
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.ui.input textarea,
|
||||
.ui.form textarea,
|
||||
.ui.form input:not([type]),
|
||||
|
@ -98,8 +128,7 @@ textarea:focus,
|
|||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.ui.form .required.fields:not(.grouped) > .field > label::after,
|
||||
.ui.form .required.fields.grouped > label::after,
|
||||
.ui.form .required.fields > .field > label::after,
|
||||
.ui.form .required.field > label::after,
|
||||
.ui.form label.required::after {
|
||||
color: var(--color-red);
|
||||
|
|
|
@ -6,7 +6,7 @@ export function initCompWebHookEditor() {
|
|||
return;
|
||||
}
|
||||
|
||||
for (const input of document.querySelectorAll('.events.checkbox input')) {
|
||||
for (const input of document.querySelectorAll('label.events input')) {
|
||||
input.addEventListener('change', function () {
|
||||
if (this.checked) {
|
||||
showElem('.events.fields');
|
||||
|
@ -14,7 +14,7 @@ export function initCompWebHookEditor() {
|
|||
});
|
||||
}
|
||||
|
||||
for (const input of document.querySelectorAll('.non-events.checkbox input')) {
|
||||
for (const input of document.querySelectorAll('label.non-events input')) {
|
||||
input.addEventListener('change', function () {
|
||||
if (this.checked) {
|
||||
hideElem('.events.fields');
|
||||
|
|
Loading…
Reference in a new issue