d2d7c0a762
Add PATCH /users/{username}/tokens/{id} API endpoint and web UI edit
button so token scopes can be modified after creation without having
to delete and recreate the token.
187 lines
7.8 KiB
Handlebars
187 lines
7.8 KiB
Handlebars
{{template "user/settings/layout_head" (dict "pageClass" "user settings applications")}}
|
|
<div class="user-setting-content">
|
|
<h4 class="ui top attached header">
|
|
{{ctx.Locale.Tr "settings.manage_access_token"}}
|
|
</h4>
|
|
<div class="ui attached segment">
|
|
<div class="flex-divided-list items-with-main">
|
|
<div class="item">
|
|
{{ctx.Locale.Tr "settings.tokens_desc"}}
|
|
</div>
|
|
{{range .Tokens}}
|
|
<div class="item">
|
|
<div class="item-leading">
|
|
<span class="{{if .HasRecentActivity}}tw-text-green{{end}}" {{if .HasRecentActivity}}data-tooltip-content="{{ctx.Locale.Tr "settings.token_state_desc"}}"{{end}}>
|
|
{{svg "fontawesome-send" 32}}
|
|
</span>
|
|
</div>
|
|
<div class="item-main">
|
|
<details>
|
|
<summary><span class="item-title">{{.Name}}</span></summary>
|
|
<p class="tw-my-1">
|
|
{{ctx.Locale.Tr "settings.repo_and_org_access"}}:
|
|
{{if .DisplayPublicOnly}}
|
|
{{ctx.Locale.Tr "settings.permissions_public_only"}}
|
|
{{else}}
|
|
{{ctx.Locale.Tr "settings.permissions_access_all"}}
|
|
{{end}}
|
|
</p>
|
|
<p class="tw-my-1">{{ctx.Locale.Tr "settings.permissions_list"}}</p>
|
|
<ul class="tw-my-1">
|
|
{{range .Scope.StringSlice}}
|
|
{{if (ne . $.AccessTokenScopePublicOnly)}}
|
|
<li>{{.}}</li>
|
|
{{end}}
|
|
{{end}}
|
|
</ul>
|
|
</details>
|
|
<div class="item-body">
|
|
<i>{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="tw-text-green"{{end}}>{{DateUtils.AbsoluteShort .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</i>
|
|
</div>
|
|
</div>
|
|
<div class="item-trailing">
|
|
<button class="ui primary tiny button edit-token-button" data-modal-id="edit-token" data-id="{{.ID}}" data-scopes="{{StringUtils.Join (.Scope.StringSlice) ","}}">
|
|
{{svg "octicon-pencil"}}
|
|
{{ctx.Locale.Tr "edit"}}
|
|
</button>
|
|
<button class="ui red tiny button delete-button" data-modal-id="delete-token" data-url="{{$.Link}}/delete" data-id="{{.ID}}">
|
|
{{svg "octicon-trash"}}
|
|
{{ctx.Locale.Tr "settings.delete_token"}}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
<div class="ui bottom attached segment">
|
|
<details {{if or .name (not .Tokens)}}open{{end}}>
|
|
<summary><h4 class="ui header tw-inline-block tw-my-2">{{ctx.Locale.Tr "settings.generate_new_token"}}</h4></summary>
|
|
<form class="ui form ignore-dirty" action="{{.Link}}" method="post">
|
|
<div class="field {{if .Err_Name}}error{{end}}">
|
|
<label for="name">{{ctx.Locale.Tr "settings.token_name"}}</label>
|
|
<input id="name" name="name" value="{{.name}}" required maxlength="255">
|
|
</div>
|
|
<div class="field">
|
|
<div class="tw-my-2">{{ctx.Locale.Tr "settings.repo_and_org_access"}}</div>
|
|
<label class="gt-checkbox">
|
|
<input type="radio" name="scope-public-only" value="{{$.AccessTokenScopePublicOnly}}"> {{ctx.Locale.Tr "settings.permissions_public_only"}}
|
|
</label>
|
|
<label class="gt-checkbox">
|
|
<input type="radio" name="scope-public-only" value="" checked> {{ctx.Locale.Tr "settings.permissions_access_all"}}
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<div class="tw-my-2">{{ctx.Locale.Tr "settings.access_token_desc" (HTMLFormat `href="%s/api/swagger" target="_blank"` AppSubUrl) (HTMLFormat `href="%s" target="_blank"` "{{HelpURL}}/development/oauth2-provider#scopes")}}</div>
|
|
<table class="ui table unstackable tw-my-2">
|
|
{{range $category := .TokenCategories}}
|
|
<tr>
|
|
<td>{{$category}}</td>
|
|
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="" checked> {{ctx.Locale.Tr "settings.permission_no_access"}}</label></td>
|
|
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="read:{{$category}}"> {{ctx.Locale.Tr "settings.permission_read"}}</label></td>
|
|
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="write:{{$category}}"> {{ctx.Locale.Tr "settings.permission_write"}}</label></td>
|
|
</tr>
|
|
{{end}}
|
|
</table>
|
|
</div>
|
|
<button class="ui primary button">
|
|
{{ctx.Locale.Tr "settings.generate_token"}}
|
|
</button>
|
|
</form>
|
|
</details>
|
|
</div>
|
|
|
|
{{if .EnableOAuth2}}
|
|
{{template "user/settings/grants_oauth2" .}}
|
|
{{template "user/settings/applications_oauth2" .}}
|
|
{{end}}
|
|
</div>
|
|
|
|
<div class="ui modal" id="edit-token">
|
|
<div class="header">
|
|
{{svg "octicon-pencil"}}
|
|
{{ctx.Locale.Tr "settings.edit_token_scopes"}}
|
|
</div>
|
|
<div class="content">
|
|
<form class="ui form" id="edit-token-form" action="{{.Link}}/edit" method="post">
|
|
{{.CsrfTokenHtml}}
|
|
<input type="hidden" name="id" value="">
|
|
<div class="field">
|
|
<div class="tw-my-2">{{ctx.Locale.Tr "settings.repo_and_org_access"}}</div>
|
|
<label class="gt-checkbox">
|
|
<input type="radio" name="scope-public-only" value="{{$.AccessTokenScopePublicOnly}}"> {{ctx.Locale.Tr "settings.permissions_public_only"}}
|
|
</label>
|
|
<label class="gt-checkbox">
|
|
<input type="radio" name="scope-public-only" value="" checked> {{ctx.Locale.Tr "settings.permissions_access_all"}}
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<div class="tw-my-2">{{ctx.Locale.Tr "settings.permissions_list"}}</div>
|
|
<table class="ui table unstackable tw-my-2">
|
|
{{range $category := .TokenCategories}}
|
|
<tr>
|
|
<td>{{$category}}</td>
|
|
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="" checked> {{ctx.Locale.Tr "settings.permission_no_access"}}</label></td>
|
|
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="read:{{$category}}"> {{ctx.Locale.Tr "settings.permission_read"}}</label></td>
|
|
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="write:{{$category}}"> {{ctx.Locale.Tr "settings.permission_write"}}</label></td>
|
|
</tr>
|
|
{{end}}
|
|
</table>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="actions">
|
|
<button class="ui cancel button">{{ctx.Locale.Tr "cancel"}}</button>
|
|
<button class="ui primary button" id="edit-token-submit">{{ctx.Locale.Tr "save"}}</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
for (const btn of document.querySelectorAll('.edit-token-button')) {
|
|
btn.addEventListener('click', (e) => {
|
|
const modal = document.getElementById('edit-token');
|
|
const form = document.getElementById('edit-token-form');
|
|
const id = e.currentTarget.getAttribute('data-id');
|
|
const scopes = (e.currentTarget.getAttribute('data-scopes') || '').split(',').filter(Boolean);
|
|
|
|
form.querySelector('input[name="id"]').value = id;
|
|
|
|
// Reset all radios to defaults
|
|
for (const radio of form.querySelectorAll('input[type="radio"]')) {
|
|
radio.checked = radio.value === '';
|
|
}
|
|
|
|
// Set current scopes
|
|
for (const scope of scopes) {
|
|
if (scope === 'public-only') {
|
|
const radio = form.querySelector('input[name="scope-public-only"][value="public-only"]');
|
|
if (radio) radio.checked = true;
|
|
} else {
|
|
const radio = form.querySelector(`input[name="scope-${scope.split(':')[1]}"][value="${scope}"]`);
|
|
if (radio) radio.checked = true;
|
|
}
|
|
}
|
|
|
|
$(modal).modal('show');
|
|
});
|
|
}
|
|
|
|
document.getElementById('edit-token-submit')?.addEventListener('click', () => {
|
|
document.getElementById('edit-token-form')?.submit();
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<div class="ui g-modal-confirm delete modal" id="delete-token">
|
|
<div class="header">
|
|
{{svg "octicon-trash"}}
|
|
{{ctx.Locale.Tr "settings.access_token_deletion"}}
|
|
</div>
|
|
<div class="content">
|
|
<p>{{ctx.Locale.Tr "settings.access_token_deletion_desc"}}</p>
|
|
</div>
|
|
{{template "base/modal_actions_confirm"}}
|
|
</div>
|
|
|
|
{{template "user/settings/layout_footer" .}}
|