diff --git a/app/components/gh-date-time-picker.js b/app/components/gh-date-time-picker.js index dc47f863c2..dc7bdfa318 100644 --- a/app/components/gh-date-time-picker.js +++ b/app/components/gh-date-time-picker.js @@ -33,7 +33,7 @@ export default Component.extend({ let errors = this.get('errors'); let property = this.get('dateErrorProperty'); - if (!isEmpty(errors.errorsFor(property))) { + if (errors && !isEmpty(errors.errorsFor(property))) { return errors.errorsFor(property).get('firstObject').message; } }), @@ -42,7 +42,7 @@ export default Component.extend({ let errors = this.get('errors'); let property = this.get('timeErrorProperty'); - if (!isEmpty(errors.errorsFor(property))) { + if (errors && !isEmpty(errors.errorsFor(property))) { return errors.errorsFor(property).get('firstObject').message; } }), diff --git a/app/components/gh-post-settings-menu.js b/app/components/gh-post-settings-menu.js index ff0e6f20cf..02282f9fe8 100644 --- a/app/components/gh-post-settings-menu.js +++ b/app/components/gh-post-settings-menu.js @@ -137,21 +137,6 @@ export default Component.extend(SettingsMenuMixin, { return false; }, - togglePage() { - this.toggleProperty('post.page'); - - // If this is a new post. Don't save the post. Defer the save - // to the user pressing the save button - if (this.get('post.isNew')) { - return; - } - - this.get('savePost').perform().catch((error) => { - this.showError(error); - this.get('post').rollbackAttributes(); - }); - }, - toggleFeatured() { this.toggleProperty('post.featured'); diff --git a/app/components/gh-psm-template-select.js b/app/components/gh-psm-template-select.js index 952c5106fc..a90101e339 100644 --- a/app/components/gh-psm-template-select.js +++ b/app/components/gh-psm-template-select.js @@ -31,7 +31,7 @@ export default Component.extend({ matchedSlugTemplate: computed('post.{page,slug}', 'activeTheme.slugTemplates.[]', function () { let slug = this.get('post.slug'); - let type = this.get('post.page') ? 'page' : 'post'; + let type = this.post.constructor.modelName; let [matchedTemplate] = this.get('activeTheme.slugTemplates').filter(function (template) { return template.for.includes(type) && template.slug === slug; diff --git a/app/components/gh-search-input.js b/app/components/gh-search-input.js index c31086f678..f430315cae 100644 --- a/app/components/gh-search-input.js +++ b/app/components/gh-search-input.js @@ -33,7 +33,7 @@ export default Component.extend({ currentSearch: '', selection: null, - posts: computedGroup('Stories'), + posts: computedGroup('Posts'), pages: computedGroup('Pages'), users: computedGroup('Users'), tags: computedGroup('Tags'), @@ -42,7 +42,7 @@ export default Component.extend({ let groups = []; if (!isEmpty(this.get('posts'))) { - groups.pushObject({groupName: 'Stories', options: this.get('posts')}); + groups.pushObject({groupName: 'Posts', options: this.get('posts')}); } if (!isEmpty(this.get('pages'))) { @@ -71,9 +71,14 @@ export default Component.extend({ return; } - if (selected.category === 'Stories' || selected.category === 'Pages') { + if (selected.category === 'Posts') { let id = selected.id.replace('post.', ''); - this.get('router').transitionTo('editor.edit', id); + this.get('router').transitionTo('editor.edit', 'post', id); + } + + if (selected.category === 'Pages') { + let id = selected.id.replace('page.', ''); + this.get('router').transitionTo('editor.edit', 'page', id); } if (selected.category === 'Users') { @@ -132,6 +137,7 @@ export default Component.extend({ this.set('content', []); promises.pushObject(this._loadPosts()); + promises.pushObject(this._loadPages()); promises.pushObject(this._loadUsers()); promises.pushObject(this._loadTags()); @@ -149,14 +155,31 @@ export default Component.extend({ _loadPosts() { let store = this.get('store'); let postsUrl = `${store.adapterFor('post').urlForQuery({}, 'post')}/`; - let postsQuery = {fields: 'id,title,page', limit: 'all', status: 'all', filter: 'page:[true,false]'}; + let postsQuery = {fields: 'id,title,page', limit: 'all', status: 'all'}; let content = this.get('content'); return this.get('ajax').request(postsUrl, {data: postsQuery}).then((posts) => { content.pushObjects(posts.posts.map(post => ({ id: `post.${post.id}`, title: post.title, - category: post.page ? 'Pages' : 'Stories' + category: 'Posts' + }))); + }).catch((error) => { + this.get('notifications').showAPIError(error, {key: 'search.loadPosts.error'}); + }); + }, + + _loadPages() { + let store = this.get('store'); + let pagesUrl = `${store.adapterFor('page').urlForQuery({}, 'page')}/`; + let pagesQuery = {fields: 'id,title,page', limit: 'all', status: 'all'}; + let content = this.get('content'); + + return this.get('ajax').request(pagesUrl, {data: pagesQuery}).then((pages) => { + content.pushObjects(pages.pages.map(page => ({ + id: `page.${page.id}`, + title: page.title, + category: 'Pages' }))); }).catch((error) => { this.get('notifications').showAPIError(error, {key: 'search.loadPosts.error'}); diff --git a/app/controllers/pages-loading.js b/app/controllers/pages-loading.js new file mode 100644 index 0000000000..c26eb82da8 --- /dev/null +++ b/app/controllers/pages-loading.js @@ -0,0 +1,7 @@ +import PostsLoadingController from './posts-loading'; +import {inject as controller} from '@ember/controller'; + +/* eslint-disable ghost/ember/alias-model-in-controller */ +export default PostsLoadingController.extend({ + postsController: controller('pages') +}); diff --git a/app/controllers/pages.js b/app/controllers/pages.js new file mode 100644 index 0000000000..c4f5abc8fb --- /dev/null +++ b/app/controllers/pages.js @@ -0,0 +1,44 @@ +import PostsController from './posts'; + +const TYPES = [{ + name: 'All pages', + value: null +}, { + name: 'Draft pages', + value: 'draft' +}, { + name: 'Published pages', + value: 'published' +}, { + name: 'Scheduled pages', + value: 'scheduled' +}, { + name: 'Featured pages', + value: 'featured' +}]; + +const ORDERS = [{ + name: 'Newest', + value: null +}, { + name: 'Oldest', + value: 'published_at asc' +}, { + name: 'Recently updated', + value: 'updated_at desc' +}]; + +/* eslint-disable ghost/ember/alias-model-in-controller */ +export default PostsController.extend({ + init() { + this._super(...arguments); + this.availableTypes = TYPES; + this.availableOrders = ORDERS; + }, + + actions: { + openEditor(page) { + this.transitionToRoute('editor.edit', 'page', page.get('id')); + } + } +}); diff --git a/app/controllers/posts-loading.js b/app/controllers/posts-loading.js index 7a1b6a51f7..41c136ebe5 100644 --- a/app/controllers/posts-loading.js +++ b/app/controllers/posts-loading.js @@ -1,8 +1,8 @@ -/* eslint-disable ghost/ember/alias-model-in-controller */ import Controller, {inject as controller} from '@ember/controller'; import {readOnly} from '@ember/object/computed'; import {inject as service} from '@ember/service'; +/* eslint-disable ghost/ember/alias-model-in-controller */ export default Controller.extend({ postsController: controller('posts'), diff --git a/app/controllers/posts.js b/app/controllers/posts.js index 6f3b21bcbc..4fbbffb9e1 100644 --- a/app/controllers/posts.js +++ b/app/controllers/posts.js @@ -19,9 +19,6 @@ const TYPES = [{ }, { name: 'Featured posts', value: 'featured' -}, { - name: 'Pages', - value: 'page' }]; const ORDERS = [{ @@ -137,7 +134,7 @@ export default Controller.extend({ }, openEditor(post) { - this.transitionToRoute('editor.edit', post.get('id')); + this.transitionToRoute('editor.edit', 'post', post.get('id')); } } }); diff --git a/app/models/page.js b/app/models/page.js new file mode 100644 index 0000000000..5d3faca464 --- /dev/null +++ b/app/models/page.js @@ -0,0 +1,5 @@ +import PostModel from './post'; + +export default PostModel.extend({ + displayName: 'page' +}); diff --git a/app/models/post.js b/app/models/post.js index ff7f5ecc8b..f117938fd2 100644 --- a/app/models/post.js +++ b/app/models/post.js @@ -72,6 +72,7 @@ export default Model.extend(Comparable, ValidationEngine, { clock: service(), settings: service(), + displayName: 'post', validationType: 'post', createdAtUTC: attr('moment-utc'), @@ -92,7 +93,6 @@ export default Model.extend(Comparable, ValidationEngine, { metaDescription: attr('string'), metaTitle: attr('string'), mobiledoc: attr('json-string'), - page: attr('boolean', {defaultValue: false}), plaintext: attr('string'), publishedAtUTC: attr('moment-utc'), slug: attr('string'), diff --git a/app/router.js b/app/router.js index 1562131bfc..cdf12b9840 100644 --- a/app/router.js +++ b/app/router.js @@ -32,10 +32,11 @@ Router.map(function () { this.route('about', {path: '/about'}); this.route('posts', {path: '/'}, function () {}); + this.route('pages', {path: '/pages'}, function () {}); this.route('editor', function () { - this.route('new', {path: ''}); - this.route('edit', {path: ':post_id'}); + this.route('new', {path: ':type'}); + this.route('edit', {path: ':type/:post_id'}); }); this.route('team', {path: '/team'}, function () { diff --git a/app/routes/editor/edit.js b/app/routes/editor/edit.js index c3980e3ef6..67548aecc1 100644 --- a/app/routes/editor/edit.js +++ b/app/routes/editor/edit.js @@ -1,4 +1,5 @@ import AuthenticatedRoute from 'ghost-admin/routes/authenticated'; +import {pluralize} from 'ember-inflector'; export default AuthenticatedRoute.extend({ beforeModel(transition) { @@ -17,11 +18,10 @@ export default AuthenticatedRoute.extend({ let query = { id: params.post_id, status: 'all', - filter: 'page:[true,false]', formats: 'mobiledoc,plaintext' }; - return this.store.query('post', query) + return this.store.query(params.type, query) .then(records => records.get('firstObject')); }, @@ -32,17 +32,26 @@ export default AuthenticatedRoute.extend({ this._super(...arguments); return this.get('session.user').then((user) => { + let returnRoute = `${pluralize(post.constructor.modelName)}.index`; + if (user.get('isAuthorOrContributor') && !post.isAuthoredByUser(user)) { - return this.replaceWith('posts.index'); + return this.replaceWith(returnRoute); } // If the post is not a draft and user is contributor, redirect to index if (user.get('isContributor') && !post.get('isDraft')) { - return this.replaceWith('posts.index'); + return this.replaceWith(returnRoute); } }); }, + serialize(model) { + return { + type: model.constructor.modelName, + post_id: model.id + }; + }, + // there's no specific controller for this route, instead all editor // handling is done on the editor route/controler setupController(controller, post) { diff --git a/app/routes/editor/index.js b/app/routes/editor/index.js new file mode 100644 index 0000000000..1fa6ccfa91 --- /dev/null +++ b/app/routes/editor/index.js @@ -0,0 +1,8 @@ +import AuthenticatedRoute from 'ghost-admin/routes/authenticated'; + +export default AuthenticatedRoute.extend({ + beforeModel() { + this._super(...arguments); + this.replaceWith('editor.new', 'post'); + } +}); diff --git a/app/routes/editor/new.js b/app/routes/editor/new.js index c88b5099a2..63373860c7 100644 --- a/app/routes/editor/new.js +++ b/app/routes/editor/new.js @@ -1,9 +1,9 @@ import AuthenticatedRoute from 'ghost-admin/routes/authenticated'; export default AuthenticatedRoute.extend({ - model() { + model(params) { return this.get('session.user').then(user => ( - this.store.createRecord('post', {authors: [user]}) + this.store.createRecord(params.type, {authors: [user]}) )); }, diff --git a/app/routes/pages.js b/app/routes/pages.js new file mode 100644 index 0000000000..ae543e0c10 --- /dev/null +++ b/app/routes/pages.js @@ -0,0 +1,6 @@ +import PostsRoute from './posts'; + +export default PostsRoute.extend({ + titleToken: 'Pages', + modelName: 'page' +}); diff --git a/app/routes/posts.js b/app/routes/posts.js index 012201bdc5..024dbc448f 100644 --- a/app/routes/posts.js +++ b/app/routes/posts.js @@ -1,4 +1,3 @@ -import $ from 'jquery'; import AuthenticatedRoute from 'ghost-admin/routes/authenticated'; import {assign} from '@ember/polyfills'; import {isBlank} from '@ember/utils'; @@ -26,14 +25,15 @@ export default AuthenticatedRoute.extend({ } }, - titleToken: 'Content', + titleToken: 'Posts', + modelName: 'post', perPage: 30, _type: null, model(params) { - return this.get('session.user').then((user) => { + return this.session.user.then((user) => { let queryParams = {}; let filterParams = {tag: params.tag}; let paginationParams = { @@ -47,12 +47,12 @@ export default AuthenticatedRoute.extend({ filterParams.featured = true; } - if (user.get('isAuthor')) { + if (user.isAuthor) { // authors can only view their own posts - filterParams.authors = user.get('slug'); - } else if (user.get('isContributor')) { + filterParams.authors = user.slug; + } else if (user.isContributor) { // Contributors can only view their own draft posts - filterParams.authors = user.get('slug'); + filterParams.authors = user.slug; filterParams.status = 'draft'; } else if (params.author) { filterParams.authors = params.author; @@ -69,10 +69,10 @@ export default AuthenticatedRoute.extend({ queryParams.formats = 'mobiledoc,plaintext'; - let perPage = this.get('perPage'); + let perPage = this.perPage; let paginationSettings = assign({perPage, startingPage: 1}, paginationParams, queryParams); - return this.infinity.model('post', paginationSettings); + return this.infinity.model(this.modelName, paginationSettings); }); }, @@ -81,14 +81,14 @@ export default AuthenticatedRoute.extend({ this._super(...arguments); if (!controller._hasLoadedTags) { - this.get('store').query('tag', {limit: 'all'}).then(() => { + this.store.query('tag', {limit: 'all'}).then(() => { controller._hasLoadedTags = true; }); } - this.get('session.user').then((user) => { - if (!user.get('isAuthorOrContributor') && !controller._hasLoadedAuthors) { - this.get('store').query('user', {limit: 'all'}).then(() => { + this.session.user.then((user) => { + if (!user.isAuthorOrContributor && !controller._hasLoadedAuthors) { + this.store.query('user', {limit: 'all'}).then(() => { controller._hasLoadedAuthors = true; }); } @@ -97,14 +97,17 @@ export default AuthenticatedRoute.extend({ actions: { willTransition() { - if (this.get('controller')) { + if (this.controller) { this.resetController(); } }, queryParamsDidChange() { // scroll back to the top - $('.content-list').scrollTop(0); + let contentList = document.querySelector('.content-list'); + if (contentList) { + contentList.scrollTop = 0; + } this._super(...arguments); } @@ -112,29 +115,21 @@ export default AuthenticatedRoute.extend({ _getTypeFilters(type) { let status = '[draft,scheduled,published]'; - let page = '[true,false]'; switch (type) { case 'draft': status = 'draft'; - page = false; break; case 'published': status = 'published'; - page = false; break; case 'scheduled': status = 'scheduled'; - page = false; - break; - case 'page': - page = true; break; } return { - status, - page + status }; }, diff --git a/app/serializers/page.js b/app/serializers/page.js new file mode 100644 index 0000000000..5e82bbd95e --- /dev/null +++ b/app/serializers/page.js @@ -0,0 +1,3 @@ +import PostSerializer from './post'; + +export default PostSerializer.extend({}); diff --git a/app/services/tour.js b/app/services/tour.js index 2ad99c5e2a..13ac6609a3 100644 --- a/app/services/tour.js +++ b/app/services/tour.js @@ -53,10 +53,6 @@ export default Service.extend(Evented, { id: 'using-the-editor', title: 'Using the Ghost editor', message: 'Ghost uses Markdown to allow you to write and format content quickly and easily. This toolbar also helps! Hit the ? icon for more editor shortcuts.' - }, { - id: 'static-post', - title: 'Turning posts into pages', - message: 'Static pages are permanent pieces of content which live outside of your usual stream of posts, for example an \'about\' or \'contact\' page.' }, { id: 'featured-post', title: 'Setting a featured post', diff --git a/app/templates/components/gh-mobile-nav-bar.hbs b/app/templates/components/gh-mobile-nav-bar.hbs index 5b81a41b8c..6a6184c6a5 100644 --- a/app/templates/components/gh-mobile-nav-bar.hbs +++ b/app/templates/components/gh-mobile-nav-bar.hbs @@ -1,8 +1,8 @@ -{{#link-to "editor.new" data-test-mobile-nav="new-story"}}{{svg-jar "pen"}}New story{{/link-to}} +{{#link-to "editor.new" "post" data-test-mobile-nav="new-post"}}{{svg-jar "pen"}}New post{{/link-to}} {{#if (eq router.currentRouteName "posts.index")}} - {{#link-to "posts" (query-params type=null) classNames="active" data-test-mobile-nav="stories"}}{{svg-jar "content"}}Stories{{/link-to}} + {{#link-to "posts" (query-params type=null) classNames="active" data-test-mobile-nav="posts"}}{{svg-jar "content"}}Posts{{/link-to}} {{else}} - {{#link-to "posts"}}{{svg-jar "content" data-test-mobile-nav="stories"}}Content{{/link-to}} + {{#link-to "posts"}}{{svg-jar "content" data-test-mobile-nav="posts"}}Posts{{/link-to}} {{/if}} {{#link-to "team" classNames="gh-nav-main-users" data-test-mobile-nav="team"}}{{svg-jar "account-group"}}Team{{/link-to}}
{{svg-jar "icon" class="icon-gh"}}More
diff --git a/app/templates/components/gh-nav-menu.hbs b/app/templates/components/gh-nav-menu.hbs index 46758c7126..633c7b8f3d 100644 --- a/app/templates/components/gh-nav-menu.hbs +++ b/app/templates/components/gh-nav-menu.hbs @@ -40,13 +40,21 @@ {{gh-search-input class="gh-nav-search-input"}}
- -
@@ -410,13 +396,6 @@ pane is shown --}} {{#if _showThrobbers}} - {{gh-tour-item "static-post" - target="label[for='static-page'] p" - throbberAttachment="middle middle" - throbberOffset="0px 33px" - popoverTriangleClass="bottom-right" - }} - {{gh-tour-item "featured-post" target="label[for='featured'] p" throbberAttachment="middle middle" diff --git a/app/templates/components/gh-posts-list-item.hbs b/app/templates/components/gh-posts-list-item.hbs index 00518c485a..2a8e4dcc36 100644 --- a/app/templates/components/gh-posts-list-item.hbs +++ b/app/templates/components/gh-posts-list-item.hbs @@ -1,4 +1,4 @@ -

{{#link-to "editor.edit" post.id class="permalink" title="Edit this post"}}{{post.title}}{{/link-to}}

+

{{#link-to "editor.edit" "post" post.id class="permalink" title="Edit this post"}}{{post.title}}{{/link-to}}

{{subText}}

diff --git a/app/templates/editor.hbs b/app/templates/editor.hbs index c443cc03e2..8e98095462 100644 --- a/app/templates/editor.hbs +++ b/app/templates/editor.hbs @@ -8,9 +8,9 @@
{{#if ui.isFullScreen}}
- {{#link-to "posts" classNames="blue link fw4 flex items-center" data-test-link="stories"}} + {{#link-to (pluralize post.displayName) classNames="blue link fw4 flex items-center" data-test-link=(pluralize post.displayName)}} {{svg-jar "arrow-left" class="w3 fill-blue mr1 nudge-right--2"}} - Stories + {{capitalize (pluralize post.displayName)}} {{/link-to}}
{{/if}} @@ -23,7 +23,7 @@ {{#gh-scheduled-post-countdown post=post as |post countdown|}} {{/gh-scheduled-post-countdown}}
@@ -71,11 +71,11 @@ --}} {{gh-koenig-editor title=(readonly post.titleScratch) - titlePlaceholder="Story Title" + titlePlaceholder=(concat (capitalize post.displayName) " Title") onTitleChange=(action "updateTitleScratch") onTitleBlur=(action (perform saveTitle)) body=(readonly post.scratch) - bodyPlaceholder="Begin writing your story..." + bodyPlaceholder=(concat "Begin writing your " post.displayName "...") bodyAutofocus=shouldFocusEditor onBodyChange=(action "updateScratch") headerOffset=editor.headerHeight diff --git a/app/templates/pages-loading.hbs b/app/templates/pages-loading.hbs new file mode 100644 index 0000000000..dc439e6469 --- /dev/null +++ b/app/templates/pages-loading.hbs @@ -0,0 +1,89 @@ +
+
+

Your pages

+
+ {{#link-to "editor.new" "page" class="gh-btn gh-btn-green" data-test-new-page-button=true}}New page{{/link-to}} +
+
+ +
+
+ {{#power-select + placeholder="All pages" + selected=selectedType + options=availableTypes + searchField="name" + onchange=(action (mut k)) + tagName="div" + classNames="gh-contentfilter-menu gh-contentfilter-type" + triggerClass="gh-contentfilter-menu-trigger" + dropdownClass="gh-contentfilter-menu-dropdown" + matchTriggerWidth=false + data-test-type-select=true + as |type| + }} + {{type.name}} + {{/power-select}} + + {{#unless session.user.isAuthorOrContributor}} + {{#power-select + placeholder="All authors" + selected=selectedAuthor + options=availableAuthors + searchField="name" + onchange=(action (mut k)) + tagName="div" + classNames="gh-contentfilter-menu gh-contentfilter-author" + triggerClass="gh-contentfilter-menu-trigger" + dropdownClass="gh-contentfilter-menu-dropdown" + matchTriggerWidth=false + data-test-author-select=true + as |author| + }} + {{author.name}} + {{/power-select}} + {{/unless}} + + {{#power-select + placeholder="All tags" + selected=selectedTag + options=availableTags + searchField="name" + onchange=(action (mut k)) + tagName="div" + classNames="gh-contentfilter-menu gh-contentfilter-tag" + triggerClass="gh-contentfilter-menu-trigger" + dropdownClass="gh-contentfilter-menu-dropdown" + searchPlaceholder="Search tags" + matchTriggerWidth=false + data-test-tag-select=true + as |tag| + }} + {{tag.name}} + {{/power-select}} +
+
+ Sort by: + {{#power-select + selected=selectedOrder + options=availableOrders + searchEnabled=false + onchange=(action (mut k)) + tagName="div" + classNames="gh-contentfilter-menu gh-contentfilter-sort" + triggerClass="gh-contentfilter-menu-trigger" + dropdownClass="gh-contentfilter-menu-dropdown" + horizontalPosition="right" + matchTriggerWidth=false + data-test-order-select=true + as |order| + }} + {{order.name}} + {{/power-select}} +
+
+ +
+ {{gh-loading-spinner}} +
+
diff --git a/app/templates/pages.hbs b/app/templates/pages.hbs new file mode 100644 index 0000000000..a9a65e32d5 --- /dev/null +++ b/app/templates/pages.hbs @@ -0,0 +1,118 @@ +
+
+

Your pages

+
+ {{#link-to "editor.new" "page" class="gh-btn gh-btn-green" data-test-new-page-button=true}}New page{{/link-to}} +
+
+
+
+ {{#unless session.user.isContributor}} + {{#power-select + selected=selectedType + options=availableTypes + searchEnabled=false + onchange=(action "changeType") + tagName="div" + classNames="gh-contentfilter-menu gh-contentfilter-type" + triggerClass="gh-contentfilter-menu-trigger" + dropdownClass="gh-contentfilter-menu-dropdown" + matchTriggerWidth=false + data-test-type-select=true + as |type| + }} + {{type.name}} + {{/power-select}} + {{/unless}} + + {{#unless session.user.isAuthorOrContributor}} + {{#power-select + selected=selectedAuthor + options=availableAuthors + searchField="name" + onchange=(action "changeAuthor") + tagName="div" + classNames="gh-contentfilter-menu gh-contentfilter-author" + triggerClass="gh-contentfilter-menu-trigger" + dropdownClass="gh-contentfilter-menu-dropdown" + searchPlaceholder="Search authors" + matchTriggerWidth=false + data-test-author-select=true + as |author| + }} + {{author.name}} + {{/power-select}} + {{/unless}} + + {{#unless session.user.isContributor}} + {{#power-select + selected=selectedTag + options=availableTags + searchField="name" + onchange=(action "changeTag") + tagName="div" + classNames="gh-contentfilter-menu gh-contentfilter-tag" + triggerClass="gh-contentfilter-menu-trigger" + dropdownClass="gh-contentfilter-menu-dropdown" + searchPlaceholder="Search tags" + matchTriggerWidth=false + optionsComponent="power-select-vertical-collection-options" + data-test-tag-select=true + as |tag| + }} + {{tag.name}} + {{/power-select}} + {{/unless}} +
+ +
+ Sort by: + {{#power-select + selected=selectedOrder + options=availableOrders + searchEnabled=false + onchange=(action "changeOrder") + tagName="div" + classNames="gh-contentfilter-menu gh-contentfilter-sort" + triggerClass="gh-contentfilter-menu-trigger" + dropdownClass="gh-contentfilter-menu-dropdown" + horizontalPosition="right" + matchTriggerWidth=false + data-test-order-select=true + as |order| + }} + {{order.name}} + {{/power-select}} +
+
+ +
+
    + {{#each postsInfinityModel as |page|}} + {{gh-posts-list-item + post=page + onDoubleClick=(action "openEditor") + data-test-page-id=page.id}} + {{else}} +
  1. +
    + {{#if showingAll}} +

    You haven't created any pages yet!

    + {{#link-to "editor.new" "page"}}{{/link-to}} + {{else}} +

    No pages match the current filter

    + {{#link-to "pages.index" (query-params type=null author=null tag=null)}}{{/link-to}} + {{/if}} +
    +
  2. + {{/each}} +
+ + {{gh-infinity-loader + infinityModel=postsInfinityModel + scrollable=".gh-main" + triggerOffset=1000}} +
+ + {{outlet}} +
diff --git a/app/templates/posts-loading.hbs b/app/templates/posts-loading.hbs index 5adc043ffa..8cab312c20 100644 --- a/app/templates/posts-loading.hbs +++ b/app/templates/posts-loading.hbs @@ -1,8 +1,8 @@
-

Your stories

+

Your posts

- {{#link-to "editor.new" class="gh-btn gh-btn-green" data-test-new-post-button=true}}New story{{/link-to}} + {{#link-to "editor.new" "post" class="gh-btn gh-btn-green" data-test-new-post-button=true}}New post{{/link-to}}
diff --git a/app/templates/posts.hbs b/app/templates/posts.hbs index 51d358699f..49d98e6b8b 100644 --- a/app/templates/posts.hbs +++ b/app/templates/posts.hbs @@ -1,8 +1,8 @@
-

Your stories

+

Your posts

- {{#link-to "editor.new" class="gh-btn gh-btn-green" data-test-new-post-button=true}}New story{{/link-to}} + {{#link-to "editor.new" "post" class="gh-btn gh-btn-green" data-test-new-post-button=true}}New post{{/link-to}}
@@ -97,11 +97,11 @@
  • {{#if showingAll}} -

    You haven't written any stories yet!

    - {{#link-to "editor.new"}}{{/link-to}} +

    You haven't written any posts yet!

    + {{#link-to "editor.new" "post"}}{{/link-to}} {{else}} -

    No stories match the current filter

    - {{#link-to "posts.index" (query-params type=null author=null tag=null)}}{{/link-to}} +

    No posts match the current filter

    + {{#link-to "posts.index" (query-params type=null author=null tag=null)}}{{/link-to}} {{/if}}
  • diff --git a/lib/koenig-editor/addon/components/koenig-slash-menu.js b/lib/koenig-editor/addon/components/koenig-slash-menu.js index 31584ec092..2b3d970b6f 100644 --- a/lib/koenig-editor/addon/components/koenig-slash-menu.js +++ b/lib/koenig-editor/addon/components/koenig-slash-menu.js @@ -62,7 +62,7 @@ export default Component.extend({ this._super(...arguments); // re-register the / text input handler if the editor changes such as - // when a "New story" is clicked from the sidebar or a different post + // when a "New post" is clicked from the sidebar or a different post // is loaded via search if (this.editor !== this._lastEditor) { this.editor.onTextInput({ diff --git a/mirage/config.js b/mirage/config.js index 63a1421a74..c429010542 100644 --- a/mirage/config.js +++ b/mirage/config.js @@ -4,6 +4,7 @@ import mockConfiguration from './config/configuration'; import mockIntegrations from './config/integrations'; import mockInvites from './config/invites'; import mockMembers from './config/members'; +import mockPages from './config/pages'; import mockPosts from './config/posts'; import mockRoles from './config/roles'; import mockSettings from './config/settings'; @@ -57,6 +58,7 @@ export function testConfig() { mockIntegrations(this); mockInvites(this); mockMembers(this); + mockPages(this); mockPosts(this); mockRoles(this); mockSettings(this); diff --git a/mirage/config/pages.js b/mirage/config/pages.js new file mode 100644 index 0000000000..e23d48b123 --- /dev/null +++ b/mirage/config/pages.js @@ -0,0 +1,119 @@ +import moment from 'moment'; +import {Response} from 'ember-cli-mirage'; +import {dasherize} from '@ember/string'; +import {isArray} from '@ember/array'; +import {isBlank, isEmpty} from '@ember/utils'; +import {paginateModelCollection} from '../utils'; + +function normalizeBooleanParams(arr) { + if (!isArray(arr)) { + return arr; + } + + return arr.map((i) => { + if (i === 'true') { + return true; + } else if (i === 'false') { + return false; + } else { + return i; + } + }); +} + +// TODO: use GQL to parse filter string? +function extractFilterParam(param, filter) { + let filterRegex = new RegExp(`${param}:(.*?)(?:\\+|$)`); + let match; + + let [, result] = filter.match(filterRegex) || []; + if (result && result.startsWith('[')) { + match = result.replace(/^\[|\]$/g, '').split(','); + } else if (result) { + match = [result]; + } + + return normalizeBooleanParams(match); +} + +// NOTE: mirage requires Model objects when saving relationships, however the +// `attrs` on POST/PUT requests will contain POJOs for authors and tags so we +// need to replace them +function extractAuthors(pageAttrs, users) { + return pageAttrs.authors.map(author => users.find(author.id)); +} + +function extractTags(pageAttrs, tags) { + return pageAttrs.tags.map((requestTag) => { + let tag = tags.find(requestTag.id); + + if (!tag) { + tag = tag.create(requestTag); + } + + return tag; + }); +} + +export default function mockPages(server) { + server.post('/pages', function ({pages, users, tags}) { + let attrs = this.normalizedRequestAttrs(); + + attrs.authors = extractAuthors(attrs, users); + attrs.tags = extractTags(attrs, tags); + + if (isBlank(attrs.slug) && !isBlank(attrs.title)) { + attrs.slug = dasherize(attrs.title); + } + + return pages.create(attrs); + }); + + // TODO: handle authors filter + server.get('/pages/', function ({pages}, {queryParams}) { + let {filter, page, limit} = queryParams; + + page = +page || 1; + limit = +limit || 15; + + let statusFilter = extractFilterParam('status', filter); + + let collection = pages.all().filter((page) => { + let matchesStatus = true; + + if (!isEmpty(statusFilter)) { + matchesStatus = statusFilter.includes(page.status); + } + + return matchesStatus; + }); + + return paginateModelCollection('pages', collection, page, limit); + }); + + server.get('/pages/:id/', function ({pages}, {params}) { + let {id} = params; + let page = pages.find(id); + + return page || new Response(404, {}, { + errors: [{ + errorType: 'NotFoundError', + message: 'Page not found.' + }] + }); + }); + + server.put('/pages/:id/', function ({pages, users, tags}, {params}) { + let attrs = this.normalizedRequestAttrs(); + let page = pages.find(params.id); + + attrs.authors = extractAuthors(attrs, users); + attrs.tags = extractTags(attrs, tags); + + attrs.updatedAt = moment.utc().toDate(); + + return page.update(attrs); + }); + + server.del('/pages/:id/'); +} diff --git a/mirage/config/posts.js b/mirage/config/posts.js index abc3af68e1..793d3b7af8 100644 --- a/mirage/config/posts.js +++ b/mirage/config/posts.js @@ -77,21 +77,15 @@ export default function mockPosts(server) { limit = +limit || 15; let statusFilter = extractFilterParam('status', filter); - let pageFilter = extractFilterParam('page', filter); let collection = posts.all().filter((post) => { let matchesStatus = true; - let matchesPage = true; if (!isEmpty(statusFilter)) { matchesStatus = statusFilter.includes(post.status); } - if (!isEmpty(pageFilter)) { - matchesPage = pageFilter.includes(post.page); - } - - return matchesStatus && matchesPage; + return matchesStatus; }); return paginateModelCollection('posts', collection, page, limit); diff --git a/mirage/factories/post.js b/mirage/factories/post.js index 7ae02459ba..a73e906ff0 100644 --- a/mirage/factories/post.js +++ b/mirage/factories/post.js @@ -18,7 +18,6 @@ export default Factory.extend({ ogDescription: null, ogImage: null, ogTitle: null, - page: false, plaintext(i) { return `Plaintext for post ${i}.`; }, publishedAt: '2015-12-19T16:25:07.000Z', publishedBy: 1, diff --git a/mirage/models/page.js b/mirage/models/page.js new file mode 100644 index 0000000000..d597bc4ca4 --- /dev/null +++ b/mirage/models/page.js @@ -0,0 +1,5 @@ +import PostModel from './post'; + +export default PostModel.extend({ + +}); diff --git a/tests/acceptance/content-test.js b/tests/acceptance/content-test.js index 793f1b7c60..8e5d2cdd8c 100644 --- a/tests/acceptance/content-test.js +++ b/tests/acceptance/content-test.js @@ -18,8 +18,7 @@ describe('Acceptance: Content', function () { }); describe('as admin', function () { - let admin, editor, - publishedPost, scheduledPost, draftPost, publishedPage, authorPost; + let admin, editor, publishedPost, scheduledPost, draftPost, authorPost; beforeEach(async function () { let adminRole = this.server.create('role', {name: 'Administrator'}); @@ -30,9 +29,11 @@ describe('Acceptance: Content', function () { publishedPost = this.server.create('post', {authors: [admin], status: 'published', title: 'Published Post'}); scheduledPost = this.server.create('post', {authors: [admin], status: 'scheduled', title: 'Scheduled Post'}); draftPost = this.server.create('post', {authors: [admin], status: 'draft', title: 'Draft Post'}); - publishedPage = this.server.create('post', {authors: [admin], status: 'published', page: true, title: 'Published Page'}); authorPost = this.server.create('post', {authors: [editor], status: 'published', title: 'Editor Published Post'}); + // pages shouldn't appear in the list + this.server.create('page', {authors: [admin], status: 'published', title: 'Published Page'}); + return await authenticateSession(); }); @@ -40,7 +41,7 @@ describe('Acceptance: Content', function () { await visit('/'); // Not checking request here as it won't be the last request made // Displays all posts + pages - expect(findAll('[data-test-post-id]').length, 'all posts count').to.equal(5); + expect(findAll('[data-test-post-id]').length, 'all posts count').to.equal(4); // show draft posts await selectChoose('[data-test-type-select]', 'Draft posts'); @@ -48,7 +49,6 @@ describe('Acceptance: Content', function () { // API request is correct let [lastRequest] = this.server.pretender.handledRequests.slice(-1); expect(lastRequest.queryParams.filter, '"drafts" request status filter').to.have.string('status:draft'); - expect(lastRequest.queryParams.filter, '"drafts" request page filter').to.have.string('page:false'); // Displays draft post expect(findAll('[data-test-post-id]').length, 'drafts count').to.equal(1); expect(find(`[data-test-post-id="${draftPost.id}"]`), 'draft post').to.exist; @@ -59,7 +59,6 @@ describe('Acceptance: Content', function () { // API request is correct [lastRequest] = this.server.pretender.handledRequests.slice(-1); expect(lastRequest.queryParams.filter, '"published" request status filter').to.have.string('status:published'); - expect(lastRequest.queryParams.filter, '"published" request page filter').to.have.string('page:false'); // Displays three published posts + pages expect(findAll('[data-test-post-id]').length, 'published count').to.equal(2); expect(find(`[data-test-post-id="${publishedPost.id}"]`), 'admin published post').to.exist; @@ -71,29 +70,16 @@ describe('Acceptance: Content', function () { // API request is correct [lastRequest] = this.server.pretender.handledRequests.slice(-1); expect(lastRequest.queryParams.filter, '"scheduled" request status filter').to.have.string('status:scheduled'); - expect(lastRequest.queryParams.filter, '"scheduled" request page filter').to.have.string('page:false'); // Displays scheduled post expect(findAll('[data-test-post-id]').length, 'scheduled count').to.equal(1); expect(find(`[data-test-post-id="${scheduledPost.id}"]`), 'scheduled post').to.exist; - // show pages - await selectChoose('[data-test-type-select]', 'Pages'); - - // API request is correct - [lastRequest] = this.server.pretender.handledRequests.slice(-1); - expect(lastRequest.queryParams.filter, '"pages" request status filter').to.have.string('status:[draft,scheduled,published]'); - expect(lastRequest.queryParams.filter, '"pages" request page filter').to.have.string('page:true'); - // Displays page - expect(findAll('[data-test-post-id]').length, 'pages count').to.equal(1); - expect(find(`[data-test-post-id="${publishedPage.id}"]`), 'page post').to.exist; - // show all posts await selectChoose('[data-test-type-select]', 'All posts'); // API request is correct [lastRequest] = this.server.pretender.handledRequests.slice(-1); expect(lastRequest.queryParams.filter, '"all" request status filter').to.have.string('status:[draft,scheduled,published]'); - expect(lastRequest.queryParams.filter, '"all" request page filter').to.have.string('page:[true,false]'); // show all posts by editor await selectChoose('[data-test-author-select]', editor.name); @@ -101,7 +87,6 @@ describe('Acceptance: Content', function () { // API request is correct [lastRequest] = this.server.pretender.handledRequests.slice(-1); expect(lastRequest.queryParams.filter, '"editor" request status filter').to.have.string('status:[draft,scheduled,published]'); - expect(lastRequest.queryParams.filter, '"editor" request page filter').to.have.string('page:[true,false]'); expect(lastRequest.queryParams.filter, '"editor" request filter param').to.have.string(`authors:${editor.slug}`); // Displays editor post @@ -114,7 +99,7 @@ describe('Acceptance: Content', function () { // Double-click on a post opens editor await triggerEvent(`[data-test-post-id="${authorPost.id}"]`, 'dblclick'); - expect(currentURL(), 'url after double-click').to.equal(`/editor/${authorPost.id}`); + expect(currentURL(), 'url after double-click').to.equal(`/editor/post/${authorPost.id}`); }); // TODO: skipped due to consistently random failures on Travis diff --git a/tests/acceptance/custom-post-templates-test.js b/tests/acceptance/custom-post-templates-test.js index a3c30cc0f9..723d61d85a 100644 --- a/tests/acceptance/custom-post-templates-test.js +++ b/tests/acceptance/custom-post-templates-test.js @@ -63,7 +63,7 @@ describe('Acceptance: Custom Post Templates', function () { it('can change selected template', async function () { let post = this.server.create('post', {customTemplate: 'custom-news-bulletin.hbs'}); - await visit('/editor/1'); + await visit('/editor/post/1'); await click('[data-test-psm-trigger]'); // template form should be shown @@ -109,7 +109,7 @@ describe('Acceptance: Custom Post Templates', function () { this.server.create('post', {customTemplate: 'custom-news-bulletin.hbs'}); - await visit('/editor/1'); + await visit('/editor/post/1'); await click('[data-test-psm-trigger]'); expect(themeRequests().length, 'after first open').to.equal(1); @@ -137,7 +137,7 @@ describe('Acceptance: Custom Post Templates', function () { it('doesn\'t show template selector', async function () { this.server.create('post', {customTemplate: 'custom-news-bulletin.hbs'}); - await visit('/editor/1'); + await visit('/editor/post/1'); await click('[data-test-psm-trigger]'); // template form should be shown diff --git a/tests/acceptance/editor-test.js b/tests/acceptance/editor-test.js index 7d0fdfbebf..67966e61fd 100644 --- a/tests/acceptance/editor-test.js +++ b/tests/acceptance/editor-test.js @@ -23,7 +23,7 @@ describe('Acceptance: Editor', function () { this.server.create('post', {authors: [author]}); await invalidateSession(); - await visit('/editor/1'); + await visit('/editor/post/1'); expect(currentURL(), 'currentURL').to.equal('/signin'); }); @@ -34,9 +34,9 @@ describe('Acceptance: Editor', function () { this.server.create('post', {authors: [author]}); await authenticateSession(); - await visit('/editor/1'); + await visit('/editor/post/1'); - expect(currentURL(), 'currentURL').to.equal('/editor/1'); + expect(currentURL(), 'currentURL').to.equal('/editor/post/1'); }); it('does not redirect to team page when authenticated as author', async function () { @@ -45,9 +45,9 @@ describe('Acceptance: Editor', function () { this.server.create('post', {authors: [author]}); await authenticateSession(); - await visit('/editor/1'); + await visit('/editor/post/1'); - expect(currentURL(), 'currentURL').to.equal('/editor/1'); + expect(currentURL(), 'currentURL').to.equal('/editor/post/1'); }); it('does not redirect to team page when authenticated as editor', async function () { @@ -56,9 +56,9 @@ describe('Acceptance: Editor', function () { this.server.create('post', {authors: [author]}); await authenticateSession(); - await visit('/editor/1'); + await visit('/editor/post/1'); - expect(currentURL(), 'currentURL').to.equal('/editor/1'); + expect(currentURL(), 'currentURL').to.equal('/editor/post/1'); }); it('displays 404 when post does not exist', async function () { @@ -66,10 +66,10 @@ describe('Acceptance: Editor', function () { this.server.create('user', {roles: [role], slug: 'test-user'}); await authenticateSession(); - await visit('/editor/1'); + await visit('/editor/post/1'); expect(currentRouteName()).to.equal('error404'); - expect(currentURL()).to.equal('/editor/1'); + expect(currentURL()).to.equal('/editor/post/1'); }); it('when logged in as a contributor, renders a save button instead of a publish menu & hides tags input', async function () { @@ -80,9 +80,9 @@ describe('Acceptance: Editor', function () { await authenticateSession(); // post id 1 is a draft, checking for draft behaviour now - await visit('/editor/1'); + await visit('/editor/post/1'); - expect(currentURL(), 'currentURL').to.equal('/editor/1'); + expect(currentURL(), 'currentURL').to.equal('/editor/post/1'); // Expect publish menu to not exist expect( @@ -100,7 +100,7 @@ describe('Acceptance: Editor', function () { ).to.not.exist; // post id 2 is published, we should be redirected to index - await visit('/editor/2'); + await visit('/editor/post/2'); expect(currentURL(), 'currentURL').to.equal('/'); }); @@ -121,10 +121,10 @@ describe('Acceptance: Editor', function () { let futureTime = moment().tz('Etc/UTC').add(10, 'minutes'); // post id 1 is a draft, checking for draft behaviour now - await visit('/editor/1'); + await visit('/editor/post/1'); expect(currentURL(), 'currentURL') - .to.equal('/editor/1'); + .to.equal('/editor/post/1'); // open post settings menu await click('[data-test-psm-trigger]'); @@ -235,9 +235,9 @@ describe('Acceptance: Editor', function () { ).to.equal('Unpublish'); // post id 2 is a published post, checking for published post behaviour now - await visit('/editor/2'); + await visit('/editor/post/2'); - expect(currentURL(), 'currentURL').to.equal('/editor/2'); + expect(currentURL(), 'currentURL').to.equal('/editor/post/2'); expect(find('[data-test-date-time-picker-date-input]').value).to.equal('12/19/2015'); expect(find('[data-test-date-time-picker-time-input]').value).to.equal('16:25'); @@ -280,10 +280,10 @@ describe('Acceptance: Editor', function () { .to.equal('(GMT +12:00) International Date Line West'); // and now go back to the editor - await visit('/editor/2'); + await visit('/editor/post/2'); expect(currentURL(), 'currentURL in editor') - .to.equal('/editor/2'); + .to.equal('/editor/post/2'); expect( find('[data-test-date-time-picker-date-input]').value, @@ -436,7 +436,7 @@ describe('Acceptance: Editor', function () { let post = this.server.create('post', 1, {authors: [author], status: 'draft'}); let plusTenMin = moment().utc().add(10, 'minutes'); - await visit(`/editor/${post.id}`); + await visit(`/editor/post/${post.id}`); await click('[data-test-publishmenu-trigger]'); await click('[data-test-publishmenu-scheduled-option]'); @@ -461,10 +461,10 @@ describe('Acceptance: Editor', function () { this.server.create('post', {authors: [author]}); // post id 1 is a draft, checking for draft behaviour now - await visit('/editor/1'); + await visit('/editor/post/1'); expect(currentURL(), 'currentURL') - .to.equal('/editor/1'); + .to.equal('/editor/post/1'); await fillIn('[data-test-editor-title-input]', Array(260).join('a')); await click('[data-test-publishmenu-trigger]'); @@ -486,10 +486,10 @@ describe('Acceptance: Editor', function () { // this.server.createList('post', 1); // // // post id 1 is a draft, checking for draft behaviour now - // await visit('/editor/1'); + // await visit('/editor/post/1'); // // expect(currentURL(), 'currentURL') - // .to.equal('/editor/1'); + // .to.equal('/editor/post/1'); // // await titleRendered(); // @@ -508,10 +508,10 @@ describe('Acceptance: Editor', function () { // this.server.createList('post', 1); // // // post id 1 is a draft, checking for draft behaviour now - // await visit('/editor/1'); + // await visit('/editor/post/1'); // // expect(currentURL(), 'currentURL') - // .to.equal('/editor/1'); + // .to.equal('/editor/post/1'); // // await titleRendered(); // @@ -529,10 +529,10 @@ describe('Acceptance: Editor', function () { this.server.create('setting', {activeTimezone: 'Europe/Dublin'}); clock.restore(); - await visit('/editor/1'); + await visit('/editor/post/1'); expect(currentURL(), 'currentURL') - .to.equal('/editor/1'); + .to.equal('/editor/post/1'); expect(find('[data-test-date-time-picker-date-input]').value, 'scheduled date') .to.equal(compareDateString); expect(find('[data-test-date-time-picker-time-input]').value, 'scheduled time') @@ -552,10 +552,10 @@ describe('Acceptance: Editor', function () { this.server.create('user', {name: 'Waldo', roles: [authorRole]}); this.server.create('post', {authors: [user1]}); - await visit('/editor/1'); + await visit('/editor/post/1'); expect(currentURL(), 'currentURL') - .to.equal('/editor/1'); + .to.equal('/editor/post/1'); await click('button.post-settings'); @@ -586,7 +586,7 @@ describe('Acceptance: Editor', function () { expect( currentURL(), 'url on initial visit' - ).to.equal('/editor'); + ).to.equal('/editor/post'); await click('[data-test-editor-title-input]'); await blur('[data-test-editor-title-input]'); @@ -599,13 +599,13 @@ describe('Acceptance: Editor', function () { expect( currentURL(), 'url after autosave' - ).to.equal('/editor/1'); + ).to.equal('/editor/post/1'); }); it('saves post settings fields', async function () { let post = this.server.create('post', {authors: [author]}); - await visit(`/editor/${post.id}`); + await visit(`/editor/post/${post.id}`); // TODO: implement tests for other fields diff --git a/tests/acceptance/error-handling-test.js b/tests/acceptance/error-handling-test.js index aa9cb60647..d9955229d0 100644 --- a/tests/acceptance/error-handling-test.js +++ b/tests/acceptance/error-handling-test.js @@ -45,7 +45,7 @@ describe('Acceptance: Error Handling', function () { expect(find('.gh-alert').textContent).to.match(/refresh/); // try navigating back to the content list - await click('[data-test-link="stories"]'); + await click('[data-test-link="posts"]'); expect(currentRouteName()).to.equal('editor.edit'); }); @@ -123,7 +123,7 @@ describe('Acceptance: Error Handling', function () { this.server.put('/posts/1/', htmlErrorResponse); this.server.create('post'); - await visit('/editor/1'); + await visit('/editor/post/1'); await click('[data-test-publishmenu-trigger]'); await click('[data-test-publishmenu-save]'); diff --git a/tests/integration/components/gh-psm-template-select-test.js b/tests/integration/components/gh-psm-template-select-test.js index 31f5dcef67..16e2e4414e 100644 --- a/tests/integration/components/gh-psm-template-select-test.js +++ b/tests/integration/components/gh-psm-template-select-test.js @@ -60,7 +60,9 @@ describe('Integration: Component: gh-psm-template-select', function () { it('disables template selector if slug matches post template', async function () { this.set('post', { slug: 'one', - page: false + constructor: { + modelName: 'post' + } }); await render(hbs`{{gh-psm-template-select post=post}}`); @@ -73,7 +75,9 @@ describe('Integration: Component: gh-psm-template-select', function () { it('disables template selector if slug matches page template', async function () { this.set('post', { slug: 'about', - page: true + constructor: { + modelName: 'page' + } }); await render(hbs`{{gh-psm-template-select post=post}}`); diff --git a/tests/unit/components/gh-post-settings-menu-test.js b/tests/unit/components/gh-post-settings-menu-test.js index ad7167cebb..513b2e28f2 100644 --- a/tests/unit/components/gh-post-settings-menu-test.js +++ b/tests/unit/components/gh-post-settings-menu-test.js @@ -291,65 +291,6 @@ describe.skip('Unit: Component: post-settings-menu', function () { }); }); - describe('togglePage', function () { - it('should toggle the page property', function () { - let component = this.subject({ - post: EmberObject.create({ - page: false, - isNew: true - }) - }); - - expect(component.get('post.page')).to.not.be.ok; - - run(function () { - component.send('togglePage'); - - expect(component.get('post.page')).to.be.ok; - }); - }); - - it('should not save the post if it is still new', function () { - let component = this.subject({ - post: EmberObject.create({ - page: false, - isNew: true, - save() { - this.incrementProperty('saved'); - return RSVP.resolve(); - } - }) - }); - - run(function () { - component.send('togglePage'); - - expect(component.get('post.page')).to.be.ok; - expect(component.get('post.saved')).to.not.be.ok; - }); - }); - - it('should save the post if it is not new', function () { - let component = this.subject({ - post: EmberObject.create({ - page: false, - isNew: false, - save() { - this.incrementProperty('saved'); - return RSVP.resolve(); - } - }) - }); - - run(function () { - component.send('togglePage'); - - expect(component.get('post.page')).to.be.ok; - expect(component.get('post.saved')).to.equal(1); - }); - }); - }); - describe('toggleFeatured', function () { it('should toggle the featured property', function () { let component = this.subject({