· 7 years ago · Mar 09, 2018, 09:24 AM
1Index: cw-ui/app/templates/components/add-post-form.hbs
2IDEA additional info:
3Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
4<+>UTF-8
5===================================================================
6--- cw-ui/app/templates/components/add-post-form.hbs (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
7+++ cw-ui/app/templates/components/add-post-form.hbs (revision )
8@@ -8,6 +8,10 @@
9 rows=10
10 }}
11
12+ {{#if showTwitterWarning}}
13+ <small class="text-warning"><em>{{t "publishing.addPost.form.twitterWarning"}}</em></small>
14+ {{/if}}
15+
16 {{#form.element property="tags" label=(t "publishing.addPost.form.labels.tags") as |el|}}
17 {{manage-related-tags tags=tags record=formData id=el.id}}
18 {{/form.element}}
19@@ -131,9 +135,9 @@
20 </ul>
21 {{/form.element}}
22
23- {{#if (and formData.photo (not formData.useDirectLink))}}
24+ {{#if (and formData.file (not formData.useDirectLink))}}
25 <label>{{t "publishing.addPost.mediaItemPreview"}}</label>
26- {{media-manager/file-viewer file=formData.photo onlyPreview=true}}
27+ {{media-manager/file-viewer file=formData.file onlyPreview=true}}
28 {{/if}}
29 </div>
30 </div>
31Index: cw-ui/app/controllers/login.js
32IDEA additional info:
33Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
34<+>UTF-8
35===================================================================
36--- cw-ui/app/controllers/login.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
37+++ cw-ui/app/controllers/login.js (revision )
38@@ -79,19 +79,21 @@
39 */
40 doTwitterLogin() {
41 const i18n = get(this, 'i18n');
42-
43- get(this, 'ajax')
44- .post('/twitter/request_token')
45- .then(options => {
46- get(this, 'session').authenticate('authenticator:torii', 'twitter', options)
47- .then(() => get(this, 'router').transitionTo('portals'))
48- .catch(e => get(this, 'modalsManager')
49- .alert({
50- title: i18n.t('modals.defaultAlertOptions.title'),
51- body: i18n.t('login.twitterLogin.error') + e,
52- confirm: i18n.t('modals.defaultAlertOptions.confirm')
53- }));
54- });
55+ const ajax = get(this, 'ajax');
56+ get(this, 'session').authenticate('authenticator:torii', 'twitter', {
57+ clb(data) {
58+ return ajax
59+ .post('/twitter/login', {data})
60+ .then(response => ({token: response.token, provider: 'twitter'}));
61+ }
62+ })
63+ .then(() => get(this, 'router').transitionTo('portals'))
64+ .catch(e => get(this, 'modalsManager')
65+ .alert({
66+ title: i18n.t('modals.defaultAlertOptions.title'),
67+ body: i18n.t('login.twitterLogin.error') + e,
68+ confirm: i18n.t('modals.defaultAlertOptions.confirm')
69+ }));
70 }
71 }
72 });
73Index: cw-ui/app/components/posts/posts-table.js
74IDEA additional info:
75Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
76<+>UTF-8
77===================================================================
78--- cw-ui/app/components/posts/posts-table.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
79+++ cw-ui/app/components/posts/posts-table.js (revision )
80@@ -22,6 +22,12 @@
81 */
82 i18n: service(),
83
84+ /**
85+ * @property modalsManager
86+ * @type Ember.Service
87+ */
88+ modalsManager: service(),
89+
90 /**
91 * @property posts
92 * @type Models.Post[]
93@@ -29,6 +35,12 @@
94 */
95 posts: null,
96
97+ /**
98+ * @property columns
99+ * @type object[]
100+ * @private
101+ * @readonly
102+ */
103 columns: computed(function () {
104 const i18n = get(this, 'i18n');
105 return [
106@@ -44,6 +56,8 @@
107 },
108 {
109 propertyName: 'status',
110+ title: i18n.t('campaigns.details.posts.table.titles.status'),
111+ component: 'posts/posts-table/status',
112 filterWithSelect: true
113 },
114 {
115@@ -59,8 +73,29 @@
116 const tags = get(post, 'tags');
117 return filter ? filter.every(f => tags.includes(f)) : true;
118 }
119- }
120+ },
121+ // todo uncomment when BE will support deletion in the publish sources
122+ // {component: 'delete-record'}
123 ];
124- })
125+ }).readOnly(),
126+
127+ actions: {
128+
129+ /**
130+ * @method actions.deletePost
131+ * @param {Models.Post} post post to delete
132+ * @return {RSVP.Promise} delete result or nothing
133+ */
134+ deletePost(post) {
135+ const i18n = get(this, 'i18n');
136+ return get(this, 'modalsManager')
137+ .confirm({
138+ title: i18n.t('modals.defaultConfirmOptions.title'),
139+ body: i18n.t('modals.defaultConfirmOptions.body'),
140+ confirm: i18n.t('modals.defaultConfirmOptions.confirm')
141+ })
142+ .then(() => post.destroyRecord());
143+ }
144+ }
145
146 });
147Index: cw-ui/app/locales/en/translations.js
148IDEA additional info:
149Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
150<+>UTF-8
151===================================================================
152--- cw-ui/app/locales/en/translations.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
153+++ cw-ui/app/locales/en/translations.js (revision )
154@@ -164,6 +164,7 @@
155 },
156 publishing: {
157 sources: {
158+ title: 'Publish Sources',
159 cantLoadSources: {
160 title: 'Warning',
161 body: 'Something went wrong. Please try again',
162@@ -190,6 +191,8 @@
163 publishDate: 'Publish Date',
164 publishTime: 'Publish Time'
165 },
166+ twitterWarning: 'You have selected a Twitter-account to publish. Keep in mind that Twitter has a restriction for maximum post size.',
167+ twitterError: 'Twitter post must be lower than {{max}} symbols',
168 noPageSelected: 'At least one page must be selected',
169 submit: 'Add Post'
170 },
171@@ -231,6 +234,7 @@
172 title: 'Posts in the Campaign',
173 table: {
174 titles: {
175+ status: 'Status',
176 media: 'Page or Media',
177 body: 'Message',
178 noMediaPage: 'Linked Page is already deleted'
179Index: cw-ui/app/templates/components/posts/posts-table/media-link.hbs
180IDEA additional info:
181Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
182<+>UTF-8
183===================================================================
184--- cw-ui/app/templates/components/posts/posts-table/media-link.hbs (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
185+++ cw-ui/app/templates/components/posts/posts-table/media-link.hbs (revision )
186@@ -3,8 +3,8 @@
187 {{record.page.title}}
188 {{/link-to}}
189 {{else}}
190- {{#if record.postOptions.photo}}
191- <img class="preview" src={{record.postOptions.photo}} alt="">
192+ {{#if record.postOptions.file}}
193+ <img class="preview" src={{record.postOptions.file.preview}} alt="">
194 {{else}}
195 <em>{{t "campaigns.details.posts.table.titles.noMediaPage"}}</em>
196 {{/if}}
197Index: cw-ui/app/templates/components/posts/posts-table/status.hbs
198IDEA additional info:
199Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
200<+>UTF-8
201===================================================================
202--- cw-ui/app/templates/components/posts/posts-table/status.hbs (revision )
203+++ cw-ui/app/templates/components/posts/posts-table/status.hbs (revision )
204@@ -0,0 +1,7 @@
205+{{record.status}}
206+{{#unless isOk}}
207+ <span>
208+ <i class="fa fa-question-circle-o" aria-hidden="true"></i>
209+ {{#bs-tooltip placement="top"}}{{record.postAttributes.reason}}{{/bs-tooltip}}
210+ </span>
211+{{/unless}}
212Index: cw-ui/app/controllers/portals/portal/publishing/post.js
213IDEA additional info:
214Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
215<+>UTF-8
216===================================================================
217--- cw-ui/app/controllers/portals/portal/publishing/post.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
218+++ cw-ui/app/controllers/portals/portal/publishing/post.js (revision )
219@@ -113,7 +113,7 @@
220 .then(() => {
221 const msg = get(this, 'i18n').t('publishing.addPost.postsArePosted', {count: postsData.sources.length});
222 get(this, 'notify').success(msg);
223- get(this, 'router').transitionTo('portals.portal');
224+ get(this, 'router').transitionTo('portals.portal.campaigns.campaign.edit', get(postsData, 'campaign.id'));
225 });
226 },
227
228@@ -128,14 +128,18 @@
229 postsDataToRequests(postsData) {
230 const ajax = get(this, 'ajax');
231 return postsData.sources.map(source => {
232- const {tags, rawMessage, photo, useDirectLink, schedulePublish, scheduleType, page, interval, campaign, at: {date, minutes, hours}} = postsData;
233+ const {tags, rawMessage, file, useDirectLink, schedulePublish, scheduleType, page, interval, campaign, at: {date, minutes, hours}} = postsData;
234 const campaignId = get(campaign, 'id');
235 const postOptions = {rawMessage};
236 if (useDirectLink) {
237- postOptions.page = get(page, 'id');
238+ if (page) {
239+ postOptions.page = get(page, 'id');
240+ }
241 }
242 else {
243- postOptions.photo = photo;
244+ if (file) {
245+ postOptions.file = get(file, 'id');
246+ }
247 }
248 const data = {postOptions, campaignId, tagsIds: tags.mapBy('id')};
249 const publishSourceId = get(source, 'id');
250Index: cw-ui/app/templates/portals/portal/publishing/sources.hbs
251IDEA additional info:
252Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
253<+>UTF-8
254===================================================================
255--- cw-ui/app/templates/portals/portal/publishing/sources.hbs (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
256+++ cw-ui/app/templates/portals/portal/publishing/sources.hbs (revision )
257@@ -1,18 +1,20 @@
258-{{#bs-button onClick=(action "loadFbPages")}} <i class="fa fa-plus"></i> <i class="fa fa-facebook"></i>{{/bs-button}}
259-<p></p>
260-{{models-table
261- data=model
262- columns=sourceColumns
263- showColumnsDropdown=false
264- showGlobalFilter=false
265- columnComponents=(hash
266- delete-record=(component
267- "cw-table/delete-record"
268- btnClass="btn-default"
269- btnIcon="fa-remove text-danger"
270- deleteRecord=(action "deletePublishSource")
271- )
272- )
273-}}
274-
275-{{outlet}}
276\ No newline at end of file
277+{{#cw-panel title=(t "publishing.sources.title")}}
278+ {{#bs-button onClick=(action "loadFbPages")}} <i class="fa fa-plus"></i> <i class="fa fa-facebook"></i>{{/bs-button}}
279+ {{#bs-button onClick=(action "loadTwitterAccount")}} <i class="fa fa-plus"></i> <i class="fa fa-twitter"></i>{{/bs-button}}
280+ <p></p>
281+ {{models-table
282+ data=model
283+ columns=sourceColumns
284+ showColumnsDropdown=false
285+ showGlobalFilter=false
286+ columnComponents=(hash
287+ delete-record=(component
288+ "cw-table/delete-record"
289+ btnClass="btn-default"
290+ btnIcon="fa-remove text-danger"
291+ deleteRecord=(action "deletePublishSource")
292+ )
293+ )
294+ }}
295+ {{outlet}}
296+{{/cw-panel}}
297\ No newline at end of file
298Index: cw-ui/app/components/add-post-form.js
299IDEA additional info:
300Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
301<+>UTF-8
302===================================================================
303--- cw-ui/app/components/add-post-form.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
304+++ cw-ui/app/components/add-post-form.js (revision )
305@@ -105,10 +105,26 @@
306 return new Date();
307 }),
308
309+ /**
310+ * Warning is shown if Twitter-acc is selected as publish source and message size is greater than 280 symbols
311+ *
312+ * However, warning is not shown if only Twitter-accounts are selected (error is shown in this case)
313+ *
314+ * @property showTwitterWarning
315+ * @type boolean
316+ * @default false
317+ * @private
318+ * @readonly
319+ */
320+ showTwitterWarning: computed('formData.{sources.@each.sourceType,rawMessage}', function () {
321+ const sources = get(this, 'formData.sources');
322+ return sources.length && sources.isAny('sourceType', 'twitter') && !sources.isEvery('sourceType', 'twitter') && get(this, 'formData.rawMessage.length') > 280;
323+ }).readOnly(),
324+
325 /**
326 * Fields:
327 * * `link`
328- * * `photo`
329+ * * `file`
330 * * `tags`
331 * * `useDirectLink`
332 * * `schedulePublish`
333@@ -141,9 +157,20 @@
334 allowBlank: true
335 })
336 ],
337+ campaign: [
338+ validator('presence', true)
339+ ],
340 rawMessage: [
341 validator('presence', true),
342- validator('length', {min: 11})
343+ validator('length', {min: 11}),
344+ validator(function (value, options, model) {
345+ const sources = get(model, 'sources');
346+ const twitterSelected = sources.isAny('sourceType', 'twitter');
347+ const notOnlyTwitterSelected = !!sources.find(s => get(s, 'sourceType') !== 'twitter');
348+ return twitterSelected && !notOnlyTwitterSelected && value.length > 280 ? i18n.t('publishing.addPost.form.twitterError', {max: 280}).toString() : true;
349+ }, {
350+ dependentKeys: ['model.sources.[]']
351+ })
352 ],
353 sourcesStr: validator('length', {
354 min: 1,
355@@ -210,10 +237,7 @@
356 * @method actions.onSubmit
357 */
358 onSubmit() {
359- const dataToSend = getProperties(get(this, 'formData'), ['link', 'rawMessage', 'sources', 'photo', 'useDirectLink', 'at', 'schedulePublish', 'page', 'interval', 'scheduleType', 'campaign', 'tags']);
360- if (dataToSend.photo) {
361- dataToSend.photo = get(dataToSend.photo, 'preview');
362- }
363+ const dataToSend = getProperties(get(this, 'formData'), ['link', 'rawMessage', 'sources', 'file', 'useDirectLink', 'at', 'schedulePublish', 'page', 'interval', 'scheduleType', 'campaign', 'tags']);
364 get(this, 'onSubmit')(dataToSend);
365 },
366
367@@ -222,7 +246,7 @@
368 * @param {Models.File} file file to attach
369 */
370 selectFile(file) {
371- set(this, 'formData.photo', file);
372+ set(this, 'formData.file', file);
373 },
374
375 /**
376@@ -248,7 +272,7 @@
377 */
378 updatePreviewSource(val) {
379 if (val) {
380- set(this, 'formData.photo', null);
381+ set(this, 'formData.file', null);
382 }
383 else {
384 set(this, 'formData.link', '');
385@@ -302,6 +326,13 @@
386 }
387 },
388
389+ /**
390+ * @method pageMatcher
391+ * @param {Models.Page} page page to check matching
392+ * @param {string} term term from search-field
393+ * @returns {Number} -1 - don't match, any other - match
394+ * @private
395+ */
396 pageMatcher(page, term) {
397 return `${get(page, 'title')} ${get(page, 'url')}`.indexOf(term);
398 }
399Index: cw-ui/app/components/posts/posts-table/status.js
400IDEA additional info:
401Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
402<+>UTF-8
403===================================================================
404--- cw-ui/app/components/posts/posts-table/status.js (revision )
405+++ cw-ui/app/components/posts/posts-table/status.js (revision )
406@@ -0,0 +1,24 @@
407+import Component from '@ember/component';
408+import {computed, get} from '@ember/object';
409+
410+/**
411+ * @class PostStatus
412+ * @namespace Components
413+ * @extends Ember.Component
414+ */
415+export default Component.extend({
416+ classNames: ['posts-table-status'],
417+
418+ /**
419+ * @property isOk
420+ * @type boolean
421+ * @default false
422+ * @private
423+ * @readonly
424+ */
425+ isOk: computed('record.status', function () {
426+ const status = get(this, 'record.status');
427+ return status >= 200 && status < 300;
428+ }).readOnly()
429+
430+});
431Index: cw-ui/app/controllers/portals/portal/publishing/sources.js
432IDEA additional info:
433Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
434<+>UTF-8
435===================================================================
436--- cw-ui/app/controllers/portals/portal/publishing/sources.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
437+++ cw-ui/app/controllers/portals/portal/publishing/sources.js (revision )
438@@ -1,6 +1,7 @@
439 import Controller from '@ember/controller';
440 import {computed, get, set} from '@ember/object';
441 import {inject as service} from '@ember/service';
442+import {getOwner} from '@ember/application';
443
444 /**
445 * @namespace Controllers
446@@ -40,6 +41,15 @@
447 */
448 fbPages: null,
449
450+
451+ /**
452+ * @property toriiAuth
453+ * @type Authenticators.Torii
454+ */
455+ toriiAuth: computed(function () {
456+ return getOwner(this).lookup('authenticator:torii');
457+ }),
458+
459 /**
460 * List of column-definitions for modal with fb-pages
461 *
462@@ -66,7 +76,7 @@
463 return [
464 {component: 'publish-source/external-link'},
465 {propertyName: 'category'},
466- {propertyName: 'sourceId'},
467+ {propertyName: 'sourceType', filterWithSelect: true},
468 {component: 'delete-record'}
469 ];
470 }),
471@@ -108,6 +118,29 @@
472 );
473 },
474
475+ /**
476+ * @method loadTwitterAccount
477+ * @returns {RSVP.Promise} request to add twitter account
478+ */
479+ loadTwitterAccount() {
480+ const i18n = get(this, 'i18n');
481+ const ajax = get(this, 'ajax');
482+ const store = get(this, 'store');
483+ return get(this, 'toriiAuth')
484+ .authenticate('twitter', {
485+ clb(data) {
486+ return ajax.post('/twitter/sources', {data: {data}})
487+ .then(() => store.findAll('publish-source'));
488+ }
489+ })
490+ .catch(e => get(this, 'modalsManager')
491+ .alert({
492+ title: i18n.t('publishing.sources.cantLoadSources.title'),
493+ body: i18n.t('publishing.sources.cantLoadSources.body') + e,
494+ confirm: i18n.t('modals.defaultAlertOptions.confirm')
495+ }));
496+ },
497+
498 /**
499 * @method actions.deletePublishSource
500 * @param {Models.PublishSource} record record to delete
501Index: cw-ui/app/templates/components/posts/posts-table.hbs
502IDEA additional info:
503Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
504<+>UTF-8
505===================================================================
506--- cw-ui/app/templates/components/posts/posts-table.hbs (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
507+++ cw-ui/app/templates/components/posts/posts-table.hbs (revision )
508@@ -3,4 +3,13 @@
509 columns=columns
510 showColumnsDropdown=false
511 showGlobalFilter=false
512+ columnComponents=(hash
513+ delete-record=(component
514+ "cw-table/delete-record"
515+ btnClass="btn-xs btn-default pull-right"
516+ btnIcon="fa-remove text-danger"
517+ btnText=""
518+ deleteRecord=(action "deletePost")
519+ )
520+ )
521 }}
522\ No newline at end of file
523Index: cw-ui/app/components/cw-table/delete-record.js
524IDEA additional info:
525Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
526<+>UTF-8
527===================================================================
528--- cw-ui/app/components/cw-table/delete-record.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
529+++ cw-ui/app/components/cw-table/delete-record.js (revision )
530@@ -37,6 +37,10 @@
531 */
532 export default Component.extend({
533
534+ /**
535+ * @property i18n
536+ * @type Ember.Service
537+ */
538 i18n: service(),
539
540 tagName: 'button',
541Index: cw-ui/app/torii-providers/twitter.js
542IDEA additional info:
543Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
544<+>UTF-8
545===================================================================
546--- cw-ui/app/torii-providers/twitter.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
547+++ cw-ui/app/torii-providers/twitter.js (revision )
548@@ -13,9 +13,5 @@
549 open: function (options) {
550 const url = `${get(this, 'requestTokenUri')}${options.oauthToken}`;
551 return get(this, 'popup').open(url, ['oauth_verifier'], options);
552- },
553-
554- fetch(data) {
555- return data;
556 }
557 });
558Index: cw-ui/app/templates/components/cw-panel.hbs
559IDEA additional info:
560Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
561<+>UTF-8
562===================================================================
563--- cw-ui/app/templates/components/cw-panel.hbs (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
564+++ cw-ui/app/templates/components/cw-panel.hbs (revision )
565@@ -13,8 +13,12 @@
566 </div>
567 {{#if expanded}}
568 <div class="panel-body">
569- {{#if bodyComponent}}
570- {{component bodyComponent}}
571+ {{#if hasBlock}}
572+ {{yield}}
573+ {{else}}
574+ {{#if bodyComponent}}
575+ {{component bodyComponent}}
576+ {{/if}}
577 {{/if}}
578 </div>
579 {{/if}}
580Index: cw-ui/app/authenticators/torii.js
581IDEA additional info:
582Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
583<+>UTF-8
584===================================================================
585--- cw-ui/app/authenticators/torii.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
586+++ cw-ui/app/authenticators/torii.js (revision )
587@@ -28,30 +28,33 @@
588 /**
589 * @method authenticate
590 * @param {string} type auth type (facebook, twitter etc)
591- * @param {object} options auth options
592+ * @param {object} opts auth options
593 * @return {RSVP.Promise} auth result
594 */
595- authenticate(type, options) {
596+ authenticate(type, opts) {
597 const ajax = get(this, 'ajax');
598 if (type === 'facebook') {
599 return this._super(...arguments).then(data => ajax
600 .post('/facebook/login', {data: {userToken: data.authorizationCode}})
601 .then(response => ({
602- token: response.token,
603- provider: data.provider
604- })));
605+ token: response.token,
606+ provider: data.provider
607+ })));
608 }
609 if (type === 'twitter') {
610- return this._super(...arguments).then(data => ajax
611- .post('/twitter/access_token', {
612- data: {
613- verifier: data.oauth_verifier,
614- oauthToken: options.oauthToken,
615- oauthTokenSecret: options.oauthTokenSecret
616- }
617- })
618- .then(data => ajax
619- .post('/twitter/login', {data})));
620+ const _super = this._super;
621+ return ajax.post('/twitter/request_token')
622+ .then(options => {
623+ return _super.call(this, type, options).then(data => ajax
624+ .post('/twitter/access_token', {
625+ data: {
626+ verifier: data.oauth_verifier,
627+ oauthToken: options.oauthToken,
628+ oauthTokenSecret: options.oauthTokenSecret
629+ }
630+ })
631+ .then(opts.clb));
632+ });
633 }
634 }
635 });
636Index: cw-ui/app/templates/components/publish-source/external-link.hbs
637IDEA additional info:
638Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
639<+>UTF-8
640===================================================================
641--- cw-ui/app/templates/components/publish-source/external-link.hbs (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
642+++ cw-ui/app/templates/components/publish-source/external-link.hbs (revision )
643@@ -1,1 +1,5 @@
644-<a target="_blank" rel="noopener" href={{url}}>{{record.name}}</a>
645\ No newline at end of file
646+{{#if url}}
647+ <a target="_blank" rel="noopener" href={{url}}>{{record.name}}</a>
648+{{else}}
649+ {{record.name}}
650+{{/if}}
651\ No newline at end of file
652Index: cw-ui/app/authenticators/jwt.js
653IDEA additional info:
654Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
655<+>UTF-8
656===================================================================
657--- cw-ui/app/authenticators/jwt.js (revision c68e9e38b31a08e1c748b4f370d61a2e74b23b24)
658+++ cw-ui/app/authenticators/jwt.js (revision )
659@@ -13,8 +13,19 @@
660 */
661 export default Jwt.extend({
662
663+ /**
664+ * @property ajax
665+ * @type Ember.Service
666+ */
667 ajax: service(),
668
669+ /**
670+ * @method makeRequest
671+ * @param {string} url url for request
672+ * @param {object} data request data
673+ * @param {object} headers extra headers for request
674+ * @returns {RSVP.Promise} request itself
675+ */
676 makeRequest(url, data, headers) {
677 const host = get(this, 'ajax.host') || '';
678 url = `${host}/${url}`;
679Index: cw-ui/tests/integration/components/posts/posts-table/status-test.js
680IDEA additional info:
681Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
682<+>UTF-8
683===================================================================
684--- cw-ui/tests/integration/components/posts/posts-table/status-test.js (revision )
685+++ cw-ui/tests/integration/components/posts/posts-table/status-test.js (revision )
686@@ -0,0 +1,11 @@
687+import { moduleForComponent, test } from 'ember-qunit';
688+import hbs from 'htmlbars-inline-precompile';
689+
690+moduleForComponent('posts/posts-table/status', 'Integration | Component | posts/posts table/status', {
691+ integration: true
692+});
693+
694+test('it renders', function(assert) {
695+ this.render(hbs`{{posts/posts-table/status}}`);
696+ assert.ok(true);
697+});