mirror of
https://github.com/redmine/redmine.git
synced 2025-10-26 07:46:17 +01:00
Adds button to copy API access key to clipboard.
Patch by Mizuki ISHIKAWA (user:ishikawa999). git-svn-id: https://svn.redmine.org/redmine/trunk@23991 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -2547,3 +2547,18 @@ th[role=columnheader]:not(.no-sort):hover:after {
|
|||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
width: calc(200px - 0.5rem * 2);
|
width: calc(200px - 0.5rem * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.api-key-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-key-actions .copy-api-key-link {
|
||||||
|
padding: 4px 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar .api-key-actions .copy-api-key-link svg {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|||||||
22
app/javascript/controllers/api_key_copy_controller.js
Normal file
22
app/javascript/controllers/api_key_copy_controller.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { Controller } from "@hotwired/stimulus";
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = ["apiKey"];
|
||||||
|
|
||||||
|
copy(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const apiKeyText = this.apiKeyTarget.textContent?.trim();
|
||||||
|
if (!apiKeyText) return;
|
||||||
|
|
||||||
|
const svgIcon = event.target.closest('.copy-api-key-link').querySelector('svg')
|
||||||
|
if (!svgIcon) return;
|
||||||
|
|
||||||
|
copyToClipboard(apiKeyText).then(() => {
|
||||||
|
updateSVGIcon(svgIcon, 'checked');
|
||||||
|
setTimeout(() => {
|
||||||
|
updateSVGIcon(svgIcon, 'copy');
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,17 +20,29 @@
|
|||||||
|
|
||||||
<% if Setting.rest_api_enabled? %>
|
<% if Setting.rest_api_enabled? %>
|
||||||
<h4><%= l(:label_api_access_key) %></h4>
|
<h4><%= l(:label_api_access_key) %></h4>
|
||||||
<div>
|
<div data-controller="api-key-copy">
|
||||||
|
<div class="api-key-actions">
|
||||||
<%= link_to l(:button_show), my_api_key_path, :remote => true %>
|
<%= link_to l(:button_show), my_api_key_path, :remote => true %>
|
||||||
<pre id='api-access-key' class='autoscroll'></pre>
|
<a class="copy-api-key-link icon icon-only"
|
||||||
|
title="<%= l(:button_copy) %>"
|
||||||
|
aria-label="<%= l(:button_copy) %>"
|
||||||
|
href="#"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
style="display: none;"
|
||||||
|
data-action="click->api-key-copy#copy">
|
||||||
|
<%= sprite_icon('copy') %>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<pre id='api-access-key' class='autoscroll' data-api-key-copy-target="apiKey"></pre>
|
||||||
|
<%= javascript_tag("$('#api-access-key').hide();") %>
|
||||||
|
<p>
|
||||||
|
<% if @user.api_token %>
|
||||||
|
<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %>
|
||||||
|
<% else %>
|
||||||
|
<%= l(:label_missing_api_access_key) %>
|
||||||
|
<% end %>
|
||||||
|
(<%= link_to l(:button_reset), my_api_key_path, :method => :post %>)
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<%= javascript_tag("$('#api-access-key').hide();") %>
|
|
||||||
<p>
|
|
||||||
<% if @user.api_token %>
|
|
||||||
<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %>
|
|
||||||
<% else %>
|
|
||||||
<%= l(:label_missing_api_access_key) %>
|
|
||||||
<% end %>
|
|
||||||
(<%= link_to l(:button_reset), my_api_key_path, :method => :post %>)
|
|
||||||
</p>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1 +1,7 @@
|
|||||||
$('#api-access-key').html('<%= escape_javascript @user.api_key %>').toggle();
|
$('#api-access-key').html('<%= escape_javascript @user.api_key %>').toggle();
|
||||||
|
|
||||||
|
if ($('#api-access-key').is(':visible')) {
|
||||||
|
$('.api-key-actions .copy-api-key-link').show();
|
||||||
|
} else {
|
||||||
|
$('.api-key-actions .copy-api-key-link').hide();
|
||||||
|
}
|
||||||
|
|||||||
34
test/system/api_key_copy_test.rb
Normal file
34
test/system/api_key_copy_test.rb
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../application_system_test_case'
|
||||||
|
|
||||||
|
class ApiKeyCopySystemTest < ApplicationSystemTestCase
|
||||||
|
def test_api_key_copy_to_clipboard
|
||||||
|
with_settings :rest_api_enabled => '1' do
|
||||||
|
log_user('jsmith', 'jsmith')
|
||||||
|
|
||||||
|
user = User.find_by_login('jsmith')
|
||||||
|
expected_value = user.api_key
|
||||||
|
|
||||||
|
visit '/my/account'
|
||||||
|
click_link 'Show'
|
||||||
|
|
||||||
|
assert_selector '#api-access-key', visible: true
|
||||||
|
assert_selector '.api-key-actions .copy-api-key-link', visible: true
|
||||||
|
assert_equal expected_value, find('#api-access-key').text.strip
|
||||||
|
|
||||||
|
find('.copy-api-key-link').click
|
||||||
|
|
||||||
|
find('#quick-search input').set('')
|
||||||
|
find('#quick-search input').send_keys([modifier_key, 'v'])
|
||||||
|
assert_equal expected_value, find('#quick-search input').value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def modifier_key
|
||||||
|
modifier = osx? ? 'command' : 'control'
|
||||||
|
modifier.to_sym
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user