FIX: Add back missing API key 'peek' step (#30683)

In #30096 we converted the API keys UI to follow the new admin UI guidelines.

During this conversion, the step where you get a chance to copy the API key after creating, was lost due to a rebase mistake.

This re-introduces it.
This commit is contained in:
Ted Johansson 2025-01-10 10:21:22 +08:00 committed by GitHub
parent f4b417462b
commit b1bae9b785
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 179 additions and 146 deletions

View File

@ -24,6 +24,8 @@ export default class AdminConfigAreasApiKeysNew extends Component {
@tracked loadingScopes = false;
@tracked scopes = null;
@tracked generatedApiKey = null;
userModes = [
{ id: "all", name: i18n("admin.api.all_users") },
{ id: "single", name: i18n("admin.api.single_user") },
@ -93,8 +95,8 @@ export default class AdminConfigAreasApiKeysNew extends Component {
}
try {
await this.store.createRecord("api-key").save(payload);
this.router.transitionTo("adminApiKeys");
const result = await this.store.createRecord("api-key").save(payload);
this.generatedApiKey = result.payload.key;
} catch (error) {
popupAjaxError(error);
}
@ -148,169 +150,183 @@ export default class AdminConfigAreasApiKeysNew extends Component {
<template>
<BackButton @route="adminApiKeys.index" @label="admin.api_keys.back" />
<div class="admin-config-area user-field">
<div class="admin-config-area">
<div class="admin-config-area__primary-content">
<div class="admin-config-area-card">
<ConditionalLoadingSection @isLoading={{this.loadingScopes}}>
<Form
@onSubmit={{this.save}}
@data={{this.formData}}
as |form transientData|
>
<form.Field
@name="description"
@title={{i18n "admin.api.description"}}
@format="large"
@validation="required"
as |field|
{{#if this.generatedApiKey}}
<div>{{i18n "admin.api.not_shown_again"}}</div>
<div class="generated-api-key">{{this.generatedApiKey}}</div>
<DButton
@route="adminApiKeys.index"
@label="admin.api_keys.continue"
class="continue btn-danger"
/>
{{else}}
<ConditionalLoadingSection @isLoading={{this.loadingScopes}}>
<Form
@onSubmit={{this.save}}
@data={{this.formData}}
as |form transientData|
>
<field.Input />
</form.Field>
<form.Field
@name="user_mode"
@title={{i18n "admin.api.user_mode"}}
@format="large"
@validation="required"
as |field|
>
<field.Select as |select|>
{{#each this.userModes as |userMode|}}
<select.Option
@value={{userMode.id}}
>{{userMode.name}}</select.Option>
{{/each}}
</field.Select>
</form.Field>
{{#if (eq transientData.user_mode "single")}}
<form.Field
@name="user"
@title={{i18n "admin.api.user"}}
@name="description"
@title={{i18n "admin.api.description"}}
@format="large"
@validation="required"
as |field|
>
<field.Custom>
<EmailGroupUserChooser
@value={{this.username}}
@onChange={{fn this.updateUsername field}}
@options={{hash
maximum=1
filterPlaceholder="admin.api.user_placeholder"
}}
/>
</field.Custom>
<field.Input />
</form.Field>
{{/if}}
<form.Field
@name="scope_mode"
@title={{i18n "admin.api.scope_mode"}}
@format="large"
@validation="required"
as |field|
>
<field.Select as |select|>
{{#each this.scopeModes as |scopeMode|}}
<select.Option
@value={{scopeMode.id}}
>{{scopeMode.name}}</select.Option>
{{/each}}
</field.Select>
</form.Field>
<form.Field
@name="user_mode"
@title={{i18n "admin.api.user_mode"}}
@format="large"
@validation="required"
as |field|
>
<field.Select as |select|>
{{#each this.userModes as |userMode|}}
<select.Option
@value={{userMode.id}}
>{{userMode.name}}</select.Option>
{{/each}}
</field.Select>
</form.Field>
{{#if (eq transientData.scope_mode "granular")}}
<h2 class="scopes-title">{{i18n "admin.api.scopes.title"}}</h2>
<p>{{i18n "admin.api.scopes.description"}}</p>
<table class="scopes-table grid">
<thead>
<tr>
<td></td>
<td></td>
<td>{{i18n "admin.api.scopes.allowed_urls"}}</td>
<td>{{i18n
"admin.api.scopes.optional_allowed_parameters"
}}</td>
</tr>
</thead>
<tbody>
<form.Object @name="scopes" as |scopesObject scopeName|>
<tr class="scope-resource-name">
<td><b>{{scopeName}}</b></td>
<td></td>
{{#if (eq transientData.user_mode "single")}}
<form.Field
@name="user"
@title={{i18n "admin.api.user"}}
@format="large"
@validation="required"
as |field|
>
<field.Custom>
<EmailGroupUserChooser
@value={{this.username}}
@onChange={{fn this.updateUsername field}}
@options={{hash
maximum=1
filterPlaceholder="admin.api.user_placeholder"
}}
/>
</field.Custom>
</form.Field>
{{/if}}
<form.Field
@name="scope_mode"
@title={{i18n "admin.api.scope_mode"}}
@format="large"
@validation="required"
as |field|
>
<field.Select as |select|>
{{#each this.scopeModes as |scopeMode|}}
<select.Option
@value={{scopeMode.id}}
>{{scopeMode.name}}</select.Option>
{{/each}}
</field.Select>
</form.Field>
{{#if (eq transientData.scope_mode "granular")}}
<h2 class="scopes-title">{{i18n
"admin.api.scopes.title"
}}</h2>
<p>{{i18n "admin.api.scopes.description"}}</p>
<table class="scopes-table grid">
<thead>
<tr>
<td></td>
<td></td>
<td>{{i18n "admin.api.scopes.allowed_urls"}}</td>
<td>{{i18n
"admin.api.scopes.optional_allowed_parameters"
}}</td>
</tr>
</thead>
<tbody>
<form.Object @name="scopes" as |scopesObject scopeName|>
<tr class="scope-resource-name">
<td><b>{{scopeName}}</b></td>
<td></td>
<td></td>
<td></td>
</tr>
<scopesObject.Collection
@name={{scopeName}}
@tagName="tr"
as |topicsCollection index collectionData|
>
<td>
<topicsCollection.Field
@name="enabled"
@title={{collectionData.key}}
@showTitle={{false}}
as |field|
>
<field.Checkbox />
</topicsCollection.Field>
</td>
<td>
<div class="scope-name">{{collectionData.name}}</div>
<DTooltip
@icon="circle-question"
@content={{i18n
(concat
"admin.api.scopes.descriptions."
scopeName
"."
collectionData.key
)
class="scope-tooltip"
}}
/>
</td>
<td>
<DButton
@icon="link"
@action={{fn this.showURLs collectionData.urls}}
class="btn-info"
/>
</td>
<td>
<topicsCollection.Object
@name="params"
as |paramsObject name|
>
<paramsObject.Field
@name={{name}}
@title={{name}}
<scopesObject.Collection
@name={{scopeName}}
@tagName="tr"
as |topicsCollection index collectionData|
>
<td>
<topicsCollection.Field
@name="enabled"
@title={{collectionData.key}}
@showTitle={{false}}
as |field|
>
<field.Input placeholder={{name}} />
</paramsObject.Field>
</topicsCollection.Object>
</td>
</scopesObject.Collection>
</form.Object>
</tbody>
</table>
{{/if}}
<field.Checkbox />
</topicsCollection.Field>
</td>
<td>
<div
class="scope-name"
>{{collectionData.name}}</div>
<DTooltip
@icon="circle-question"
@content={{i18n
(concat
"admin.api.scopes.descriptions."
scopeName
"."
collectionData.key
)
class="scope-tooltip"
}}
/>
</td>
<td>
<DButton
@icon="link"
@action={{fn this.showURLs collectionData.urls}}
class="btn-info"
/>
</td>
<td>
<topicsCollection.Object
@name="params"
as |paramsObject name|
>
<paramsObject.Field
@name={{name}}
@title={{name}}
@showTitle={{false}}
as |field|
>
<field.Input placeholder={{name}} />
</paramsObject.Field>
</topicsCollection.Object>
</td>
</scopesObject.Collection>
</form.Object>
</tbody>
</table>
{{/if}}
<form.Actions>
<form.Submit class="save" @label="admin.api_keys.save" />
<form.Button
@route="adminApiKeys.index"
@label="admin.api_keys.cancel"
class="btn-default"
/>
</form.Actions>
</Form>
</ConditionalLoadingSection>
<form.Actions>
<form.Submit class="save" @label="admin.api_keys.save" />
<form.Button
@route="adminApiKeys.index"
@label="admin.api_keys.cancel"
class="btn-default"
/>
</form.Actions>
</Form>
</ConditionalLoadingSection>
{{/if}}
</div>
</div>
</div>

View File

@ -100,6 +100,10 @@
}
}
.generated-api-key {
margin: 1em 0;
}
.api-key {
padding: 10px;
margin-bottom: 10px;

View File

@ -5403,6 +5403,7 @@ en:
edit: "Edit"
save: "Save"
cancel: "Cancel"
continue: "Continue"
back: "Back to API keys"
revoke: "Revoke"
undo_revoke: "Undo revoke"

View File

@ -22,6 +22,10 @@ describe "Admin API Keys Page", type: :system do
api_keys_page.visit_page
api_keys_page.add_api_key(description: "Second Integration")
expect(api_keys_page).to have_generated_api_key
api_keys_page.click_continue
expect(api_keys_page).to have_api_key_listed("Second Integration")
end

View File

@ -26,6 +26,10 @@ module PageObjects
page.has_no_css?(table_selector, text: name)
end
def has_generated_api_key?
page.has_css?(".generated-api-key")
end
def add_api_key(description:)
page.find(header_actions_selector, text: I18n.t("admin_js.admin.api_keys.add")).click
@ -34,6 +38,10 @@ module PageObjects
form.find(".save").click
end
def click_continue
page.find("button", text: I18n.t("admin_js.admin.api_keys.continue")).click
end
def click_edit(description)
row = page.find(row_selector, text: description)
row.find("button", text: I18n.t("admin_js.admin.api_keys.edit")).click