Feature #5953 » 5953-v3.patch
app/assets/stylesheets/application.css | ||
---|---|---|
2541 | 2541 |
padding: 0.5rem; |
2542 | 2542 |
width: calc(200px - 0.5rem * 2); |
2543 | 2543 |
} |
2544 | ||
2545 |
.api-key-actions { |
|
2546 |
display: flex; |
|
2547 |
justify-content: space-between; |
|
2548 |
align-items: center; |
|
2549 |
} |
|
2550 | ||
2551 |
.api-key-actions .copy-api-key-link { |
|
2552 |
padding: 4px 6px; |
|
2553 |
cursor: pointer; |
|
2554 |
} |
|
2555 | ||
2556 |
#sidebar .api-key-actions .copy-api-key-link svg { |
|
2557 |
opacity: 1; |
|
2558 |
} |
app/javascript/controllers/api_key_copy_controller.js | ||
---|---|---|
1 |
import { Controller } from "@hotwired/stimulus"; |
|
2 | ||
3 |
export default class extends Controller { |
|
4 |
static targets = ["apiKey"]; |
|
5 | ||
6 |
copy(event) { |
|
7 |
event.preventDefault(); |
|
8 | ||
9 |
const apiKeyText = this.apiKeyTarget.textContent?.trim(); |
|
10 |
if (!apiKeyText) return; |
|
11 | ||
12 |
const svgIcon = event.target.closest('.copy-api-key-link').querySelector('svg') |
|
13 |
if (!svgIcon) return; |
|
14 | ||
15 |
copyToClipboard(apiKeyText).then(() => { |
|
16 |
updateSVGIcon(svgIcon, 'checked'); |
|
17 |
setTimeout(() => { |
|
18 |
updateSVGIcon(svgIcon, 'copy'); |
|
19 |
}, 2000); |
|
20 |
}); |
|
21 |
} |
|
22 |
} |
app/views/my/_sidebar.html.erb | ||
---|---|---|
20 | 20 | |
21 | 21 |
<% if Setting.rest_api_enabled? %> |
22 | 22 |
<h4><%= l(:label_api_access_key) %></h4> |
23 |
<div> |
|
24 |
<%= link_to l(:button_show), my_api_key_path, :remote => true %> |
|
25 |
<pre id='api-access-key' class='autoscroll'></pre> |
|
23 |
<div data-controller="api-key-copy"> |
|
24 |
<div class="api-key-actions"> |
|
25 |
<%= link_to l(:button_show), my_api_key_path, :remote => true %> |
|
26 |
<a class="copy-api-key-link icon icon-only" |
|
27 |
title="<%= l(:button_copy) %>" |
|
28 |
aria-label="<%= l(:button_copy) %>" |
|
29 |
href="#" |
|
30 |
role="button" |
|
31 |
tabindex="0" |
|
32 |
style="display: none;" |
|
33 |
data-action="click->api-key-copy#copy"> |
|
34 |
<%= sprite_icon('copy') %> |
|
35 |
</a> |
|
36 |
</div> |
|
37 |
<pre id='api-access-key' class='autoscroll' data-api-key-copy-target="apiKey"></pre> |
|
38 |
<%= javascript_tag("$('#api-access-key').hide();") %> |
|
39 |
<p> |
|
40 |
<% if @user.api_token %> |
|
41 |
<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %> |
|
42 |
<% else %> |
|
43 |
<%= l(:label_missing_api_access_key) %> |
|
44 |
<% end %> |
|
45 |
(<%= link_to l(:button_reset), my_api_key_path, :method => :post %>) |
|
46 |
</p> |
|
26 | 47 |
</div> |
27 |
<%= javascript_tag("$('#api-access-key').hide();") %> |
|
28 |
<p> |
|
29 |
<% if @user.api_token %> |
|
30 |
<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %> |
|
31 |
<% else %> |
|
32 |
<%= l(:label_missing_api_access_key) %> |
|
33 |
<% end %> |
|
34 |
(<%= link_to l(:button_reset), my_api_key_path, :method => :post %>) |
|
35 |
</p> |
|
36 | 48 |
<% end %> |
app/views/my/show_api_key.js.erb | ||
---|---|---|
1 | 1 |
$('#api-access-key').html('<%= escape_javascript @user.api_key %>').toggle(); |
2 | ||
3 |
if ($('#api-access-key').is(':visible')) { |
|
4 |
$('.api-key-actions .copy-api-key-link').show(); |
|
5 |
} else { |
|
6 |
$('.api-key-actions .copy-api-key-link').hide(); |
|
7 |
} |
test/system/api_key_copy_test.rb | ||
---|---|---|
1 |
# frozen_string_literal: true |
|
2 | ||
3 |
require_relative '../application_system_test_case' |
|
4 | ||
5 |
class ApiKeyCopySystemTest < ApplicationSystemTestCase |
|
6 |
def test_api_key_copy_to_clipboard |
|
7 |
with_settings :rest_api_enabled => '1' do |
|
8 |
log_user('jsmith', 'jsmith') |
|
9 | ||
10 |
user = User.find_by_login('jsmith') |
|
11 |
expected_value = user.api_key |
|
12 | ||
13 |
visit '/my/account' |
|
14 |
click_link 'Show' |
|
15 | ||
16 |
assert_selector '#api-access-key', visible: true |
|
17 |
assert_selector '.api-key-actions .copy-api-key-link', visible: true |
|
18 |
assert_equal expected_value, find('#api-access-key').text.strip |
|
19 | ||
20 |
find('.copy-api-key-link').click |
|
21 | ||
22 |
find('#quick-search input').set('') |
|
23 |
find('#quick-search input').send_keys([modifier_key, 'v']) |
|
24 |
assert_equal expected_value, find('#quick-search input').value |
|
25 |
end |
|
26 |
end |
|
27 | ||
28 |
private |
|
29 | ||
30 |
def modifier_key |
|
31 |
modifier = osx? ? 'command' : 'control' |
|
32 |
modifier.to_sym |
|
33 |
end |
|
34 |
end |
- « Previous
- 1
- …
- 3
- 4
- 5
- Next »