mirror of
https://github.com/go-gitea/gitea.git
synced 2026-02-12 15:26:58 +01:00
Re-implement changes for feedback
This commit is contained in:
parent
7df7f72a71
commit
4ccb766bf2
@ -176,6 +176,8 @@ const (
|
||||
ActionsTokenPermissionModePermissive ActionsTokenPermissionMode = "permissive"
|
||||
// ActionsTokenPermissionModeRestricted - read access by default
|
||||
ActionsTokenPermissionModeRestricted ActionsTokenPermissionMode = "restricted"
|
||||
// ActionsTokenPermissionModeCustom - custom permissions defined by MaxTokenPermissions
|
||||
ActionsTokenPermissionModeCustom ActionsTokenPermissionMode = "custom"
|
||||
)
|
||||
|
||||
// ActionsTokenPermissions defines the permissions for different repository units
|
||||
@ -272,6 +274,10 @@ type ActionsConfig struct {
|
||||
MaxTokenPermissions *ActionsTokenPermissions `json:"max_token_permissions,omitempty"`
|
||||
// AllowCrossRepoAccess indicates if actions in this repo/org can access other repos in the same org
|
||||
AllowCrossRepoAccess bool `json:"allow_cross_repo_access,omitempty"`
|
||||
// AllowedCrossRepoIDs is a list of specific repo IDs that can be accessed cross-repo (empty means all if AllowCrossRepoAccess is true)
|
||||
AllowedCrossRepoIDs []int64 `json:"allowed_cross_repo_ids,omitempty"`
|
||||
// FollowOrgConfig indicates if this repository should follow the organization-level configuration
|
||||
FollowOrgConfig bool `json:"follow_org_config,omitempty"`
|
||||
}
|
||||
|
||||
func (cfg *ActionsConfig) EnableWorkflow(file string) {
|
||||
@ -361,6 +367,20 @@ func (cfg *ActionsConfig) ClampPermissions(perms ActionsTokenPermissions) Action
|
||||
}
|
||||
}
|
||||
|
||||
// IsRepoAllowedCrossAccess checks if a specific repo is allowed for cross-repo access
|
||||
// Returns true if AllowCrossRepoAccess is enabled AND (AllowedCrossRepoIDs is empty OR repoID is in the list)
|
||||
func (cfg *ActionsConfig) IsRepoAllowedCrossAccess(repoID int64) bool {
|
||||
if !cfg.AllowCrossRepoAccess {
|
||||
return false
|
||||
}
|
||||
// If no specific repos are configured, allow all
|
||||
if len(cfg.AllowedCrossRepoIDs) == 0 {
|
||||
return true
|
||||
}
|
||||
// Check if repo is in the allowed list
|
||||
return slices.Contains(cfg.AllowedCrossRepoIDs, repoID)
|
||||
}
|
||||
|
||||
// FromDB fills up a ActionsConfig from serialized format.
|
||||
func (cfg *ActionsConfig) FromDB(bs []byte) error {
|
||||
return json.UnmarshalHandleDoubleEncode(bs, &cfg)
|
||||
|
||||
@ -3740,8 +3740,12 @@
|
||||
"actions.general.token_permissions.none": "None",
|
||||
"actions.general.token_permissions.cross_repo": "Allow Cross-Repository Access",
|
||||
"actions.general.token_permissions.cross_repo_desc": "Control whether the token can access other repositories and packages within this organization.",
|
||||
"actions.general.token_permissions.cross_repo_all": "All repositories in this organization",
|
||||
"actions.general.token_permissions.cross_repo_selected": "Selected repositories only",
|
||||
"actions.general.token_permissions.allowed_repos": "Allowed Repositories",
|
||||
"actions.general.token_permissions.add_repo": "Add Repository",
|
||||
"actions.general.token_permissions.follow_org": "Follow organization-level configuration",
|
||||
"actions.general.token_permissions.follow_org_desc": "Use the Actions settings configured at the organization level instead of repository-specific settings.",
|
||||
"all_repositories": "All Repositories",
|
||||
"specific_repositories": "Specific Repositories"
|
||||
}
|
||||
|
||||
@ -105,21 +105,26 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
|
||||
packageRepoID = ctx.Package.Descriptor.Package.RepoID
|
||||
}
|
||||
|
||||
// If package is not linked to any repo (org-level package), deny access from Actions
|
||||
// Actions tokens should only access packages linked to repos
|
||||
if packageRepoID == 0 {
|
||||
ctx.HTTPError(http.StatusForbidden, "reqPackageAccess", "Actions tokens cannot access packages not linked to a repository")
|
||||
return
|
||||
}
|
||||
|
||||
if task.RepoID != packageRepoID {
|
||||
// Cross-repository access - check org policy first
|
||||
// Cross-repository access - check org policy
|
||||
cfg, err := actions_model.GetOrgActionsConfig(ctx, ctx.Package.Owner.ID)
|
||||
if err != nil {
|
||||
log.Error("GetOrgActionsConfig: %v", err)
|
||||
ctx.HTTPError(http.StatusInternalServerError, "GetOrgActionsConfig", err.Error())
|
||||
return
|
||||
}
|
||||
if !cfg.AllowCrossRepoAccess {
|
||||
ctx.HTTPError(http.StatusForbidden, "reqPackageAccess", "cross-repository package access is disabled")
|
||||
// Use selective cross-repo access check
|
||||
if !cfg.IsRepoAllowedCrossAccess(packageRepoID) {
|
||||
ctx.HTTPError(http.StatusForbidden, "reqPackageAccess", "cross-repository package access is not allowed for this repository")
|
||||
return
|
||||
}
|
||||
|
||||
// Cross-repo is enabled. For org-level packages (RepoID=0), allow access.
|
||||
// For repo-linked packages, allow read access (fallthrough to permission check below).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,9 +33,11 @@ func ActionsGeneral(ctx *context.Context) {
|
||||
ctx.Data["TokenPermissionMode"] = actionsCfg.GetTokenPermissionMode()
|
||||
ctx.Data["TokenPermissionModePermissive"] = repo_model.ActionsTokenPermissionModePermissive
|
||||
ctx.Data["TokenPermissionModeRestricted"] = repo_model.ActionsTokenPermissionModeRestricted
|
||||
ctx.Data["TokenPermissionModeCustom"] = repo_model.ActionsTokenPermissionModeCustom
|
||||
ctx.Data["MaxTokenPermissions"] = actionsCfg.GetMaxTokenPermissions()
|
||||
|
||||
ctx.Data["AllowCrossRepoAccess"] = actionsCfg.AllowCrossRepoAccess
|
||||
ctx.Data["HasSelectedRepos"] = len(actionsCfg.AllowedCrossRepoIDs) > 0
|
||||
|
||||
ctx.HTML(http.StatusOK, tplSettingsActionsGeneral)
|
||||
}
|
||||
@ -55,7 +57,8 @@ func ActionsGeneralPost(ctx *context.Context) {
|
||||
// Update Token Permission Mode
|
||||
permissionMode := repo_model.ActionsTokenPermissionMode(ctx.FormString("token_permission_mode"))
|
||||
if permissionMode == repo_model.ActionsTokenPermissionModeRestricted ||
|
||||
permissionMode == repo_model.ActionsTokenPermissionModePermissive {
|
||||
permissionMode == repo_model.ActionsTokenPermissionModePermissive ||
|
||||
permissionMode == repo_model.ActionsTokenPermissionModeCustom {
|
||||
actionsCfg.TokenPermissionMode = permissionMode
|
||||
}
|
||||
|
||||
@ -81,8 +84,19 @@ func ActionsGeneralPost(ctx *context.Context) {
|
||||
Wiki: parseMaxPerm("wiki"),
|
||||
}
|
||||
|
||||
// Update Cross-Repo Access
|
||||
actionsCfg.AllowCrossRepoAccess = ctx.FormBool("allow_cross_repo_access")
|
||||
// Update Cross-Repo Access Mode
|
||||
crossRepoMode := ctx.FormString("cross_repo_mode")
|
||||
switch crossRepoMode {
|
||||
case "none":
|
||||
actionsCfg.AllowCrossRepoAccess = false
|
||||
actionsCfg.AllowedCrossRepoIDs = nil
|
||||
case "all":
|
||||
actionsCfg.AllowCrossRepoAccess = true
|
||||
actionsCfg.AllowedCrossRepoIDs = nil
|
||||
case "selected":
|
||||
actionsCfg.AllowCrossRepoAccess = true
|
||||
// Keep existing AllowedCrossRepoIDs, will be updated by separate API
|
||||
}
|
||||
|
||||
if err := actions_model.SetOrgActionsConfig(ctx, ctx.Org.Organization.AsUser().ID, actionsCfg); err != nil {
|
||||
ctx.ServerError("SetOrgActionsConfig", err)
|
||||
|
||||
@ -41,8 +41,13 @@ func ActionsGeneralSettings(ctx *context.Context) {
|
||||
ctx.Data["TokenPermissionMode"] = actionsCfg.GetTokenPermissionMode()
|
||||
ctx.Data["TokenPermissionModePermissive"] = repo_model.ActionsTokenPermissionModePermissive
|
||||
ctx.Data["TokenPermissionModeRestricted"] = repo_model.ActionsTokenPermissionModeRestricted
|
||||
ctx.Data["TokenPermissionModeCustom"] = repo_model.ActionsTokenPermissionModeCustom
|
||||
ctx.Data["MaxTokenPermissions"] = actionsCfg.GetMaxTokenPermissions()
|
||||
|
||||
// Follow org config (only for repos in orgs)
|
||||
ctx.Data["IsInOrg"] = ctx.Repo.Repository.Owner.IsOrganization()
|
||||
ctx.Data["FollowOrgConfig"] = actionsCfg.FollowOrgConfig
|
||||
|
||||
if ctx.Repo.Repository.IsPrivate {
|
||||
collaborativeOwnerIDs := actionsCfg.CollaborativeOwnerIDs
|
||||
collaborativeOwners, err := user_model.GetUsersByIDs(ctx, collaborativeOwnerIDs)
|
||||
@ -141,15 +146,21 @@ func UpdateTokenPermissions(ctx *context.Context) {
|
||||
|
||||
actionsCfg := actionsUnit.ActionsConfig()
|
||||
|
||||
// Update permission mode
|
||||
permissionMode := repo_model.ActionsTokenPermissionMode(ctx.FormString("token_permission_mode"))
|
||||
if permissionMode == repo_model.ActionsTokenPermissionModeRestricted ||
|
||||
permissionMode == repo_model.ActionsTokenPermissionModePermissive {
|
||||
actionsCfg.TokenPermissionMode = permissionMode
|
||||
} else {
|
||||
ctx.Flash.Error("Invalid token permission mode")
|
||||
ctx.Redirect(redirectURL)
|
||||
return
|
||||
// Update Follow Org Config (for repos in orgs)
|
||||
actionsCfg.FollowOrgConfig = ctx.FormBool("follow_org_config")
|
||||
|
||||
// Update permission mode (only if not following org config)
|
||||
if !actionsCfg.FollowOrgConfig {
|
||||
permissionMode := repo_model.ActionsTokenPermissionMode(ctx.FormString("token_permission_mode"))
|
||||
if permissionMode == repo_model.ActionsTokenPermissionModeRestricted ||
|
||||
permissionMode == repo_model.ActionsTokenPermissionModePermissive ||
|
||||
permissionMode == repo_model.ActionsTokenPermissionModeCustom {
|
||||
actionsCfg.TokenPermissionMode = permissionMode
|
||||
} else {
|
||||
ctx.Flash.Error("Invalid token permission mode")
|
||||
ctx.Redirect(redirectURL)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Update Maximum Permissions (radio buttons: none/read/write)
|
||||
|
||||
@ -8,12 +8,30 @@
|
||||
{{.CsrfTokenHtml}}
|
||||
|
||||
<!-- Cross-Repository Access -->
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="allow_cross_repo_access" {{if .AllowCrossRepoAccess}}checked{{end}}>
|
||||
<label><strong>{{ctx.Locale.Tr "actions.general.token_permissions.cross_repo"}}</strong></label>
|
||||
<h5 class="ui header">
|
||||
{{ctx.Locale.Tr "actions.general.token_permissions.cross_repo"}}
|
||||
</h5>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.cross_repo_desc"}}</p>
|
||||
|
||||
<div class="grouped fields">
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="cross_repo_mode" value="none" {{if not .AllowCrossRepoAccess}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "settings.disabled"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="cross_repo_mode" value="all" {{if and .AllowCrossRepoAccess (not .HasSelectedRepos)}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.cross_repo_all"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="cross_repo_mode" value="selected" {{if and .AllowCrossRepoAccess .HasSelectedRepos}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.cross_repo_selected"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.cross_repo_desc"}}</p>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
@ -25,29 +43,38 @@
|
||||
<div class="grouped fields">
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="token_permission_mode" value="permissive" {{if eq .TokenPermissionMode .TokenPermissionModePermissive}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.permissive"}}</label>
|
||||
<input type="radio" name="token_permission_mode" value="permissive" {{if eq .TokenPermissionMode .TokenPermissionModePermissive}}checked{{end}} class="js-permission-mode-radio">
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.mode.permissive"}}</label>
|
||||
</div>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.permissive.description"}}</p>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.mode.permissive.desc"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="token_permission_mode" value="restricted" {{if eq .TokenPermissionMode .TokenPermissionModeRestricted}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.restricted"}}</label>
|
||||
<input type="radio" name="token_permission_mode" value="restricted" {{if eq .TokenPermissionMode .TokenPermissionModeRestricted}}checked{{end}} class="js-permission-mode-radio">
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.mode.restricted"}}</label>
|
||||
</div>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.restricted.description"}}</p>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.mode.restricted.desc"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="token_permission_mode" value="custom" {{if eq .TokenPermissionMode .TokenPermissionModeCustom}}checked{{end}} class="js-permission-mode-radio">
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.mode.custom"}}</label>
|
||||
</div>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.mode.custom.desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Maximum Permissions Table -->
|
||||
<h5 class="ui header">
|
||||
{{ctx.Locale.Tr "actions.general.token_permissions.maximum"}}
|
||||
</h5>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.maximum.description"}}</p>
|
||||
<div id="max-permissions-section">
|
||||
<h5 class="ui header">
|
||||
{{ctx.Locale.Tr "actions.general.token_permissions.max_permissions"}}
|
||||
</h5>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.max_permissions.desc"}}</p>
|
||||
</div>
|
||||
|
||||
<table class="ui celled table">
|
||||
<table class="ui celled table js-permissions-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40%">{{ctx.Locale.Tr "units.unit"}}</th>
|
||||
|
||||
@ -32,22 +32,42 @@
|
||||
<form class="ui form" action="{{.RepoLink}}/settings/actions/general/token_permissions" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
|
||||
<!-- Permission Mode Selection -->
|
||||
{{if .IsInOrg}}
|
||||
<!-- Follow Organization Configuration -->
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="follow_org_config" id="follow-org-config" {{if .FollowOrgConfig}}checked{{end}} class="js-follow-org-config">
|
||||
<label><strong>{{ctx.Locale.Tr "actions.general.token_permissions.follow_org"}}</strong></label>
|
||||
</div>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.follow_org_desc"}}</p>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
{{end}}
|
||||
|
||||
<!-- Permission Mode Selection -->
|
||||
<div class="field js-permission-mode-section">
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.mode"}}</label>
|
||||
<div class="grouped fields">
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="token_permission_mode" value="{{.TokenPermissionModePermissive}}" {{if eq .TokenPermissionMode .TokenPermissionModePermissive}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.permissive"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.permissive.description"}}</p>
|
||||
<input type="radio" name="token_permission_mode" value="{{.TokenPermissionModePermissive}}" {{if eq .TokenPermissionMode .TokenPermissionModePermissive}}checked{{end}} class="js-permission-mode-radio">
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.mode.permissive"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.mode.permissive.desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="token_permission_mode" value="{{.TokenPermissionModeRestricted}}" {{if eq .TokenPermissionMode .TokenPermissionModeRestricted}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.restricted"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.restricted.description"}}</p>
|
||||
<input type="radio" name="token_permission_mode" value="{{.TokenPermissionModeRestricted}}" {{if eq .TokenPermissionMode .TokenPermissionModeRestricted}}checked{{end}} class="js-permission-mode-radio">
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.mode.restricted"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.mode.restricted.desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" name="token_permission_mode" value="{{.TokenPermissionModeCustom}}" {{if eq .TokenPermissionMode .TokenPermissionModeCustom}}checked{{end}} class="js-permission-mode-radio">
|
||||
<label>{{ctx.Locale.Tr "actions.general.token_permissions.mode.custom"}}</label>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.mode.custom.desc"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -58,13 +78,15 @@
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Maximum Permissions Table -->
|
||||
<h5 class="ui header">
|
||||
{{ctx.Locale.Tr "actions.general.token_permissions.maximum"}}
|
||||
<span class="ui red text">*</span>
|
||||
</h5>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.maximum.description"}}</p>
|
||||
<div id="max-permissions-section">
|
||||
<h5 class="ui header">
|
||||
{{ctx.Locale.Tr "actions.general.token_permissions.maximum"}}
|
||||
<span class="ui red text">*</span>
|
||||
</h5>
|
||||
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.maximum.description"}}</p>
|
||||
</div>
|
||||
|
||||
<table class="ui celled table">
|
||||
<table class="ui celled table js-permissions-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40%">{{ctx.Locale.Tr "units.unit"}}</th>
|
||||
|
||||
@ -15,6 +15,7 @@ import (
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
org_model "code.gitea.io/gitea/models/organization"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
@ -376,17 +377,18 @@ func TestActionsCrossRepoAccess(t *testing.T) {
|
||||
uploadReq := NewRequestWithBody(t, "PUT", packageURL, bytes.NewReader(content)).AddBasicAuth("user2")
|
||||
MakeRequest(t, uploadReq, http.StatusCreated)
|
||||
|
||||
// Disable cross-repo access to test denied state
|
||||
require.NoError(t, actions_model.SetOrgActionsConfig(t.Context(), org.ID, &repo_model.ActionsConfig{
|
||||
AllowCrossRepoAccess: false,
|
||||
}))
|
||||
// Link the package to repo-B (per reviewer feedback: packages must be linked to repos)
|
||||
pkg, err := packages_model.GetPackageByName(t.Context(), org.ID, packages_model.TypeGeneric, packageName)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, packages_model.SetRepositoryLink(t.Context(), pkg.ID, repoBID))
|
||||
|
||||
// By default, cross-repo is disabled
|
||||
// Try to download with cross-repo disabled - should fail
|
||||
downloadReqDenied := NewRequest(t, "GET", packageURL)
|
||||
downloadReqDenied.Header.Set("Authorization", "Bearer "+task.Token)
|
||||
MakeRequest(t, downloadReqDenied, http.StatusForbidden)
|
||||
|
||||
// Re-enable cross-repo access
|
||||
// Enable cross-repo access
|
||||
require.NoError(t, actions_model.SetOrgActionsConfig(t.Context(), org.ID, &repo_model.ActionsConfig{
|
||||
AllowCrossRepoAccess: true,
|
||||
}))
|
||||
|
||||
46
web_src/js/features/repo-settings-actions.ts
Normal file
46
web_src/js/features/repo-settings-actions.ts
Normal file
@ -0,0 +1,46 @@
|
||||
export function initActionsPermissionsTable(): void {
|
||||
const modeRadios = document.querySelectorAll<HTMLInputElement>('.js-permission-mode-radio');
|
||||
const permTable = document.querySelector<HTMLTableElement>('table.js-permissions-table');
|
||||
const tableSection = document.querySelector<HTMLElement>('#max-permissions-section');
|
||||
const followOrgCheckbox = document.querySelector<HTMLInputElement>('.js-follow-org-config');
|
||||
const modeSection = document.querySelector<HTMLElement>('.js-permission-mode-section');
|
||||
|
||||
if (!modeRadios.length) return;
|
||||
|
||||
function updateTableState(): void {
|
||||
const followOrg = followOrgCheckbox?.checked ?? false;
|
||||
const selectedMode = document.querySelector<HTMLInputElement>('input[name="token_permission_mode"]:checked');
|
||||
const isCustom = selectedMode?.value === 'custom';
|
||||
|
||||
// Disable entire form when following org config
|
||||
for (const radio of modeRadios) {
|
||||
radio.disabled = followOrg;
|
||||
}
|
||||
|
||||
if (modeSection) {
|
||||
modeSection.style.opacity = followOrg ? '0.5' : '1';
|
||||
}
|
||||
|
||||
// Disable table if not custom OR following org
|
||||
const tableDisabled = !isCustom || followOrg;
|
||||
if (permTable) {
|
||||
const inputs = permTable.querySelectorAll<HTMLInputElement>('input[type="radio"]');
|
||||
for (const input of inputs) {
|
||||
input.disabled = tableDisabled;
|
||||
}
|
||||
permTable.style.opacity = tableDisabled ? '0.5' : '1';
|
||||
}
|
||||
|
||||
if (tableSection) {
|
||||
tableSection.style.opacity = tableDisabled ? '0.5' : '1';
|
||||
}
|
||||
}
|
||||
|
||||
for (const radio of modeRadios) {
|
||||
radio.addEventListener('change', updateTableState);
|
||||
}
|
||||
|
||||
followOrgCheckbox?.addEventListener('change', updateTableState);
|
||||
|
||||
updateTableState();
|
||||
}
|
||||
@ -64,6 +64,7 @@ import {initGlobalButtonClickOnEnter, initGlobalButtons, initGlobalDeleteButton}
|
||||
import {initGlobalComboMarkdownEditor, initGlobalEnterQuickSubmit, initGlobalFormDirtyLeaveConfirm} from './features/common-form.ts';
|
||||
import {callInitFunctions} from './modules/init.ts';
|
||||
import {initRepoViewFileTree} from './features/repo-view-file-tree.ts';
|
||||
import {initActionsPermissionsTable} from './features/repo-settings-actions.ts';
|
||||
|
||||
const initStartTime = performance.now();
|
||||
const initPerformanceTracer = callInitFunctions([
|
||||
@ -158,6 +159,7 @@ const initPerformanceTracer = callInitFunctions([
|
||||
initOAuth2SettingsDisableCheckbox,
|
||||
|
||||
initRepoFileView,
|
||||
initActionsPermissionsTable,
|
||||
]);
|
||||
|
||||
// it must be the last one, then the "querySelectorAll" only needs to be executed once for global init functions.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user