diff --git a/app/assets/javascripts/admin/adapters/web-hook-event.js.es6 b/app/assets/javascripts/admin/adapters/web-hook-event.js.es6 new file mode 100644 index 0000000000..122070ce3e --- /dev/null +++ b/app/assets/javascripts/admin/adapters/web-hook-event.js.es6 @@ -0,0 +1,7 @@ +import RESTAdapter from 'discourse/adapters/rest'; + +export default RESTAdapter.extend({ + basePath() { + return '/admin/api/'; + } +}); diff --git a/app/assets/javascripts/admin/adapters/web-hook.js.es6 b/app/assets/javascripts/admin/adapters/web-hook.js.es6 new file mode 100644 index 0000000000..122070ce3e --- /dev/null +++ b/app/assets/javascripts/admin/adapters/web-hook.js.es6 @@ -0,0 +1,7 @@ +import RESTAdapter from 'discourse/adapters/rest'; + +export default RESTAdapter.extend({ + basePath() { + return '/admin/api/'; + } +}); diff --git a/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 b/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 index 3c27f644b7..264e827da6 100644 --- a/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 +++ b/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 @@ -26,14 +26,14 @@ export default Ember.Component.extend({ @computed('model.duration') completion(duration) { const seconds = Math.floor(duration / 10.0) / 100.0; - return I18n.t('admin.web_hooks.events.completion', { seconds }); + return I18n.t('admin.web_hooks.events.completed_in', { count: seconds }); }, actions: { redeliver() { return bootbox.confirm(I18n.t('admin.web_hooks.events.redeliver_confirm'), I18n.t('no_value'), I18n.t('yes_value'), result => { if (result) { - ajax(`/admin/web_hooks/${this.get('model.web_hook_id')}/events/${this.get('model.id')}/redeliver`, { type: 'POST' }).then(json => { + ajax(`/admin/api/web_hooks/${this.get('model.web_hook_id')}/events/${this.get('model.id')}/redeliver`, { type: 'POST' }).then(json => { this.set('model', json.web_hook_event); }).catch(popupAjaxError); } diff --git a/app/assets/javascripts/admin/controllers/admin-api.js.es6 b/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-api.js.es6 rename to app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 index 9b4cc91f5c..6ef4411702 100644 --- a/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 @@ -1,14 +1,65 @@ import { ajax } from 'discourse/lib/ajax'; import { popupAjaxError } from 'discourse/lib/ajax-error'; +import computed from 'ember-addons/ember-computed-decorators'; export default Ember.Controller.extend({ + pingDisabled: false, + incomingEventIds: [], + incomingCount: Ember.computed.alias("incomingEventIds.length"), + + @computed('incomingCount') + hasIncoming(incomingCount) { + return incomingCount > 0; + }, + + subscribe() { + this.messageBus.subscribe(`/web_hook_events/${this.get('model.extras.web_hook_id')}`, data => { + if (data.event_type === 'ping') { + this.set('pingDisabled', false); + } + this._addIncoming(data.web_hook_event_id); + }); + }, + + unsubscribe() { + this.messageBus.unsubscribe('/web_hook_events/*'); + }, + + _addIncoming(eventId) { + const incomingEventIds = this.get("incomingEventIds"); + + if (incomingEventIds.indexOf(eventId) === -1) { + incomingEventIds.pushObject(eventId); + } + }, + actions: { loadMore() { this.get('model').loadMore(); }, ping() { - ajax(`/admin/web_hooks/${this.get('model.extras.web_hook_id')}/ping`, {type: 'POST'}).catch(popupAjaxError); + this.set('pingDisabled', true); + + ajax(`/admin/api/web_hooks/${this.get('model.extras.web_hook_id')}/ping`, { + type: 'POST' + }).catch(error => { + this.set('pingDisabled', false); + popupAjaxError(error); + }); + }, + + showInserted() { + const webHookId = this.get('model.extras.web_hook_id'); + + ajax(`/admin/api/web_hooks/${webHookId}/events/bulk`, { + type: 'GET', + data: { ids: this.get('incomingEventIds') } + }).then(data => { + const objects = data.map(event => this.store.createRecord('web-hook-event', event)); + this.get("model").unshiftObjects(objects); + this.set("incomingEventIds", []); + }); } } }); diff --git a/app/assets/javascripts/admin/helpers/human-size.js.es6 b/app/assets/javascripts/admin/helpers/human-size.js.es6 index a43897c627..a50cfe5819 100644 --- a/app/assets/javascripts/admin/helpers/human-size.js.es6 +++ b/app/assets/javascripts/admin/helpers/human-size.js.es6 @@ -1,3 +1,3 @@ -import { htmlHelper } from 'discourse/lib/helpers'; +import { htmlHelper } from 'discourse-common/lib/helpers'; export default htmlHelper(size => I18n.toHumanSize(size)); diff --git a/app/assets/javascripts/admin/helpers/preserve-newlines.js.es6 b/app/assets/javascripts/admin/helpers/preserve-newlines.js.es6 index 73bac43379..b58e9a552c 100644 --- a/app/assets/javascripts/admin/helpers/preserve-newlines.js.es6 +++ b/app/assets/javascripts/admin/helpers/preserve-newlines.js.es6 @@ -1,4 +1,4 @@ -import { htmlHelper } from 'discourse/lib/helpers'; +import { htmlHelper } from 'discourse-common/lib/helpers'; import { escapeExpression } from 'discourse/lib/utilities'; export default htmlHelper(str => escapeExpression(str).replace(/\n/g, "
")); diff --git a/app/assets/javascripts/admin/helpers/value-at-tl.js.es6 b/app/assets/javascripts/admin/helpers/value-at-tl.js.es6 index aeac49e83d..48d2271cab 100644 --- a/app/assets/javascripts/admin/helpers/value-at-tl.js.es6 +++ b/app/assets/javascripts/admin/helpers/value-at-tl.js.es6 @@ -1,4 +1,4 @@ -import { registerUnbound } from 'discourse/lib/helpers'; +import { registerUnbound } from 'discourse-common/lib/helpers'; registerUnbound('value-at-tl', function(data, params) { var tl = parseInt(params.level, 10); diff --git a/app/assets/javascripts/admin/models/api-key.js.es6 b/app/assets/javascripts/admin/models/api-key.js.es6 index aa05ce8341..2a7cf86778 100644 --- a/app/assets/javascripts/admin/models/api-key.js.es6 +++ b/app/assets/javascripts/admin/models/api-key.js.es6 @@ -52,7 +52,7 @@ ApiKey.reopenClass({ @returns {Promise} a promise that resolves to the array of `ApiKey` instances **/ find: function() { - return ajax("/admin/api").then(function(keys) { + return ajax("/admin/api/keys").then(function(keys) { return keys.map(function (key) { return ApiKey.create(key); }); diff --git a/app/assets/javascripts/admin/routes/admin-api-index.js.es6 b/app/assets/javascripts/admin/routes/admin-api-index.js.es6 new file mode 100644 index 0000000000..f41f6bb794 --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-api-index.js.es6 @@ -0,0 +1,5 @@ +export default Ember.Route.extend({ + beforeModel() { + this.transitionTo('adminApiKeys'); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-api.js.es6 b/app/assets/javascripts/admin/routes/admin-api-keys.js.es6 similarity index 100% rename from app/assets/javascripts/admin/routes/admin-api.js.es6 rename to app/assets/javascripts/admin/routes/admin-api-keys.js.es6 diff --git a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 index df27e2c07b..69b51e5cab 100644 --- a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 @@ -35,10 +35,14 @@ export default { this.route('edit', { path: '/:id' }); }); }); - this.route('api'); - this.resource('adminWebHooks', { path: '/web_hooks' }, function() { - this.route('show', { path: '/:web_hook_id' }); - this.route('showEvents', { path: '/:web_hook_id/events' }); + + this.resource('adminApi', { path: '/api' }, function() { + this.resource('adminApiKeys', { path: '/keys' }); + + this.resource('adminWebHooks', { path: '/web_hooks' }, function() { + this.route('show', { path: '/:web_hook_id' }); + this.route('showEvents', { path: '/:web_hook_id/events' }); + }); }); this.resource('admin.backups', { path: '/backups' }, function() { diff --git a/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 b/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 index ea4e33ac63..c9700db463 100644 --- a/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 @@ -5,9 +5,14 @@ export default Discourse.Route.extend({ setupController(controller, model) { controller.set('model', model); + controller.subscribe(); + }, + + deactivate() { + this.controllerFor('adminWebHooks.showEvents').unsubscribe(); }, renderTemplate() { - this.render('admin/templates/web-hooks-show-events', { into: 'admin' }); + this.render('admin/templates/web-hooks-show-events', { into: 'adminApi' }); } }); diff --git a/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 b/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 index 533d7c09fe..51b7d55d47 100644 --- a/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 @@ -21,6 +21,6 @@ export default Discourse.Route.extend({ }, renderTemplate() { - this.render('admin/templates/web-hooks-show', { into: 'admin' }); + this.render('admin/templates/web-hooks-show', { into: 'adminApi' }); } }); diff --git a/app/assets/javascripts/admin/templates/admin.hbs b/app/assets/javascripts/admin/templates/admin.hbs index 05076b7408..e29125aec3 100644 --- a/app/assets/javascripts/admin/templates/admin.hbs +++ b/app/assets/javascripts/admin/templates/admin.hbs @@ -19,8 +19,7 @@ {{nav-item route='adminLogs' label='admin.logs.title'}} {{#if currentUser.admin}} {{nav-item route='adminCustomize' label='admin.customize.title'}} - {{nav-item route='admin.api' label='admin.api.title'}} - {{nav-item route='adminWebHooks' label='admin.web_hooks.title'}} + {{nav-item route='adminApi' label='admin.api.title'}} {{nav-item route='admin.backups' label='admin.backups.title'}} {{/if}} {{nav-item route='adminPlugins' label='admin.plugins.title'}} diff --git a/app/assets/javascripts/admin/templates/api-keys.hbs b/app/assets/javascripts/admin/templates/api-keys.hbs new file mode 100644 index 0000000000..4123e57638 --- /dev/null +++ b/app/assets/javascripts/admin/templates/api-keys.hbs @@ -0,0 +1,34 @@ +{{#if model}} + + + + + + + {{#each model as |k|}} + + + + + + {{/each}} +
{{i18n 'admin.api.key'}}{{i18n 'admin.api.user'}} 
{{k.key}} + {{#if k.user}} + {{#link-to 'adminUser' k.user}} + {{avatar k.user imageSize="small"}} + {{/link-to}} + {{else}} + {{i18n 'admin.api.all_users'}} + {{/if}} + + {{d-button action="regenerateKey" actionParam=k icon="undo" label='admin.api.regenerate'}} + {{d-button action="revokeKey" actionParam=k icon="times" label='admin.api.revoke'}} +
+{{else}} +

{{i18n 'admin.api.none'}}

+{{/if}} + +{{#unless hasMasterKey}} + +{{/unless }} + diff --git a/app/assets/javascripts/admin/templates/api.hbs b/app/assets/javascripts/admin/templates/api.hbs index 0f2e65b89c..f3407fe0cc 100644 --- a/app/assets/javascripts/admin/templates/api.hbs +++ b/app/assets/javascripts/admin/templates/api.hbs @@ -1,33 +1,10 @@ -{{#if model}} - - - - - - - {{#each model as |k|}} - - - - - - {{/each}} -
{{i18n 'admin.api.key'}}{{i18n 'admin.api.user'}} 
{{k.key}} - {{#if k.user}} - {{#link-to 'adminUser' k.user}} - {{avatar k.user imageSize="small"}} - {{/link-to}} - {{else}} - {{i18n 'admin.api.all_users'}} - {{/if}} - - - -
-{{else}} -

{{i18n 'admin.api.none'}}

-{{/if}} +
+ {{#admin-nav}} + {{nav-item route='adminApiKeys' label='admin.api.title'}} + {{nav-item route='adminWebHooks' label='admin.web_hooks.title'}} + {{/admin-nav}} -{{#unless hasMasterKey}} - -{{/unless }} +
+ {{outlet}} +
+
diff --git a/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs b/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs index be4252c42d..026b6daae2 100644 --- a/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs @@ -1,4 +1,4 @@ -
+
{{model.status}}
{{model.id}}
diff --git a/app/assets/javascripts/admin/templates/group.hbs b/app/assets/javascripts/admin/templates/group.hbs index 1e7a90828c..6dfd5f6a56 100644 --- a/app/assets/javascripts/admin/templates/group.hbs +++ b/app/assets/javascripts/admin/templates/group.hbs @@ -119,6 +119,11 @@ {{text-field name="flair_color" class="flair_color" value=model.flair_color placeholderKey="admin.groups.flair_color_placeholder"}}
{{/if}} + +
+
+ {{i18n 'admin.groups.flair_note'}} +
{{#if flairPreviewIcon}} diff --git a/app/assets/javascripts/admin/templates/web-hooks-show-events.hbs b/app/assets/javascripts/admin/templates/web-hooks-show-events.hbs index 7cfb1bd794..f3b8825e5b 100644 --- a/app/assets/javascripts/admin/templates/web-hooks-show-events.hbs +++ b/app/assets/javascripts/admin/templates/web-hooks-show-events.hbs @@ -2,7 +2,7 @@ {{#link-to 'adminWebHooks' tagName='button' classNames='btn'}} {{fa-icon 'list'}} {{i18n 'admin.web_hooks.events.go_list'}} {{/link-to}} - {{d-button icon="send" label="admin.web_hooks.events.ping" action="ping"}} + {{d-button icon="send" label="admin.web_hooks.events.ping" action="ping" disabled=pingDisabled}} {{#link-to 'adminWebHooks.show' model.extras.web_hook_id tagName='button' classNames='btn'}} {{fa-icon 'edit'}} {{i18n 'admin.web_hooks.events.go_details'}} {{/link-to}} @@ -12,6 +12,20 @@ {{#if model}} {{#load-more selector=".web-hook-events li" action="loadMore"}}
+
+
{{i18n 'admin.web_hooks.events.status'}}
+
{{i18n 'admin.web_hooks.events.event_id'}}
+
{{i18n 'admin.web_hooks.events.timestamp'}}
+
{{i18n 'admin.web_hooks.events.completion'}}
+
{{i18n 'admin.web_hooks.events.actions'}}
+
+
+ {{#if hasIncoming}} +
+ {{count-i18n key="admin.web_hooks.events.incoming" count=incomingCount}} + {{i18n 'click_to_show'}} +
+ {{/if}}