mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 22:43:30 +03:00
2b961df4cb
no issue - Adds new regenerate button for refreshing custom integration's admin and content api keys - Adds new regenerate button for refreshing internal Zapier integration's admin key - Regenerates content or admin API key after confirmation and shows user new key
274 lines
15 KiB
Handlebars
274 lines
15 KiB
Handlebars
<section class="gh-canvas">
|
|
<form class="mb15" {{action (perform "save") on="submit"}}>
|
|
<GhCanvasHeader class="gh-canvas-header">
|
|
<h2 class="gh-canvas-title" data-test-screen-title>
|
|
<LinkTo @route="settings.integrations" data-test-link="integrations-back">Integrations</LinkTo>
|
|
<span>{{svg-jar "arrow-right"}}</span>
|
|
{{this.integration.name}}
|
|
</h2>
|
|
<section class="view-actions">
|
|
<GhTaskButton @task={{this.saveIntegration}} @class="gh-btn gh-btn-blue gh-btn-icon" @autoReset={{true}} data-test-button="save" />
|
|
</section>
|
|
</GhCanvasHeader>
|
|
|
|
<h4 class="midlightgrey f-small fw5 ttu">Configuration</h4>
|
|
<div class="pa5 pt3 pb3 br4 shadow-1 bg-grouped-table mt2">
|
|
<div class="flex">
|
|
<div class="flex flex-column items-start">
|
|
<label class="mb1">Icon</label>
|
|
<figure class="relative flex items-center h-100 ma0 br4 hide-child ba b--whitegrey-d2 pa8 bg-white" style={{this.iconImageStyle}}>
|
|
<AspectRatioBox @class="flex items-center h-100 justify-center" @ratio="1/1" @base="height">
|
|
{{#unless this.integration.iconImage}}
|
|
{{svg-jar "integration" class="w11 h11"}}
|
|
{{/unless}}
|
|
</AspectRatioBox>
|
|
|
|
<GhUploader
|
|
@extensions={{this.imageExtensions}}
|
|
@onComplete={{action "setIconImage"}}
|
|
as |uploader|
|
|
>
|
|
{{#if uploader.isUploading}}
|
|
<div class="absolute top-0 left-0 w-100 h-100 br4 bg-black-70 flex items-center">
|
|
{{uploader.progressBar}}
|
|
</div>
|
|
{{else}}
|
|
<button
|
|
type="button"
|
|
class="child absolute top-0 left-0 w-100 h-100 br4 b white text-center bg-black-70 f8"
|
|
{{action "triggerIconFileDialog"}}
|
|
>
|
|
Upload
|
|
</button>
|
|
{{/if}}
|
|
<div style="display:none">
|
|
<GhFileInput
|
|
@name="iconImage"
|
|
@multiple={{false}}
|
|
@action={{uploader.setFiles}}
|
|
@accept={{this.imageMimeTypes}} data-test-file-input="icon" />
|
|
</div>
|
|
</GhUploader>
|
|
</figure>
|
|
</div>
|
|
<div class="flex-auto ml6">
|
|
<GhValidationStatusContainer
|
|
@class="flex flex-column w-100 mr3"
|
|
@errors={{this.integration.errors}}
|
|
@hasValidated={{this.integration.hasValidated}}
|
|
@property="name"
|
|
>
|
|
<label for="integration_name">Name</label>
|
|
<GhTextInput
|
|
@id="integration_name"
|
|
@class="gh-input mt1 mb1"
|
|
@type="text"
|
|
@value={{readonly this.integration.name}}
|
|
@input={{action (mut this.integration.name) value="target.value"}}
|
|
@focus-out={{action "validate" "name" target=this.integration}}
|
|
data-test-input="name"
|
|
/>
|
|
<GhErrorMessage @errors={{this.integration.errors}} @property="name" data-test-error="name" class="ma0" />
|
|
</GhValidationStatusContainer>
|
|
|
|
<GhValidationStatusContainer
|
|
@class="flex flex-column w-100 mr3"
|
|
@errors={{this.integration.errors}}
|
|
@hasValidated={{this.integration.hasValidated}}
|
|
@property="decription"
|
|
>
|
|
<label for="integration_description" class="mt3">Description</label>
|
|
<GhTextInput
|
|
@id="integration_description"
|
|
@class="gh-input mt1"
|
|
@type="text"
|
|
@value={{readonly this.integration.description}}
|
|
@input={{action (mut this.integration.description) value="target.value"}}
|
|
@focus-out={{action "validate" "description" target=this.integration}}
|
|
data-test-input="description"
|
|
/>
|
|
<GhErrorMessage @errors={{this.integration.errors}} @property="description" data-test-error="description" class="ma0" />
|
|
</GhValidationStatusContainer>
|
|
</div>
|
|
</div>
|
|
<table class="ma0 mt5" style="table-layout: fixed">
|
|
<tbody>
|
|
<tr>
|
|
<td class="pa3 pl0 fw7 f8 w35 v-top">Content API Key</td>
|
|
<td class="pa0 truncate bb b--lightgrey">
|
|
<div class="pt3 pb3 relative truncate flex items-center {{unless this.copyContentKey.isRunning "hide-child-instant"}}">
|
|
<span class="midlightgrey" data-test-text="content-key">
|
|
{{this.integration.contentKey.secret}}
|
|
</span>
|
|
<div class="absolute top-2 right-0 flex items-stretch child">
|
|
<button type="button" {{action "confirmRegenerateKeyModal" this.integration.contentKey}} class="ba b--lightgrey-d1 br3 pa1 pl2 pr2 flex items-center mr2">
|
|
{{svg-jar "reload" class="w4 h4 stroke-midgrey"}}
|
|
</button>
|
|
<button type="button" {{action (perform this.copyContentKey)}} class="bg-black-70 f8 pa1 pr3 pl3 br3 white fw4 flex items-center">
|
|
{{#if this.copyContentKey.isRunning}}
|
|
{{svg-jar "check-circle" class="w3 v-mid mr2 stroke-white"}} Copied
|
|
{{else}}
|
|
Copy
|
|
{{/if}}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{{#if (eq this.regeneratedKeyType this.integration.contentKey.type)}}
|
|
<div class="green nt3 mb2"> Content API Key was successfully regenerated </div>
|
|
{{/if}}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="pa3 pl0 w50 fw7 f8 w35 v-top">Admin API Key</td>
|
|
<td class="pa0 truncate bb b--lightgrey">
|
|
<div class="pt3 pb3 relative truncate flex items-center {{unless this.copyAdminKey.isRunning "hide-child-instant"}}">
|
|
<span class="midlightgrey" data-test-text="admin-key">
|
|
{{this.integration.adminKey.secret}}
|
|
</span>
|
|
<div class="absolute top-2 right-0 flex items-stretch child">
|
|
<button type="button" {{action "confirmRegenerateKeyModal" this.integration.adminKey}} class="ba b--lightgrey-d1 br3 pa1 pl2 pr2 flex items-center mr2">
|
|
{{svg-jar "reload" class="w4 h4 stroke-midgrey"}}
|
|
</button>
|
|
<button type="button" {{action (perform this.copyAdminKey)}} class="bg-black-70 f8 pa1 pr3 pl3 br3 white fw4 flex items-center">
|
|
{{#if this.copyAdminKey.isRunning}}
|
|
{{svg-jar "check-circle" class="w3 v-mid mr2 stroke-white"}} Copied
|
|
{{else}}
|
|
Copy
|
|
{{/if}}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{{#if (eq this.regeneratedKeyType this.integration.adminKey.type)}}
|
|
<div class="green nt3 mb2"> Admin API Key was successfully regenerated </div>
|
|
{{/if}}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="pa3 pl0 w50 fw7 f8 w35">API URL</td>
|
|
<td class="pa0 truncate">
|
|
<div class="pt3 pb3 relative truncate {{unless this.copyApiUrl.isRunning "hide-child-instant"}}">
|
|
<span class="midlightgrey" data-test-text="api-url">
|
|
{{this.apiUrl}}
|
|
</span>
|
|
<div class="absolute top-1 right-0">
|
|
<div class="pt1 pr3 pb1 pl3 bg-black-70 child br3 f8 nudge-top--4 nudge-right--1">
|
|
<button type="button" {{action (perform this.copyApiUrl)}} class="white fw4 flex items-center">
|
|
{{#if this.copyApiUrl.isRunning}}
|
|
{{svg-jar "check-circle" class="w3 v-mid mr2 stroke-white"}} Copied
|
|
{{else}}
|
|
Copy
|
|
{{/if}}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</form>
|
|
|
|
<h4 class="mt15 midlightgrey f-small fw5 ttu">Webhooks</h4>
|
|
<div class="mt2">
|
|
<table class="ma0 w-100 bg-grouped-table shadow-1 br3">
|
|
<thead>
|
|
<tr>
|
|
<th class="pa2 pl3 midlightgrey ttu fw4 f-small br3 br--top br--left fw5">Name</th>
|
|
<th class="pa2 pl3 midlightgrey ttu fw4 f-small br3 fw5">Event</th>
|
|
<th class="pa2 pl3 midlightgrey ttu fw4 f-small br3 fw5">URL</th>
|
|
<th class="pa2 pl3 midlightgrey ttu fw4 f-small br3 fw5">Last triggered</th>
|
|
<th class="pa2 pl3 ttu br3 br--top br--right"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{#each this.filteredWebhooks as |webhook|}}
|
|
<tr class="hide-child bt b--whitegrey f7" data-test-webhook-row="{{webhook.id}}">
|
|
<td class="pa2 pl3" data-test-text="name">{{webhook.name}}</td>
|
|
<td class="pa2 pl3" data-test-text="event">{{event-name webhook.event}}</td>
|
|
<td class="pa2 pl3" data-test-text="targetUrl">{{webhook.targetUrl}}</td>
|
|
<td class="pa2 pl3" data-test-text="last-triggered">{{or webhook.lastTriggeredAtUTC "Not triggered"}}</td>
|
|
<td class="w1 pa2 pl3 nowrap">
|
|
<div class="child flex items-center">
|
|
<LinkTo @route="settings.integration.webhooks.edit" @models={{array this.integration webhook}} data-test-link="edit-webhook">
|
|
{{svg-jar "pen" class="w6 h6 fill-midgrey pa1 mr1"}}
|
|
</LinkTo>
|
|
<button {{action "confirmWebhookDeletion" webhook}} data-test-button="delete-webhook">
|
|
{{svg-jar "trash" class="w6 fill-red pa1"}}
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{{else}}
|
|
<tr class="bt b--whitegrey" data-test-webhooks-blank-slate>
|
|
<td colspan="5" class="pa5 pt15 pb15 tc midgrey f7">
|
|
<div class="flex flex-column items-center">
|
|
<p class="ma0 pa0 tc midgrey lh-title mt2">
|
|
No webhooks configured
|
|
</p>
|
|
<LinkTo @route="settings.integration.webhooks.new" @model={{this.integration}} @classNames="flex items-center" data-test-link="add-webhook">
|
|
<div class="flex items-center pa2 pt1">
|
|
{{svg-jar "add" class="w3 h3 fill-blue-d1"}}
|
|
<span class="ml1 blue">Add webhook</span>
|
|
</div>
|
|
</LinkTo>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{{/each}}
|
|
</tbody>
|
|
{{#if this.filteredWebhooks}}
|
|
<tfoot class="bt b--lightgrey">
|
|
<tr class="new-webhook-cell">
|
|
<td colspan="5">
|
|
<LinkTo @route="settings.integration.webhooks.new" @model={{this.integration}} @classNames="flex items-center" data-test-link="add-webhook">
|
|
<div class="pa3 f7">
|
|
{{svg-jar "add" class="w3 h3 fill-blue-d1"}}
|
|
<span class="ml1 blue">Add webhook</span>
|
|
</div>
|
|
</LinkTo>
|
|
</td>
|
|
</tr>
|
|
</tfoot>
|
|
{{/if}}
|
|
</table>
|
|
</div>
|
|
<button class="gh-btn gh-btn-red gh-btn-icon mb15 mt15" {{action "confirmIntegrationDeletion"}}>
|
|
<span> Delete Integration </span>
|
|
</button>
|
|
</section>
|
|
|
|
{{#if this.showUnsavedChangesModal}}
|
|
<GhFullscreenModal @modal="leave-settings"
|
|
@confirm={{action "leaveScreen"}}
|
|
@close={{action "toggleUnsavedChangesModal"}}
|
|
@modifier="action wide" />
|
|
{{/if}}
|
|
|
|
{{#if this.showRegenerateKeyModal}}
|
|
<GhFullscreenModal @modal="regenerate-key"
|
|
@model={{hash
|
|
apiKey=this.selectedApiKey
|
|
integration=this.integration
|
|
}}
|
|
@confirm={{action "regenerateKey"}}
|
|
@close={{action "cancelRegenerateKeyModal"}}
|
|
@modifier="action wide" />
|
|
{{/if}}
|
|
|
|
{{#if this.showDeleteIntegrationModal}}
|
|
<GhFullscreenModal @modal="delete-integration"
|
|
@confirm={{action "deleteIntegration"}}
|
|
@close={{action "cancelIntegrationDeletion"}}
|
|
@modifier="action wide" />
|
|
{{/if}}
|
|
|
|
{{#if this.webhookToDelete}}
|
|
<GhFullscreenModal @modal="delete-webhook"
|
|
@confirm={{action "deleteWebhook"}}
|
|
@close={{action "cancelWebhookDeletion"}}
|
|
@modifier="action wide" />
|
|
{{/if}}
|
|
|
|
{{outlet}}
|